Skip to content

feat(surveys): add optional intro screen before the first question - #754

Open
jakesciotto wants to merge 6 commits into
mainfrom
posthog-code/survey-intro-screen
Open

feat(surveys): add optional intro screen before the first question#754
jakesciotto wants to merge 6 commits into
mainfrom
posthog-code/survey-intro-screen

Conversation

@jakesciotto

@jakesciotto jakesciotto commented Aug 6, 2026

Copy link
Copy Markdown

💡 Motivation and Context

Surveys can show a confirmation ("thank you") screen after the last question, but there is no equivalent screen before the first one — the built-in survey sheet drops respondents straight into question 1 with no framing.

This is the posthog-ios part of the cross-SDK intro screen rollout tracked in PostHog/posthog#74064. The web/RN renderer shipped in PostHog/posthog-js#4436; this PR brings the native SwiftUI rendering to parity.

What it does:

  • New SurveyAppearance fields decoded from the API and exposed on PostHogDisplaySurveyAppearance (for custom delegates too): displayIntroScreen, introScreenHeader, introScreenDescription, introScreenDescriptionContentType, introScreenButtonText.
  • New IntroMessage SwiftUI view, the leading mirror of ConfirmationMessage, rendered by SurveySheet before the first question when displayIntroScreen is on.
  • Advancing past the intro (dismissIntroScreen) is a pure UI transition: no response recorded, no survey event sent, no effect on $survey_partially_completed. The X button on the intro still dismisses the survey with the normal survey dismissed event, and the confirmation branch still wins for completed surveys.
  • Intro copy is translatable (introScreenHeader / introScreenDescription / introScreenButtonText in survey translations), wired through PostHogSurveyTranslation, the resolver's change gate, and the display-appearance overlay.
  • Drive-by fix: getAppearanceWithDefaults never passed thankYouMessageDescription through to the sheet appearance, so the thank-you description never rendered in the built-in UI. Fixed while mirroring the field for the intro screen.

💚 How did you test it?

Unit tests added:

  • Raw → display appearance mapping for the 5 new fields, plus default-off behavior when absent (PostHogSurveysTest.swift).
  • Display controller intro state machine: starts on the intro only when enabled, and advancing keeps the survey open without invoking the close callback (PostHogSurveyTranslationsTest.swift).
  • Translation fixture extended: translated intro header/button apply, untranslated description falls back.

Written on Linux, so the suite was not executed locally — please rely on CI (make test / iOS simulator tests). The public API snapshot (api/posthog-ios.public-api.txt) was updated by hand following the snapshot format; the Build workflow's apiCheck verifies it, and make apiUpdate on macOS produces the canonical version if it disagrees.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file (.changeset/survey-intro-screen.md, minor)

🤖 Agent context

Autonomy: Human-driven (agent-assisted)


Created with PostHog Code

Adds the leading mirror of the confirmation message: an optional intro screen shown before question 1, configured via the new displayIntroScreen / introScreenHeader / introScreenDescription / introScreenDescriptionContentType / introScreenButtonText appearance fields. Advancing past it records no response and sends no survey event. Intro copy is translatable like the thank-you message.

Generated-By: PostHog Code
Task-Id: 50ceca51-4b90-4b94-8e72-e01bce50073c
SwiftPM discovers sources automatically but the example apps and CodeQL build the SDK through PostHog.xcodeproj, which lists files explicitly, so every xcodeproj-based job failed with "cannot find 'IntroMessage' in scope".

Generated-By: PostHog Code
Task-Id: 50ceca51-4b90-4b94-8e72-e01bce50073c
Written by hand following the snapshot format (the mangling model was validated against the existing thankYouMessageDescriptionContentType entry); the Build workflow's apiCheck verifies it against the compiler's own symbol graph.

Generated-By: PostHog Code
Task-Id: 50ceca51-4b90-4b94-8e72-e01bce50073c
@jakesciotto
jakesciotto marked this pull request as ready for review August 6, 2026 18:51
@jakesciotto
jakesciotto requested a review from a team as a code owner August 6, 2026 18:51
@greptile-apps

greptile-apps Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
### Issue 1
PostHog/Surveys/IntroMessage.swift:26
**HTML intro descriptions disappear**

