onDeepLink()

Subscribe to smart-link / deeplink events. Fires for Universal Links, deferred deeplinks, and probabilistic re-engagement matches. See the Smart Links guide for setup.

Signature#

Mobana.onDeepLink<T = Record<string, unknown>>(
  handler: (event: DeepLinkEvent<T>) => void
): () => void;

Usage#

App.tsx
import { Mobana } from '@mobana/react-native-sdk';

interface UnlockData { unlock?: string; ref?: string }

const unsubscribe = Mobana.onDeepLink<UnlockData>((event) => {
  if (event.data?.unlock) applyUnlock(event.data.unlock);
  if (event.data?.ref) trackReferral(event.data.ref);

  // Optionally branch on delivery source
  if (event.source === 'universal_link') {
    // Tap-to-open from a real link tap.
  } else if (event.source === 'probabilistic') {
    // Re-engagement after the OS failed to intercept the URL.
  } else if (event.source === 'deferred') {
    // First-launch delivery from the install-attribution path.
  }
});

// Later, when you no longer need it (e.g. user logs out)
unsubscribe();

Or via the MobanaProvider prop — equivalent to calling Mobana.onDeepLink(...) in a useEffect, but with automatic cleanup on unmount:

<MobanaProvider
  onDeepLink={(event) => {
    if (event.data?.unlock) applyUnlock(event.data.unlock);
  }}
>
  <App />
</MobanaProvider>

DeepLinkEvent shape#

interface DeepLinkEvent<T = Record<string, unknown>> {
  url: string;                    // Raw URL the OS / probe surfaced (empty string for 'deferred')
  data?: T;                       // Typed payload from ?data= JSON
  utm: {
    source?: string;
    medium?: string;
    campaign?: string;
    content?: string;
    term?: string;
  };
  clickParams: Record<string, string>;  // ttclid / fbclid / gclid / etc.
  source: 'universal_link' | 'probabilistic' | 'deferred';
  timestamp: number;              // ms since epoch when the SDK captured the event
}
sourceWhen it fires
universal_linkOS handed a URL to the app via Linking. Cold-start (getInitialURL) and mid-session both route here. Same URL won't fire twice within 50 ms (iOS double-delivery dedup).
probabilisticServer-side re-engagement match. Fires on cold start and on every background→foreground transition (debounced ~1.5 s) when /api/deeplink/probe returns a match.
deferredSynthesized from the install attribution payload when /find matched a Mobana click but no UL was delivered (typical of first-time installs whose tap came through the app store).

Wire both surfaces#

The deeplink delivery matrix means any given tap may surface via getAttribution(), onDeepLink(), or both — depending on whether the user is a fresh install, whether the OS intercepted the URL, and whether the app was running. Wire the same idempotent handler to both surfaces so you never special-case which path won:

// Wire the SAME idempotent handler to BOTH surfaces.
// Different deeplink delivery cases surface via different paths,
// and a few cases fire both — making the handler idempotent is
// the cleanest way to never special-case which path won.
function applyPayload(data?: UnlockData) {
  if (data?.unlock) applyUnlock(data.unlock);
}

const result = await Mobana.getAttribution<UnlockData>();
if (result.status === 'matched') applyPayload(result.attribution.data);

Mobana.onDeepLink<UnlockData>((event) => applyPayload(event.data));

Behaviour#

Multiple subscribers

Standard event-emitter semantics. Every registered handler receives every event. The provider's onDeepLink prop is sugar over Mobana.onDeepLink(...); using both is fine.

Late subscribers

A subscriber that registers within ~30 s of an event being fired with no handlers attached gets the buffered event replayed exactly once. Useful when your onDeepLink setup runs in a screen that mounts after a fast cold-start deeplink.

URL filtering

Only URLs whose host matches your configured Mobana endpoint ({appId}.mobana.ai or your custom endpoint domain) trigger onDeepLink. Other URLs (your own custom URI schemes, third-party share handlers, etc.) are passed through untouched — wire them via Linking.addEventListener directly.

Tracking-disabled mode

When tracking is off, onDeepLink still fires for every smart-link tap. The universal_link case is parsed locally on-device and never round-trips to the server. The probabilistic case still calls the probe (anonymously, without an installId) so re-engagement payloads keep working — server just doesn't link the match to a device.

Universal Links must be configured

Without an iOS Team ID + Android SHA-256 fingerprints in App Settings → Deeplinks (and the corresponding Associated Domains / <intent-filter> entries in your app), the OS won't hand smart-link URLs to your app — they'll always go through the web flow. The probe and deferred paths still work, but you lose the instant tap-to-open UX.

AI agents: for complete Mobana SDK & API documentation, get full context here or visit llms.txt