Flow Control

Complete or dismiss the flow. Resolves the startFlow() Promise.

complete()#

Complete the flow successfully. This closes the flow and resolves the startFlow() Promise with completed: true.

Mobana.complete(data?: Record<string, unknown>): void
ParameterTypeDescription
dataRecord<string, unknown>Optional data to return to the app. Available as result.data in the startFlow() result.
flow.js
// Simple completion
document.getElementById('done-btn').addEventListener('click', () => {
  Mobana.complete();
});

// Completion with data
document.getElementById('submit-btn').addEventListener('click', () => {
  const selectedPlan = document.querySelector('input[name="plan"]:checked').value;
  
  Mobana.complete({
    selectedPlan,
    onboardingCompleted: true,
    timestamp: Date.now(),
  });
});

Returning Data to the App

flow.js
// Data is returned to the app via startFlow() result
Mobana.complete({
  selectedPlan: 'premium',
  preferences: {
    notifications: true,
    darkMode: false,
  },
});

// In the app:
// const result = await Mobana.startFlow('onboarding');
// if (result.completed) {
//   console.log(result.data.selectedPlan); // 'premium'
// }
System Event

Calling complete() automatically tracks a __completed__ system event for analytics. You don't need to track this manually.

dismiss()#

Dismiss the flow. This closes the flow and resolves the startFlow() Promise with dismissed: true.

Mobana.dismiss(): void
flow.js
// User wants to skip/close the flow
document.getElementById('skip-btn').addEventListener('click', () => {
  Mobana.dismiss();
});

// Close button in corner
document.querySelector('.close-btn').addEventListener('click', () => {
  Mobana.dismiss();
});
System Event

Calling dismiss() automatically tracks a __dismissed__ system event for analytics.

requestCallback()#

Request the app to perform an async action (e.g., trigger a purchase, validate a promo code) and return a result. The flow stays open while the app processes the request.

Mobana.requestCallback(data?: Record<string, unknown>, options?: { timeout?: number }): Promise<Record<string, unknown>>
ParameterTypeDescription
dataRecord<string, unknown>Arbitrary data to send to the app's onCallback handler.
options.timeoutnumberTimeout in seconds. Default: 300 (5 minutes). The Promise rejects if the app doesn't respond within this time.

Flow Side

flow.js
// Request the app to trigger a purchase
document.getElementById('buy-btn').addEventListener('click', async () => {
  const planId = document.querySelector('input[name="plan"]:checked').value;
  
  try {
    // Show loading state while app processes
    showLoading(true);
    
    const result = await Mobana.requestCallback(
      { action: 'purchase', planId },
      { timeout: 120 }  // 2 minute timeout for purchase flow
    );
    
    showLoading(false);
    
    if (result.success) {
      Mobana.haptic('success');
      Mobana.complete({ purchased: true, planId });
    } else {
      showError('Purchase failed. Please try again.');
    }
  } catch (error) {
    showLoading(false);
    showError('Something went wrong. Please try again.');
  }
});

App Side

Provide an onCallback handler when calling startFlow():

screens/Paywall.tsx
// In the app — provide onCallback when starting the flow
const result = await Mobana.startFlow('paywall', {
  params: { plans: availablePlans },
  onCallback: async (data) => {
    if (data.action === 'purchase') {
      const purchase = await purchaseManager.buy(data.planId);
      return { success: purchase.success, receipt: purchase.receipt };
    }
    return { error: 'Unknown action' };
  },
});
Handler Required

If the flow calls requestCallback() but no onCallback handler was provided to startFlow(), the Promise will reject with an error. Always wrap calls in try/catch.

Loading States

The flow is responsible for showing its own loading UI while waiting for the callback result. The bridge does not display any loading indicators automatically.

To track custom events from your flow, see Flow Events and trackEvent().