Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: send survey partial responses event #1788

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

lucasheriques
Copy link
Contributor

@lucasheriques lucasheriques commented Mar 5, 2025

Changes

sends events after every survey question - logic to dedupe them will be done on posthog/posthog side

related issue: PostHog/posthog#19300

todo:

  • add tests

Checklist

  • Tests for new code (see advice on the tests we use)
  • Accounted for the impact of any changes across different browsers
  • Accounted for backwards compatibility of any changes (no breaking changes in posthog-js!)

@lucasheriques lucasheriques added bump patch Bump patch version when this PR gets merged feature/surveys labels Mar 5, 2025
@lucasheriques lucasheriques self-assigned this Mar 5, 2025
Copy link

vercel bot commented Mar 5, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
posthog-js ✅ Ready (Inspect) Visit Preview Mar 19, 2025 5:15am

Copy link

github-actions bot commented Mar 5, 2025

Size Change: +10.3 kB (+0.29%)

Total Size: 3.59 MB

Filename Size Change
dist/all-external-dependencies.js 223 kB +2.84 kB (+1.29%)
dist/array.full.es5.js 276 kB +351 B (+0.13%)
dist/array.full.js 379 kB +327 B (+0.09%)
dist/array.full.no-external.js 377 kB +327 B (+0.09%)
dist/array.js 186 kB +22 B (+0.01%)
dist/array.no-external.js 184 kB +22 B (+0.01%)
dist/main.js 186 kB +22 B (+0.01%)
dist/module.full.js 379 kB +327 B (+0.09%)
dist/module.full.no-external.js 377 kB +327 B (+0.09%)
dist/module.js 186 kB +22 B (+0.01%)
dist/module.no-external.js 184 kB +22 B (+0.01%)
dist/surveys-preview.js 74.2 kB +2.84 kB (+3.99%)
dist/surveys.js 79.5 kB +2.84 kB (+3.7%)
ℹ️ View Unchanged
Filename Size
dist/customizations.full.js 14 kB
dist/dead-clicks-autocapture.js 14.5 kB
dist/exception-autocapture.js 9.94 kB
dist/external-scripts-loader.js 2.75 kB
dist/posthog-recorder.js 211 kB
dist/recorder-v2.js 115 kB
dist/recorder.js 115 kB
dist/tracing-headers.js 1.76 kB
dist/web-vitals.js 10.4 kB

compressed-size-action

@posthog-bot
Copy link
Collaborator

This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, post a comment or remove the stale label – otherwise this will be closed in another week.

@lucasheriques lucasheriques marked this pull request as ready for review March 19, 2025 01:53
@lucasheriques lucasheriques requested a review from a team as a code owner March 19, 2025 01:53
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This PR adds support for sending partial survey responses by tracking individual question responses before survey completion, with a new enable_partial_response flag controlling this behavior.

  • Added enable_partial_response flag to Survey interface to control partial response behavior
  • Implemented surveyResponseId using uuidv7() to track responses across questions consistently
  • Modified sendSurveyEvent to conditionally send events based on enable_partial_response and surveyCompleted flags
  • Added logging for survey response payloads to aid debugging
  • Deduplication logic will be handled server-side in posthog/posthog

3 file(s) reviewed, 2 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines 823 to 833

const nextStep = getNextSurveyStep(survey, displayQuestionIndex, res)
if (nextStep === SurveyQuestionBranchingType.End) {
sendSurveyEvent({ ...questionsResponses, [responseKey]: res }, survey, posthog)
sendSurveyEvent({
responses: { ...questionsResponses, [responseKey]: res },
survey,
posthog,
surveyCompleted: nextStep === SurveyQuestionBranchingType.End,
surveyResponseId,
})
onPopupSurveySent()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Sending partial responses here but not in the else branch creates inconsistent behavior. Should also send partial responses when moving to next question.

onPopupSurveySent()
},
surveyResponseId: uuidv7(),
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: surveyResponseId is regenerated on every render due to useMemo dependencies. Should be stored in state or ref to maintain consistency.

Suggested change
}),
surveyResponseId: useRef(uuidv7()).current,
}),

Copy link

@ioannisj ioannisj Mar 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: surveyResponseId is regenerated on every render due to useMemo dependencies. Should be stored in state or ref to maintain consistency.

No idea if this stands but this would mean a new uuid on every render right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not correct, as uuidv7() is a stable function (outside of preact component lifecycle)

it would only change when SurveyPopup is unmounted then rendered again, as expected

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could it be that the user answers 1 question, refresh the page, generates another uuid, and answers the 2nd question?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or rather, how do we keep track of the current state of responses if the user refresh the page, comes back later, etc? is that gonna be an issue? (eg, even if starting from zero, having multiple answers for the same question, with a different uuid)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

than the survey will not be shown, as after one question is answered, it's marked as if it is responded

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'd have to do a more complex logic to handle a bigger user session that might involve refreshing. because, right now, if they answer one question, at this point the survey is marked as responded, so once it's gone, no longer it'll show up

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems like we should address then, because previously, the user had a chance to answer the full survey, even if from the very beginning (annoying but possible).
now if the user just goes to another page (that is not a match anymore and survey is closed), or refreshes the page, the user cant answer anything anymore, leading to maybe an even poorer experience than before, with lots of surveys half answered

@marandaneto marandaneto requested a review from ioannisj March 19, 2025 07:22
@@ -16,7 +16,7 @@ const window = _window as Window & typeof globalThis
const document = _document as Document
const SurveySeenPrefix = 'seenSurvey_'

const logger = createLogger('[Surveys]')
const logger = createLogger('[Surveys Utils]')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const logger = createLogger('[Surveys Utils]')
const logger = createLogger('[Surveys]')

any reason to change it? its easier to filter logs by [Surveys] rather than many other options

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those logs are just not working, i was just testing it out to make sure.

the only logs who are working are from posthog-surveys

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quickfix? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not that quick (really confused why it's not working) but I do wanna take a look

localStorage.setItem(getSurveySeenKey(survey), 'true')

logger.info('[PostHog Surveys] survey partial response payload', {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
logger.info('[PostHog Surveys] survey partial response payload', {
logger.info('survey partial response payload', {

createLogger already has a prefix

@marandaneto
Copy link
Member

i think some tests around the new props would be good.
also, if an event is captured per answer or the whole survey, including if partial response is enabled or not

onPopupSurveySent()
},
surveyResponseId: uuidv7(),
}),
Copy link

@ioannisj ioannisj Mar 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: surveyResponseId is regenerated on every render due to useMemo dependencies. Should be stored in state or ref to maintain consistency.

No idea if this stands but this would mean a new uuid on every render right?

if (!posthog) {
logger.error('[survey sent] event not captured, PostHog instance not found.')
return
}
if (!isSurveyCompleted && !survey.enable_partial_responses) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this bit of logic here should be on the calling side

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we also check for survey complete on the callsite to fire the survey sent popup callback, so better to avoid dupe checks and keep in a single place

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bump patch Bump patch version when this PR gets merged feature/surveys
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants