Skip to main content

API Reference

Complete API documentation for all exported components, hooks, and types.

Components​

OnboardingProvider​

The root provider component that wraps your app and provides onboarding context for data fetching.

import { OnboardingProvider } from "@rocapine/react-native-onboarding";

<OnboardingProvider
client={client}
locale="en"
customAudienceParams={{ onboardingId: "abc-123" }}
customActions={{
trackCta: async ({ variables }) => {
console.log("trackCta", variables);
},
}}
>
<YourApp />
</OnboardingProvider>

Props​

PropTypeDefaultDescription
clientOnboardingStudioClientRequiredClient instance for API communication
localestring"en"Locale for fetching steps
customAudienceParamsRecord<string, any>{}Static audience params (build-time facts such as an onboardingId). Merged under the OnboardingStudio user-property store, which wins per key, and read once when the onboarding is served — a later change applies to the next serve (next mount or launch).
customActionsCustomActions{}Map of named handlers invokable from ComposableScreen Button.actions { type: "custom", function, variables? }. See Custom Actions

CustomActionHandler​

import type {
CustomActionHandler,
CustomActions,
ComposableVariableEntry,
} from "@rocapine/react-native-onboarding";

type CustomActionHandler = (args: {
variables: Record<string, ComposableVariableEntry | undefined>;
}) => void | Promise<void>;

type CustomActions = Record<string, CustomActionHandler>;

variables is filtered to the names listed in the action's variables array (missing keys yield undefined). Handlers may return a Promise — the action chain awaits before proceeding.


ThemeProvider​

The theme provider component that wraps your app and provides theme context. Import from the UI SDK.

import { ThemeProvider } from "@rocapine/react-native-onboarding-ui";

<ThemeProvider
initialColorScheme="light"
customTheme={{
colors: { primary: "#FF5733" },
typography: {
fontFamily: { title: "Poppins-Bold" }
}
}}
>
<YourApp />
</ThemeProvider>

Props​

PropTypeDefaultDescription
initialColorScheme"light" | "dark""light"Initial color scheme
customThemeDeepPartial<Theme>-Custom theme to override both light and dark mode tokens
customLightThemeDeepPartial<Theme>-Custom theme tokens for light mode only
customDarkThemeDeepPartial<Theme>-Custom theme tokens for dark mode only

OnboardingPage​

Central routing component that renders the appropriate page based on step type.

<OnboardingPage
step={step}
onContinue={handleContinue}
theme={theme}
customComponents={customComponents}
/>

Props​

PropTypeDescription
stepOnboardingStepTypeStep data to render
onContinue(args?: any) => voidCallback when user continues
themeThemeOptional theme override (defaults to theme from ThemeProvider)
customComponentsCustomComponentsCustom components for the onboarding
isSandboxbooleanEnable sandbox mode for development

ProgressBar​

Global progress indicator component. Add once in your app layout, typically inside both providers.

<OnboardingProvider {...props}>
<ThemeProvider>
<ProgressBar isProgressBarVisible={isProgressBarVisible} progressPercentage={progressPercentage} />
<YourApp />
</ThemeProvider>
</OnboardingProvider>

Props​

None. Reads from progress context automatically.


Page Renderers​

Individual renderer components for each page type.

import {
QuestionRenderer,
MediaContentRenderer,
CarouselRenderer,
PickerRenderer,
LoaderRenderer,
RatingsRenderer,
CommitmentRenderer,
} from "@rocapine/react-native-onboarding";

Common Props:

PropTypeDescription
stepStepTypeType-specific step data
onContinue(args?: any) => voidCallback when user continues

Example:

<MediaContentRenderer
step={mediaContentStep}
onContinue={(args) => console.log(args)}
/>

Hooks​

useOnboardingQuestions​

Hook for accessing onboarding steps in your pages.

import { useOnboardingQuestions } from "@rocapine/react-native-onboarding";

const {
step,
isLastStep,
stepsLength,
onboardingMetadata,
steps
} = useOnboardingQuestions({
stepNumber: 1,
});

Parameters​

ParamTypeDescription
stepNumbernumberThe current step number (1-indexed)

Returns​

PropertyTypeDescription
stepOnboardingStepTypeCurrent step data
isLastStepbooleanTrue if this is the last step
stepsLengthnumberTotal number of steps
onboardingMetadataOnboardingStepMetadataMetadata from API (id, name, audienceId, etc.)
stepsOnboardingStepType[]Array of all steps

useTheme​

Hook for accessing theme tokens and utilities. Import from the UI SDK.

import { useTheme } from "@rocapine/react-native-onboarding-ui";

const { theme, colorScheme, toggleTheme } = useTheme();

Returns​

PropertyTypeDescription
themeThemeCurrent theme tokens (colors + typography)
colorScheme"light" | "dark"Current color scheme
toggleTheme() => voidFunction to toggle between light and dark mode

useCustomComponents​

Hook for accessing custom component overrides.

import { useCustomComponents } from "@rocapine/react-native-onboarding";

const customComponents = useCustomComponents();
const Button = customComponents.QuestionAnswerButton || DefaultButton;

Returns​

PropertyTypeDescription
customComponentsCustomComponentsCustom component overrides

Classes​

OnboardingStudioClient​

Client for communicating with the Rocapine CMS backend.

import { OnboardingStudioClient } from "@rocapine/react-native-onboarding";

const client = new OnboardingStudioClient(projectId, options);

Constructor​

new OnboardingStudioClient(
projectId: string,
options?: {
appVersion?: string;
assignmentId?: string | false | (() => string | false | null | undefined | Promise<string | false | null | undefined>);
isSandbox?: boolean;
baseUrl?: string;
fallbackOnboarding?: Onboarding;
timeout?: number;
cacheKey?: string;
}
)

Parameters​

ParamTypeDefaultDescription
projectIdstringRequiredYour Rocapine project ID
options.appVersionstring-Your app version (sent to the CMS for version targeting)
options.assignmentIdstring | false | () => string | false | Promise<…>Installation idStable per-person id sent with every request so a person keeps the same variant across launches. A getter is called on every request. false opts out. See Sticky variant assignment.
options.isSandboxbooleanfalseEnable sandbox/draft mode (always fetches fresh, never caches)
options.baseUrlstringRocapine prodOverride the CMS endpoint (testing/self-host)
options.fallbackOnboardingOnboarding-Payload returned on fetch failure (never cached)
options.timeoutnumber-End-to-end timeout in ms per request, covering assignmentId resolution and the fetch together
options.cacheKeystring-Custom cache key. Persists the payload under rocapine-onboarding-sdk-{cacheKey} cache-first with no background revalidation (a pinned version survives across launches until you clearCache()). Omit for the default key with stale-while-revalidate. See Caching Strategy.

Sticky variant assignment​

Every getSteps and getPaywalls request carries an assignmentId in the X-Assignment-Id request header, so the server can put the same person in the same variant every time. It is never put on the URL, because the id may be one of your user ids and request URLs end up in server logs. A custom audience param named assignmentId is dropped, never sent. The SDK resolves it per request, in this order:

  1. options.assignmentId: a string, or a getter (sync or async) called on every request.
  2. An installation id: a UUID the SDK generates on first use and persists in AsyncStorage under rocapine-assignment-id. It survives app updates, clearCache() and OnboardingStudio.reset(). It is lost when the app is uninstalled or its storage is cleared.
  3. Nothing: if storage cannot be read or written, the X-Assignment-Id header is not sent, rather than sent with an id the next launch would not repeat.

A host value of undefined, null or "" falls back to the installation id for that request.

A getter that throws, rejects, or takes longer than 2 seconds fails closed: that request sends no assignmentId, and the installation id is not read, created or written. A getter that cannot answer may be one that would have answered false (no consent yet), so the SDK never substitutes the stored id for it. Resolving the id counts against options.timeout, so a slow getter cannot delay fallbackOnboarding past it.

To assign by your RevenueCat App User ID (stable across devices once the user is identified):

import Purchases from "react-native-purchases";

// App entry, at module scope: configure RevenueCat FIRST, then the SDK.
Purchases.configure({ apiKey: REVENUECAT_API_KEY });

OnboardingStudio.init({
projectId,
assignmentId: () => Purchases.getAppUserID(),
});

Purchases.configure() must have run before the first getSteps or getPaywalls request, and OnboardingProvider / PaywallProvider fetch when they mount. If your RevenueCat setup is asynchronous (for example, you load the API key first), await it before mounting them:

