Your deep link,
after the install.
Deferred deep linking that does one job. Deterministic on Android via Play Install Referrer. Probabilistic on iOS, labeled honestly, failing open every time.
$ npx expo install @uselinking/react-native
✓ added @uselinking/react-native
# app.json → plugins: [["@uselinking/react-native", { "linkDomain": "acme.lnk.uselinking.com" }]]
$ npx expo prebuild
✓ ios applinks:acme.lnk.uselinking.com entitlement written
✓ android https app-links intent filter written
# first launch after an install, on a real device:
✓ POST /v1/match → matchType=unique path=/invite/9fb2 41msThree steps, and the third one matters most.
A link tapped in a mobile browser with no app installed loses everything at the store boundary. We carry the payload across it — and when we can't, we say so.
Store bounce, payload parked
Your link hits our redirect endpoint. We park the deep path and its params with a short TTL, plus a coarse click fingerprint, then bounce to the store. Desktop and unsupported browsers go straight to your fallback URL.
First launch claims it
On first launch the SDK calls /v1/match. Android sends back the Play Install Referrer we planted — an exact identity. iOS sends device signals and the server looks for exactly one candidate in the window.
No guess is better than a wrong guess
Zero candidates, or several that can't be told apart, returns none and your app runs its normal onboarding. A user dropped into someone else's invite is worse than a user dropped into the default screen.
One of these platforms tells you the truth.
Android hands the payload through the install intact. iOS hands you nothing, so the match is inferred — and every response says which of the two you got.
| Platform | How the payload survives | Accuracy |
|---|---|---|
| Android deterministic | The payload rides the Play Store referrer parameter and the app reads it back verbatim via the Play Install Referrer API. No fingerprinting, no inference. | Exact. It either arrives or the user never went through the store. |
| iOS probabilistic | The App Store passes nothing through, so the server matches the first launch against pending clicks on IP bucket, OS major, device class and locale, inside a short TTL, and requires a single surviving candidate. | Typically 70–90%. Carrier-grade NAT, iCloud Private Relay and a WiFi↔cellular switch between click and install are the known holes. |
Three words your code can branch on.
import { DeepLinkProvider, useDeferredLink } from '@uselinking/react-native'
export default function App() {
return (
<DeepLinkProvider config={{ apiKey: process.env.EXPO_PUBLIC_USELINKING_KEY }}>
<Root />
</DeepLinkProvider>
)
}
function Root() {
const { isLinkProcessed, link } = useDeferredLink()
// First launch, straight after the install:
// link = { path: '/invite/9fb2', params: { it: 'ey…' },
// matchType: 'unique', clickId: '3f0c…' }
if (!isLinkProcessed) return <Splash />
return <Navigator initial={link?.path ?? '/home'} />
}- ▸unique — one candidate survived filtering, or Android handed us an exact referrer. Route them.
- ▸weak — strict filtering eliminated everything, but only one click was pending at all. Probably right; you decide how much to trust it.
- ▸none — nothing to claim. Normal onboarding.
- ▸Every click is consumed once. Two devices racing the same pending click means one wins and the other gets
none.
Not an attribution suite. Just the link.
- ▸Your own link domain, with Universal Links and App Links assets served for you — no
.well-knownfiles to babysit. - ▸An Expo config plugin that writes the associated-domains entitlement and the Android intent filter — the two things everyone gets wrong.
- ▸A click → install → match funnel in the dashboard, broken down by confidence, so a drop in match rate is visible the day it happens.
- ▸First-party by construction. Signals stay server-side and are used to restore the user's own intent — no cross-app tracking, no ad attribution, no SDK-side identifiers.
- ▸No attribution suite priced like one. Branch and AppsFlyer solve ad-network measurement; most apps only ever needed the link to survive.
- ▸No clipboard token handoff. The iOS 16+ paste prompt on first launch reads as a security warning to your users, so we don't do it.
- ▸No App Clip requirement. It moves iOS match rates, and it costs your team a second build target — that trade is yours to make, not ours.
- ▸No invented certainty. Nothing here reports a match rate that quietly counts guesses as hits.
Firebase Dynamic Links shut down in August 2025.
If you are still carrying its stub, the migration is a link domain, one config plugin entry and a hook. The docs walk the whole path.