startFlow()
Display an in-app flow in a full-screen modal. Requires MobanaProvider.
Method Signature#
Mobana.startFlow(slug: string, options?: FlowOptions): Promise<FlowResult>Prerequisites#
Flows require MobanaProvider to be mounted in your component tree and react-native-webview installed.
import { MobanaProvider } from '@mobana/react-native-sdk';
export default function App() {
return (
<MobanaProvider>
{/* Your app */}
</MobanaProvider>
);
}Usage#
const result = await Mobana.startFlow('onboarding');
if (result.completed) {
console.log('User completed the flow!', result.data);
navigation.navigate('Home');
} else if (result.dismissed) {
console.log('User dismissed the flow');
}Parameters#
| Parameter | Type | Description |
|---|---|---|
slugRequired | string | The flow's unique identifier (slug) from the Dashboard. |
placement | string | Where in the host app this flow is triggered — used as an analytics dimension. Any consistent label works: 'post_signup', 'settings_upgrade_button', 'paywall_cta'. Max 64 characters, letters/digits/_/-/:/. only. Does not affect which flow or version is served. |
params | Record<string, unknown> | Custom parameters available in the flow via getParams(). |
onEvent | (event: string) => void | Callback fired when the flow calls Mobana.trackEvent(). |
onCallback | (data: Record<string, unknown>) => Promise<Record<string, unknown>> | Async callback invoked when the flow calls requestCallback(). Allows the flow to request app actions (e.g., purchases) without closing. |
Return Value#
| Property | Type | Description |
|---|---|---|
completed | boolean | True if user completed the flow (called complete()). |
dismissed | boolean | True if user dismissed the flow (called dismiss()). |
error | FlowError | undefined | Error code if the flow couldn't be shown. |
data | Record<string, unknown> | undefined | Custom data passed to complete(data). |
sessionId | string | undefined | Unique session ID for this flow presentation. Use with trackConversion(). |
trackEvent | (event: string, data?: Record<string, unknown>) => Promise<boolean> | Function to track events after the flow closes. |
Placement#
Pass a placement label to record where in the app the flow was triggered. The label is attached to every event emitted during that presentation (started, completed, dismissed, and any custom events), so you can filter and compare analytics by placement in the Mobana dashboard.
// Attach a placement label so this event is segmentable in analytics
const result = await Mobana.startFlow('onboarding', {
placement: 'post_signup',
});
// Works alongside all other options
const result2 = await Mobana.startFlow('paywall', {
placement: 'settings_upgrade_button',
params: { plans: availablePlans },
});Placement is analytics-only — it does not change which flow or version is served. Values that exceed 64 characters or contain disallowed characters are silently ignored.
Passing Parameters#
Pass custom data to your flow that's accessible via getParams():
const result = await Mobana.startFlow('welcome', {
// Custom parameters available inside the flow
params: {
userName: user.name,
isPremium: user.subscription?.active,
features: ['feature1', 'feature2'],
},
});Event Callback#
Listen for custom events emitted by the flow:
const result = await Mobana.startFlow('onboarding', {
params: { userName: 'John' },
// Callback fired when flow calls Mobana.trackEvent()
onEvent: (eventName) => {
analytics.track(eventName);
console.log('Flow event:', eventName);
},
});App Callback#
Allow the flow to request async actions from the app (e.g., trigger a purchase, validate a promo code) without closing. The flow calls requestCallback() and awaits the result:
const result = await Mobana.startFlow('paywall', {
params: { plans: availablePlans },
// Async callback when flow calls Mobana.requestCallback()
onCallback: async (data) => {
if (data.action === 'purchase') {
const purchase = await purchaseManager.buy(data.planId);
return { success: purchase.success, receipt: purchase.receipt };
}
if (data.action === 'validatePromo') {
const promo = await api.validatePromo(data.code);
return { valid: promo.valid, discount: promo.discount };
}
return { error: 'Unknown action' };
},
});If the flow calls requestCallback() but no onCallback handler was provided, the flow's Promise will reject. See requestCallback() for flow-side usage.
Error Handling#
const result = await Mobana.startFlow('premium-upsell');
if (result.error) {
switch (result.error) {
case 'NOT_FOUND':
console.log('Flow does not exist or is not published');
break;
case 'PLAN_REQUIRED':
console.log('Flows require a Pro plan');
break;
case 'FLOW_LIMIT_EXCEEDED':
console.log('Monthly flow view limit reached');
break;
case 'PROVIDER_NOT_MOUNTED':
console.log('MobanaProvider is not in the component tree');
break;
case 'SDK_NOT_CONFIGURED':
console.log('Call Mobana.init() first');
break;
case 'NETWORK_ERROR':
case 'SERVER_ERROR':
console.log('Could not load flow, try again later');
break;
}
return;
}startFlow() never throws. Check result.error to handle issues gracefully.
Post-Flow Tracking#
Track events or conversions after a flow closes:
const result = await Mobana.startFlow('pre-purchase');
if (result.completed) {
// Later, after user makes a purchase...
// Option 1: Use trackEvent for flow-specific events
await result.trackEvent?.('purchase_completed', { amount: 49.99 });
// Option 2: Use trackConversion with sessionId for attribution
Mobana.trackConversion('purchase', 49.99, result.sessionId);
}Caching#
- Flow content is cached: After the first load, flows are cached locally for offline access and faster display.
- Version-aware: The SDK automatically checks for updates and fetches new content when you publish changes.
- Prefetch for instant display: Use prefetchFlow() to load flows in advance.