const [purchasesReady, setPurchasesReady] = useState(false);
useEffect(() => {
setupPurchases().then(() => setPurchasesReady(true)); // resolves after Purchases.configure()
}, []);
if (!purchasesReady) return <Splash />;
return <OnboardingProvider>{/* … */}</OnboardingProvider>;

If a request runs before configure, the getter throws, so that request sends no assignmentId (it fails closed, see above) and the server picks a variant at random. On a later launch the same person is assigned by their RevenueCat id and can land in a different variant.

The SDK never reads RevenueCat on its own: the getter is the only way to use the RevenueCat App User ID. Detecting it automatically would make the id depend on whether RevenueCat was configured before the first request, so the same install could send different ids on different launches.

Privacy and opting out​

What is stored, and when: on the first getSteps or getPaywalls request without a host id, the SDK writes one random UUID to AsyncStorage under rocapine-assignment-id, and sends it in the X-Assignment-Id header on that request and every later one. It is not derived from any device or advertising identifier, and it is not shared with any other SDK. It stays until the app is uninstalled or its storage is cleared. If you pass your own id, the SDK sends that instead and stores nothing. Declare it accordingly in your privacy disclosures, for example as a device or user identifier used for app functionality.

To send nothing, pass false, or return false from the getter. The X-Assignment-Id header is then not sent, and the installation id is never read, created or written. Every request is then assigned independently, with no stickiness across requests. null and "" are not an opt-out: they fall back to the installation id.

To wait for consent, return false until it is given:

OnboardingStudio.init({
projectId,
assignmentId: () => (hasConsented() ? undefined : false), // undefined → installation id
});

An installation id written before an opt-out stays on disk. It is not sent while the opt-out applies. To delete it, call clearAssignmentId():

// Consent withdrawn: stop sending an id, then delete the stored one.
setConsented(false); // your getter now returns false
await OnboardingStudio.clearAssignmentId(); // or client.clearAssignmentId()

clearAssignmentId() removes rocapine-assignment-id from AsyncStorage and forgets the id in memory. It works before init. A request that is already resolving the id when you call it sends none, even if your getter is still pending, and a first-launch id still being written is not brought back. It rejects if the removal fails, or if it is still waiting after 2 seconds. Each queued storage operation is bounded this way, but only for the caller. The operations still run strictly one after another, so a removal never overtakes a write already in flight. While a write or removal hangs, the requests queued behind it wait 2 seconds each and then send no assignmentId. That wait counts against options.timeout, which covers the whole request. A read that hangs does not block later requests. A timed-out request never mints an id, unless its write was already in flight. That write lands before any later removal. Make the getter return false first: otherwise the next request without a host id mints a new installation id, which can put the person in a different variant. Use that deliberately if you want a fresh assignment. OnboardingStudio.reset() does not call it, so logging out does not move anyone to another variant.

Changing the id can change the variant

The server picks the variant from the id. If the id a person sends changes, for example from an anonymous id to a logged-in user id, that person can move to another variant once, and is counted under both ids. To avoid it, pass an id that is already final on the first request, or keep the default installation id.

Methods​

getSteps(params)

Fetches onboarding steps from the CMS.

const { steps, headers } = await client.getSteps({
locale: "en",
onboardingId: "abc-123",
});

clearAssignmentId()

Deletes the stored installation id sent as assignmentId. Same effect as OnboardingStudio.clearAssignmentId(), because the id is shared by the whole process. See Privacy and opting out.

await client.clearAssignmentId();

clearCache()

Removes this client's cached onboarding payload from AsyncStorage (the key derived from options.cacheKey, or the default key). The next query mount or app launch is then a cache miss and refetches. To force an in-session refetch as well, also invalidate the React Query key ["onboardingQuestions", ...].

await client.clearCache();

Utilities​

getTextStyle​

Utility function to get semantic text styles from theme.

import { getTextStyle } from "@rocapine/react-native-onboarding";

const textStyle = getTextStyle(theme, "heading1");

Parameters​

ParamTypeDescription
themeThemeTheme object from useTheme()
styleNameTextStyleNameName of the semantic style

TextStyleName Options​

  • heading1 - Large headings (32px, semibold)
  • heading2 - Medium headings (24px, semibold)
  • heading3 - Small headings (18px, medium)
  • body - Body text (16px, regular)
  • bodyMedium - Medium body text (16px, medium)
  • label - Labels (14px, medium)
  • caption - Captions (12px, regular)
  • button - Button text (16px, medium)