When an intro description uses the supported `html` content type, this guard renders nothing, causing respondents to see the intro header and button without the configured description.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "chore(surveys): add intro screen fields ..." | Re-trigger Greptile

Comment thread PostHog/Surveys/IntroMessage.swift
Parity with the web renderer: the intro has no default header, so an intro with neither header nor description would draw an empty sheet with a lone button. Skips straight to question 1 instead.

Generated-By: PostHog Code
Task-Id: 50ceca51-4b90-4b94-8e72-e01bce50073c
@marandaneto
marandaneto requested a review from a team August 10, 2026 10:12
@marandaneto

Copy link
Copy Markdown
Member

moving to draft until we hear from @PostHog/team-surveys

@marandaneto
marandaneto marked this pull request as draft August 10, 2026 10:13
@github-actions

Copy link
Copy Markdown
Contributor

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.

@github-actions github-actions Bot added the stale label Aug 18, 2026
Generated-By: PostHog Desktop
Task-Id: de8974e0-537f-4189-a799-66a7bc98cb10
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

posthog-ios Compliance Report

Date: 2026-08-19 21:53:25 UTC
Duration: 218944ms

✅ All Tests Passed!

45/45 tests passed


Capture Tests

29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 2818ms
Format Validation.Event Has Uuid 2765ms
Format Validation.Event Has Lib Properties 2788ms
Format Validation.Distinct Id Is String 2728ms
Format Validation.Token Is Present 2722ms
Format Validation.Custom Properties Preserved 2772ms
Format Validation.Event Has Timestamp 2827ms
Retry Behavior.Retries On 503 11255ms
Retry Behavior.Does Not Retry On 400 4794ms
Retry Behavior.Does Not Retry On 401 4858ms
Retry Behavior.Respects Retry After Header 7812ms
Retry Behavior.Implements Backoff 15363ms
Retry Behavior.Retries On 500 9196ms
Retry Behavior.Retries On 502 8752ms
Retry Behavior.Retries On 504 9218ms
Retry Behavior.Max Retries Respected 15349ms
Deduplication.Generates Unique Uuids 2925ms
Deduplication.Preserves Uuid On Retry 9163ms
Deduplication.Preserves Uuid And Timestamp On Retry 16602ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 7805ms
Deduplication.No Duplicate Events In Batch 2864ms
Deduplication.Different Events Have Different Uuids 394ms
Compression.Sends Gzip When Enabled 2850ms
Batch Format.Uses Proper Batch Structure 2697ms
Batch Format.Flush With No Events Sends Nothing 304ms
Batch Format.Multiple Events Batched Together 2810ms
Error Handling.Does Not Retry On 403 4719ms
Error Handling.Does Not Retry On 413 4783ms
Error Handling.Retries On 408 9240ms

Feature_Flags Tests

16/16 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id 2721ms
Request Payload.Flags Request Uses V2 Query Param 2771ms
Request Payload.Flags Request Hits Flags Path Not Decide 2752ms
Request Payload.Flags Request Omits Authorization Header 2679ms
Request Payload.Token In Flags Body Matches Init 2944ms
Request Payload.Groups Round Trip 2717ms
Request Payload.Groups Default To Empty Object 2656ms
Request Payload.Person Properties Distinct Id Auto Populated When Caller Omits It 2790ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False 2836ms
Request Payload.Disable Geoip Omitted Defaults To False 2850ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key 2830ms
Request Lifecycle.No Flags Request On Init Alone 138ms
Request Lifecycle.No Flags Request On Normal Capture 3055ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests 5473ms
Request Lifecycle.Mock Response Value Is Returned To Caller 2778ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event 2944ms

Main added a PostHogSurveyTranslation call site that predates the three intro screen fields, so the memberwise initializer no longer type-checks. Pass nil for the new fields.

Also correct the mangled symbol for introScreenDescriptionContentType in the public API snapshot so the apiCheck diff is clean.

Generated-By: PostHog Desktop
Task-Id: de8974e0-537f-4189-a799-66a7bc98cb10
@jakesciotto
jakesciotto marked this pull request as ready for review August 19, 2026 21:42
@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Reviews (2): Last reviewed commit: "fix(surveys): repair intro screen build ..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants