| name | survey-sdk-audit |
| description | Audit PostHog survey SDK features and version requirements |
Surveys SDK Feature Audit Skill
Use this skill when auditing survey feature support across PostHog SDKs for surveyVersionRequirements.ts.
Feature to audit: $ARGUMENTS
Setup Check (Run First)
Before starting, verify the SDK paths are accessible. Run ls on each path:
$POSTHOG_JS_PATH
$POSTHOG_IOS_PATH
$POSTHOG_ANDROID_PATH
$POSTHOG_FLUTTER_PATH
If any path is empty or doesn't exist, ask the user: "I need the path to [SDK repo] on your machine. Where is it located?"
Once you have all paths, ask the user if they'd like to save them for future sessions by adding to .claude/settings.local.json:
{
"env": {
"POSTHOG_JS_PATH": "/path/to/posthog-js",
"POSTHOG_IOS_PATH": "/path/to/posthog-ios",
"POSTHOG_ANDROID_PATH": "/path/to/posthog-android",
"POSTHOG_FLUTTER_PATH": "/path/to/posthog-flutter"
},
"permissions": {
"allow": [
"Read(/path/to/posthog-js/**)",
"Read(/path/to/posthog-ios/**)",
"Read(/path/to/posthog-android/**)",
"Read(/path/to/posthog-flutter/**)",
"Grep(/path/to/posthog-js/**)",
"Grep(/path/to/posthog-ios/**)",
"Grep(/path/to/posthog-android/**)",
"Grep(/path/to/posthog-flutter/**)"
]
}
}
Note: The Read and Grep permissions grant Claude access to these external SDK repositories without prompting each time.
Using SDK Paths in Commands
IMPORTANT: Environment variables like $POSTHOG_JS_PATH do NOT expand reliably in Bash tool commands.
Instead of bash commands, prefer:
- Use the Read tool to read files (works with permissions)
- Use the Grep tool to search files (works with permissions)
If you must use bash, first expand the variable:
echo $POSTHOG_JS_PATH
Then use the echoed path directly in subsequent commands.
Issue Visibility
Survey SDK feature parity has no central tracking issue. Visibility lives at repo level: surveyVersionRequirements.ts links unsupported SDKs to their issues, and each new issue cross-links its siblings via a ## Related section (see the issue template below).
SDK Paths and Changelogs
| SDK | Code Path | Changelog |
|---|
| posthog-js (browser) | $POSTHOG_JS_PATH/packages/browser | $POSTHOG_JS_PATH/packages/browser/CHANGELOG.md |
| posthog-react-native | $POSTHOG_JS_PATH/packages/react-native | $POSTHOG_JS_PATH/packages/react-native/CHANGELOG.md |
| posthog-ios | $POSTHOG_IOS_PATH | $POSTHOG_IOS_PATH/CHANGELOG.md |
| posthog-android | $POSTHOG_ANDROID_PATH | $POSTHOG_ANDROID_PATH/CHANGELOG.md |
| posthog-flutter | $POSTHOG_FLUTTER_PATH | $POSTHOG_FLUTTER_PATH/CHANGELOG.md |
Flutter Native Dependencies
Flutter wraps native SDKs. Check dependency versions in:
- iOS:
$POSTHOG_FLUTTER_PATH/ios/posthog_flutter.podspec (look for s.dependency 'PostHog')
- Android:
$POSTHOG_FLUTTER_PATH/android/build.gradle (look for posthog-android dependency)
Audit Process
Step 1: Understand the Feature
Look at the check function in surveyVersionRequirements.ts to understand what field/condition triggers this feature:
s.conditions?.deviceTypes → search for "deviceTypes"
s.appearance?.fontFamily → search for "fontFamily"
s.conditions?.urlMatchType → search for "urlMatchType"
Step 2: Search Changelogs First
grep -n -i "KEYWORD" /path/to/CHANGELOG.md
If found, read the surrounding lines to get the version number.
Step 3: Search Code If Not in Changelog
cd /path/to/sdk && git log --oneline --all -S "KEYWORD" -- "*.swift" "*.kt" "*.ts" "*.tsx"
git tag --contains COMMIT_HASH | sort -V | head -3
Step 4: For Flutter, Find When Native Dependency Was Bumped
cd $POSTHOG_FLUTTER_PATH && git log --oneline -p -- "ios/posthog_flutter.podspec" | grep -B10 "X.Y.Z"
git tag --contains COMMIT_HASH | sort -V | head -1
Step 5: Verify Feature Actually Works (Not Just Types)
CRITICAL: Having a field in a data model does NOT mean the feature is implemented. You must check the actual filtering/matching logic.
SDK rendering capabilities:
- posthog-js (browser): Built-in survey rendering (HTML/CSS popup)
- posthog-react-native: Built-in survey rendering (React Native components in
packages/react-native/src/surveys/)
- posthog-ios: Built-in survey rendering (SwiftUI views in
PostHog/Surveys/ — SurveySheet.swift, QuestionTypes.swift, MultipleChoiceOptions.swift)
- posthog-android: No built-in UI — pure delegate pattern. Exposes display models (
PostHogDisplaySurvey, PostHogDisplayChoiceQuestion, etc.) for developers to render themselves. Use issue: false for rendering-only features.
- posthog-flutter: Built-in survey rendering (Flutter widgets in
lib/src/surveys/widgets/ — survey_bottom_sheet.dart, choice_question.dart)
For SDKs with built-in rendering, a feature must be actually implemented in the rendering code, not just present as a field on the data model. For Android (delegate-only), exposing the field on the display model is sufficient — mark as issue: false with a comment.
Key files to check for survey filtering logic:
- posthog-js (browser):
$POSTHOG_JS_PATH/packages/browser/src/extensions/surveys/surveys-extension-utils.tsx - utility functions like canActivateRepeatedly, getSurveySeen, hasEvents
- posthog-js (browser):
$POSTHOG_JS_PATH/packages/browser/src/extensions/surveys.tsx - main survey logic
- posthog-react-native:
$POSTHOG_JS_PATH/packages/react-native/src/surveys/getActiveMatchingSurveys.ts - main filtering logic
- posthog-react-native:
$POSTHOG_JS_PATH/packages/react-native/src/surveys/surveys-utils.ts - utility functions like canActivateRepeatedly, hasEvents
- posthog-ios:
$POSTHOG_IOS_PATH/PostHog/Surveys/PostHogSurveyIntegration.swift → getActiveMatchingSurveys() method, canActivateRepeatedly computed property
- posthog-android:
$POSTHOG_ANDROID_PATH/posthog-android/src/main/java/com/posthog/android/surveys/PostHogSurveysIntegration.kt → getActiveMatchingSurveys() method, canActivateRepeatedly() function
Key utility functions to compare across SDKs:
canActivateRepeatedly - determines if a survey can be shown again after being seen
hasEvents - checks if survey has event-based triggers
getSurveySeen - checks if user has already seen the survey
Example pitfall 1: Both iOS and Android have linkedFlagKey in their Survey model, but neither implements linkedFlagVariant checking. They only call isFeatureEnabled(key) (boolean) instead of comparing flags[key] === variant.
Example pitfall 2: The browser canActivateRepeatedly checks THREE conditions: (1) event repeatedActivation, (2) schedule === 'always', (3) survey in progress. Mobile SDKs may only check condition (1), missing the schedule check entirely.
Key files to check for survey rendering logic:
- posthog-js (browser):
$POSTHOG_JS_PATH/packages/browser/src/extensions/surveys/surveys-extension-utils.tsx - getDisplayOrderQuestions(), getDisplayOrderChoices()
- posthog-react-native:
$POSTHOG_JS_PATH/packages/react-native/src/surveys/surveys-utils.ts - getDisplayOrderQuestions(), getDisplayOrderChoices()
- posthog-ios:
$POSTHOG_IOS_PATH/PostHog/Surveys/QuestionTypes.swift - SingleChoiceQuestionView, MultipleChoiceQuestionView; $POSTHOG_IOS_PATH/PostHog/Surveys/SurveySheet.swift - question ordering
- posthog-android: No built-in UI — only check display model exposure in
$POSTHOG_ANDROID_PATH/posthog/src/main/java/com/posthog/surveys/PostHogDisplaySurveyQuestion.kt and PostHogDisplaySurveyAppearance.kt
- posthog-flutter:
$POSTHOG_FLUTTER_PATH/lib/src/surveys/widgets/survey_bottom_sheet.dart - question ordering; $POSTHOG_FLUTTER_PATH/lib/src/surveys/widgets/choice_question.dart - choice rendering
What to look for:
- Is the field parsed from JSON into the model? (necessary but not sufficient)
- Is the field used in filtering logic like
getActiveMatchingSurveys()?
- For rendering features: Is the field actually used by the built-in UI? (check rendering code, not just data models)
- Does the logic match the reference implementation behavior?
- Test files don't count as implementation
Reference Implementation
posthog-js browser is the canonical implementation - it has every feature and is the source of truth for how things are supposed to work.
When auditing a feature:
- First check
$POSTHOG_JS_PATH/packages/browser/src/extensions/surveys.ts to understand the complete, correct behavior
- Then compare mobile SDKs against posthog-react-native (
$POSTHOG_JS_PATH/packages/react-native/src/surveys/getActiveMatchingSurveys.ts) which is the reference for mobile-specific implementations
Web-Only vs Cross-Platform Features
Some features only make sense on web:
- URL targeting: No concept of "current URL" in native apps →
issue: false for all mobile
- CSS selector targeting: No DOM in native apps →
issue: false for all mobile
- Custom fonts via CSS: May need native implementation or may not be applicable
Output Format
For each feature, produce:
{
feature: 'Feature Name',
sdkVersions: {
'posthog-js': 'X.Y.Z',
'posthog-react-native': 'X.Y.Z',
'posthog-ios': 'X.Y.Z',
'posthog-android': 'X.Y.Z',
'posthog_flutter': 'X.Y.Z',
},
unsupportedSdks: [
{ sdk: 'sdk-name', issue: 'https://github.com/PostHog/repo/issues/123' },
{ sdk: 'sdk-name', issue: false },
],
check: (s) => ...,
}
Creating GitHub Issues
IMPORTANT: Always search for existing issues BEFORE creating new ones.
gh issue list --repo PostHog/posthog-ios --search "FEATURE_KEYWORD" --state all --limit 20
gh issue list --repo PostHog/posthog-android --search "FEATURE_KEYWORD" --state all --limit 20
gh issue list --repo PostHog/posthog-flutter --search "FEATURE_KEYWORD" --state all --limit 20
gh issue list --repo PostHog/posthog-ios --search "survey feature flag" --state all --limit 20
Always search issues in the main repo PostHog/posthog AND the SDK-specific repo(s) to ensure an issue does not already exist anywhere.
Labels by Repository
| Repository | Labels for Survey Features |
|---|
| PostHog/posthog-js | feature/surveys |
| PostHog/posthog-ios | Survey, enhancement |
| PostHog/posthog-android | Survey, enhancement |
| PostHog/posthog-flutter | Survey, enhancement |
Issue Creation Command
gh issue create --repo PostHog/posthog-js --label "feature/surveys" --title "..." --body "..."
gh issue create --repo PostHog/posthog-ios --label "Survey" --label "enhancement" --title "..." --body "..."
gh issue create --repo PostHog/posthog-android --label "Survey" --label "enhancement" --title "..." --body "..."
gh issue create --repo PostHog/posthog-flutter --label "Survey" --label "enhancement" --title "..." --body "..."
Issue Template
## 🚨 IMPORTANT
This issue is likely user-facing in the main PostHog app, see [`surveyVersionRequirements.ts`](https://github.com/PostHog/posthog/blob/master/frontend/src/scenes/surveys/surveyVersionRequirements.ts). If you delete or close this issue, be sure to update the version requirements list here.
## Summary
The [SDK] SDK does not support [feature] for surveys.
## Current State
- [What exists, if anything - types, partial implementation, etc.]
## Expected Behavior
[What should happen when this feature is configured]
## Reference Implementation
See posthog-js browser: `packages/browser/src/extensions/surveys.ts`
For mobile-specific patterns, see posthog-react-native: `packages/react-native/src/surveys/getActiveMatchingSurveys.ts`
## Related
- [links to the sibling SDK issues created for the same feature — list the ones that exist at creation time; the rest are backfilled below]
_This issue was generated by Claude using the `/survey-sdk-audit` skill._
Backfill Sibling Links
Issues are created one at a time, so earlier issues cannot link siblings that do not exist yet. After creating all issues for the feature, backfill each issue's ## Related section so every issue links every sibling:
Step 1: Fetch the current body to a temp file:
gh issue view 123 --repo PostHog/posthog-ios --json body --jq '.body' > /tmp/issue_body.md
Step 2: Use the Edit tool on the temp file to fill in the sibling links (and remove the placeholder). This lets the user review the diff before anything is pushed.
Step 3: Push the update:
gh issue edit 123 --repo PostHog/posthog-ios --body-file /tmp/issue_body.md
Completion Checklist
Before finishing the audit, verify all steps are complete:
Common Pitfalls
- Don't guess versions - always verify with changelog or git history
- Types ≠ Implementation - having a field in a data class doesn't mean filtering logic exists
- Model field ≠ Feature support - the field may be parsed but never used in decision-making (e.g.,
linkedFlagKey exists but linkedFlagVariant check is missing)
- Test code ≠ Production code - functions only in test files aren't shipped
- Flutter inherits from native - its "support" depends on iOS/Android SDK versions it requires
- Always search for existing issues first - before creating new GitHub issues
- Compare utility function implementations - functions like
canActivateRepeatedly may have different logic across SDKs; browser is the source of truth
- Built-in UI ≠ delegate - iOS, React Native, and Flutter have built-in survey rendering; Android is delegate-only (no built-in UI). A field on the display model is sufficient for Android (
issue: false) but for SDKs with built-in rendering, the rendering code must actually use the field
- Check rendering code, not just models - e.g., iOS exposes
shuffleOptions on PostHogDisplayChoiceQuestion but the SwiftUI QuestionTypes.swift completely ignores it when rendering choices
Post-Audit: Skill Improvement
After completing an audit, consider whether any learnings should be added to this skill file:
- New pitfalls discovered - Add to Common Pitfalls section
- New key files identified - Add to the file paths in Step 5
- New utility functions to compare - Add to the "Key utility functions" list
- Pattern changes - If SDK implementations have changed structure, update paths
If you find improvements, propose them to the user:
I found some learnings during this audit that could improve the skill:
- [describe the improvement]
Would you like me to update the skill file?