Skip to main content
Use the analytics wrapper when your app already sends product events through one central client with a track(eventName, properties) method. This is the Mixpanel path and also works for app-owned analytics helpers with the same method shape. Analytics providers with different event APIs should call interviews.track(eventName, properties) from the app’s central analytics helper instead.

Flow

analytics.track("Order Completed")
  -> original analytics call runs
  -> SDK checks cached UserJourneys trigger config in the background
  -> unrelated events are ignored locally
  -> matching events are resolved with UserJourneys
  -> server returns webview, external_browser, or not_eligible
  -> SDK sets pendingInvite
  -> app shows a native prompt
  -> accepted prompt opens WebView or browser fallback
The SDK does not replace your analytics provider. It observes the same event stream from one wrapper point and preserves the original track return value. UserJourneys config, API, or network failures are reported through diagnostics and do not block the original analytics call.

Track client shape

The wrapped client must have a track method whose first argument is the event name and whose second argument is the event properties object.
type TrackMethodClient = {
  track: (
    eventName: string,
    properties?: Record<string, unknown>,
    ...extraArgs: unknown[]
  ) => unknown;
};
wrapTrackClient returns a proxy with the same surface as the original client. All properties other than track pass through unchanged. When track is called, the wrapper:
  • calls the original analytics client first;
  • returns the original track result;
  • reads the event name and allowlisted properties;
  • starts UserJourneys launch resolution in the background only when the cached trigger config says the event can launch an interview.

Server-controlled triggers

Study Launch Rules own trigger config, eligibility, interview selection, and fallback behavior after the app integration. The SDK loads active event trigger config for the project, caches it for the server-provided TTL, and ignores unrelated analytics events locally. Matching events create a pending invite instead of opening an interview without user action. You do not need an app release when UserJourneys changes which study is active for an event. The app does not define trigger rules. If UserJourneys changes the event-to-study mapping, targeting, fallback policy, or active study, the server config changes and the installed SDK keeps working. To create an event trigger, add an app-event Study Launch Rule on the study and set its event name.

Metadata

Only pass allowlisted primitive metadata.
const interviews = createUserJourneysInterviews({
  publicKey: "USERJOURNEYS_INTERVIEWS_PUBLIC_KEY",
  referenceId: user.id,
  mapTrackProperties: (_eventName, properties) => ({
    total: typeof properties?.total === "number" ? properties.total : null,
    currency:
      typeof properties?.currency === "string" ? properties.currency : null,
  }),
});
Nested analytics payloads, tokens, emails, and private vendor ids should stay out of SDK metadata.

Prompt before opening

Matching events create a pending invite. The mounted UserJourneysInterviewHost shows the in-app popup for that invite. Accepting the prompt opens the in-app WebView or browser fallback. Dismissing the prompt clears the invite without opening anything. See Customize the prompt to render your own prompt component.