Returns​

{
fontSize: number;
fontWeight: string;
lineHeight: number;
fontFamily?: string;
}

Types​

OnboardingStepType​

Union type of all step types:

type OnboardingStepType =
| QuestionStepType
| MediaContentStepType
| CarouselStepType
| PickerStepType
| LoaderStepType
| RatingsStepType
| CommitmentStepType;

OnboardingStepMetadata​

Metadata returned from the API containing information about the onboarding flow:

interface OnboardingStepMetadata {
id: string;
name?: string;
audienceId?: string;
audienceName?: string;
audienceOrder?: number;
locale?: string;
draft?: boolean;
variantKey?: string | null;
deploymentId?: number | null;
}
PropertyTypeDescription
idstringUnique onboarding ID
namestring?Display name of the onboarding
audienceIdstring?Targeted audience ID
audienceNamestring?Targeted audience name
audienceOrdernumber?Audience priority order
localestring?Locale of the onboarding
draftboolean?Whether this is a draft version
variantKeystring | null?Variant of the onboarding the user was served; the parent onboarding reports the reserved MAIN_VARIANT_KEY ("main"). null and absent mean the same thing (no variant information, e.g. an older server); treat them identically
deploymentIdnumber | null?Published deployment that was served; null for a draft payload

MAIN_VARIANT_KEY is exported from @rocapine/react-native-onboarding:

import { MAIN_VARIANT_KEY } from "@rocapine/react-native-onboarding";

const variant = metadata.variantKey ?? undefined; // null and absent: no variant info
const isMain = variant === MAIN_VARIANT_KEY; // "main"

ThemeTokens​

Partial theme override type:

interface ThemeTokens {
colors?: {
primary?: string;
secondary?: string;
disable?: string;
tertiary?: {
tertiary1?: string;
tertiary2?: string;
tertiary3?: string;
};
neutral?: {
highest?: string;
higher?: string;
high?: string;
medium?: string;
low?: string;
lower?: string;
lowest?: string;
};
surface?: {
lowest?: string;
lower?: string;
low?: string;
medium?: string;
high?: string;
higher?: string;
highest?: string;
opposite?: string;
};
text?: {
primary?: string;
secondary?: string;
tertiary?: string;
opposite?: string;
disable?: string;
};
};
typography?: {
fontFamily?: {
title?: string;
text?: string;
tagline?: string;
};
fontSize?: {
xs?: number;
sm?: number;
md?: number;
lg?: number;
xl?: number;
"2xl"?: number;
"3xl"?: number;
"4xl"?: number;
};
fontWeight?: {
regular?: string;
medium?: string;
semibold?: string;
bold?: string;
extrabold?: string;
};
lineHeight?: {
tight?: number;
normal?: number;
relaxed?: number;
};
textStyles?: {
heading1?: TextStyle;
heading2?: TextStyle;
heading3?: TextStyle;
body?: TextStyle;
bodyMedium?: TextStyle;
label?: TextStyle;
caption?: TextStyle;
button?: TextStyle;
};
};
}

CustomComponents​

Custom component overrides interface:

interface CustomComponents {
QuestionAnswerButton?: React.ComponentType<QuestionAnswerButtonProps>;
QuestionAnswersList?: React.ComponentType<QuestionAnswersListProps>;
}

Component Props Interfaces​

QuestionAnswerButtonProps

interface QuestionAnswerButtonProps {
answer: { label: string; value: string };
selected: boolean;
onPress: () => void;
theme: Theme;
index: number;
isFirst: boolean;
isLast: boolean;
}

QuestionAnswersListProps

interface QuestionAnswersListProps {
answers: Array<{ label: string; value: string }>;
selected: Record<string, boolean>;
onAnswerPress: (value: string) => void;
multipleAnswer: boolean;
theme: Theme;
}

Default Exports​

Export default components for composition:

import {
DefaultQuestionAnswerButton,
DefaultQuestionAnswersList,
} from "@rocapine/react-native-onboarding";

These allow you to wrap or extend the default implementations while maintaining the base styling.


Type Guards​

isQuestionStep​

import { isQuestionStep } from "@rocapine/react-native-onboarding";

if (isQuestionStep(step)) {
// TypeScript knows this is QuestionStepType
console.log(step.payload.answers);
}

Similar type guards exist for all step types.


Next Steps​