Conversation
…ll events Superwall-Android never wrote presentation_id into outgoing paywall event payloads (paywall_page_view, paywall_open, paywall_close, etc.), which breaks any dashboard funnel that correlates a set of page views into one paywall session. Confirmed on live ClickHouse data: the field is 100% empty on Android across every SDK version, vs 0% empty on iOS. - PaywallCloseReason: add a `description` extension mirroring iOS's camelCase close-reason strings (systemLogic, forNextPaywall, webViewFailedToLoad, manualClose, none). - PaywallInfo: add `presentationId`, and serialize it alongside the already-modeled-but-never-emitted close_reason/cache_key/build_id in eventParams(). - Paywall: add a transient `presentationId` field, threaded through getInfo(). - PaywallRequestManager.updatePaywall: mint a fresh UUID presentationId on every getPaywall() call that results in a presentation (fresh fetch, in-flight-task reuse, and content-cache hit), so repeat presentations of a cached paywall get distinct, correlatable IDs. Trade-off: PaywallLoad.Complete/PaywallProductsLoad.* events track before updatePaywall runs, so they won't carry presentation_id — same existing timing gap as experiment_id/variant_id/presentation_source_type. paywall_open/paywall_page_view/paywall_close all fire after updatePaywall and reliably get a stable ID.
Translated paywalls rendered in the default language first, then visibly
re-rendered once the template_variables message delivered deviceLocale to
paywall.js (that message is gated on product/billing loading, so it can
take seconds). The web runtime now reads window.__SW_DEVICE_PRELOAD__ at
boot and seeds its locale from it, so inject that global before any page
JavaScript runs:
- Add DevicePreloadScript, a pure builder that serializes the payload
with kotlinx.serialization so hostile locale strings cannot break out
of the script, producing exactly:
window.__SW_DEVICE_PRELOAD__ = {"deviceLocale":"en_US"};
- Install it via WebViewCompat.addDocumentStartJavaScript (androidx.webkit,
new dependency) when the WebView supports DOCUMENT_START_SCRIPT, and
fall back to evaluateJavascript in WebViewClient.onPageStarted on older
WebView versions.
- The locale comes from PaywallViewState.locale, which is the same
DeviceHelper.locale value later sent as deviceLocale in
template_variables, so the later message is a visual no-op.
- Unit-test the builder (exact output, quote escaping, longer and
non-ASCII locales) and add a CHANGELOG entry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01775Up1AYfMgNQybxjnoDSg
…entation-id fix: emit presentation_id, close_reason, cache_key, build_id on paywall events
The test asserted externalAccountId equals sha256-of-user-123 but never stubbed storage.read(AppUserId), so userId fell back to the generated anonymous alias. Stub the stored app user ID like the sibling test does. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UL13jCN87cPLKtmZnTYUrb
The document-start script path required adding androidx.webkit as a new dependency for every SDK user. It bought little: the paywall runtime reads window.__SW_DEVICE_PRELOAD__ when its network-fetched bundle boots, so an evaluateJavascript from onPageStarted lands well before that — and since the web runtime now seeds exclusively from the preload global, a missed injection just means today's behavior (wait for template_variables), never a wrong translation. This matches how the SDK already injects JS (plain evaluateJavascript, like the selection/zoom scripts), just hooked at page start rather than template delivery, which would be too late. DevicePreloadScript and its tests are unchanged; the script is now built lazily in the hook so it always uses the freshest locale. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01775Up1AYfMgNQybxjnoDSg
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01775Up1AYfMgNQybxjnoDSg
Fix Play Store user ID hashing
…f-o43go3 Inject device locale into paywall WebView at document start
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
2.8.1
Fixes
paywall_open,paywall_page_view,paywall_close, etc.) now include apresentation_id, a unique identifier minted for each paywall presentation. Adds the previously-missingclose_reason,cache_key, andbuild_idfields to these events, matching the data already sent by the iOS SDK.