Skip to main content
The React Native SDK opens the canonical UserJourneys web interview inside your app with react-native-webview. It does three things:
  • It wraps one existing analytics track client so UserJourneys can observe selected app events.
  • It shows a native prompt before starting an event-triggered or synced-audience interview.
  • It resolves UserJourneys HTTPS invite links from Intercom, email, push, or any other channel.
You keep your analytics SDK and messaging tools. After the first integration, UserJourneys controls which Study Launch Rules, synced audiences, events, and invite links should launch an interview.

Install

npm install @userjourneys/interviews-react-native react-native-webview
You do not install a separate UserJourneys core package. The shared interview runtime is bundled into @userjourneys/interviews-react-native; react-native-webview is listed separately because it is a native module linked into your app binary.
Expo Go can run JavaScript-only app code, but a production integration should be validated in the same development build, EAS build, or bare React Native app that users receive so WebView, deep links, and microphone permissions match the release build.

Add microphone permissions

The in-app interview runs in react-native-webview, but voice capture still uses native app permissions. For iOS, add NSMicrophoneUsageDescription to the app Info.plist. For Android, add both permissions to the app manifest:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
Expo apps can declare the same values through android.permissions and ios.infoPlist in app config.

Get your SDK key

In the dashboard, go to Settings → API keys and copy the Interviews SDK key. This public key is the only credential the mobile SDK needs. Pass it as publicKey when you create the client below.

Create the client

Create the UserJourneys client next to your central analytics setup. If that client exposes track(eventName, properties), wrap it once.
analytics.ts
import { createUserJourneysInterviews } from "@userjourneys/interviews-react-native";
import { rawAnalytics } from "./existing-analytics";

export const interviews = createUserJourneysInterviews({
  publicKey: "USERJOURNEYS_INTERVIEWS_PUBLIC_KEY",
  referenceId: currentUser.id,
  metadata: {
    app_version: appVersion,
  },
  mapTrackProperties: (_eventName, properties) => ({
    total: typeof properties?.total === "number" ? properties.total : null,
    currency:
      typeof properties?.currency === "string" ? properties.currency : null,
  }),
});

export const analytics = interviews.wrapTrackClient(rawAnalytics);
You do not need to update every existing track call. Wrap the single analytics client your app already imports, then keep calling that client normally.
If your analytics provider uses a different method name or argument shape, keep that provider call unchanged and call interviews.track(eventName, properties) from the same central analytics helper.

Mount the host once

Render the host once near your app root. Eligible analytics events and synced audience matches show the built-in native prompt first. Accepted prompts and explicit invite links open the interview in-app.
AppRoot.tsx
import {
  UserJourneysInterviewHost,
} from "@userjourneys/interviews-react-native";
import { interviews } from "./analytics";

export function AppRoot() {
  return (
    <>
      <AppNavigator />
      <UserJourneysInterviewHost client={interviews} />
    </>
  );
}
The built-in prompt is a small native invite sheet. The host renders accepted interviews as a full-screen WebView. The interview UI itself comes from the same UserJourneys web embed used in the browser, so welcome, setup, active interview, completion, unavailable, and error states stay visually aligned. Synced audience prompts use the same prompt and host. When the current referenceId matches an active audience member connected to a Study Launch Rule, the SDK receives a pending invite during config load and shows the prompt.

Keep tracking normally

Your app keeps calling analytics as it does today.
CheckoutCompleteButton.tsx
analytics.track("Order Completed", {
  total: 50,
  currency: "USD",
});
When UserJourneys has an active trigger for that event, the SDK creates a pending invite and the prompt appears. If the user starts the invite, the SDK opens the in-app WebView. If the installed app cannot handle the WebView path, UserJourneys returns an external browser fallback URL and the prompt starts that fallback through React Native Linking.openURL. Which events and audiences launch an interview is controlled by Study Launch Rules in the dashboard. See Study Launch Rules to create and target them. If your central analytics client is Mixpanel, see the Mixpanel setup. Configure Universal Links/App Links for https://app.userjourneys.ai/i/* and https://app.userjourneys.ai/interviews/*, then pass incoming URLs to the SDK. UserJourneys also needs to authorize your app from the app.userjourneys.ai domain before those HTTPS links can open your installed app. Provide these app identifiers:
  • Apple Team ID and iOS bundle ID.
  • Android application ID and the SHA-256 signing certificate fingerprint for each release signing key that should open links.
Until those identifiers are active on the UserJourneys domain, the same HTTPS links still work as browser fallback links.
links.ts
import { Linking } from "react-native";
import { interviews } from "./analytics";

Linking.getInitialURL().then((url) => {
  if (url != null) void interviews.handleUserJourneysLink(url);
});

Linking.addEventListener("url", (event) => {
  void interviews.handleUserJourneysLink(event.url);
});
If the app is installed and supported, the link opens the in-app WebView. If the app is missing or unsupported, the same HTTPS link opens the browser interview.