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#
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
}| source | When it fires |
|---|---|
universal_link | OS 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). |
probabilistic | Server-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. |
deferred | Synthesized 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.
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.