Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Installed-app deep links and deferred install recovery are separate problems. React Navigation can map a URL the app receives to a screen, and Universal Links on iOS and App Links on Android can route verified HTTPS URLs into an app that is already installed. Neither one carries a destination through an App Store or Google Play install. If a link clicked before installation has to open the right screen on first launch, you need a deliberate handoff that is read after installation. This guide builds the routing layers first and then adds that handoff.

Installed-app routing and deferred recovery are separate problems

Installed-app routing covers a URL delivered to an app that is already on the device: a tap on a verified link, a cold start from a link, or a link received while the app is running. Deferred recovery covers a click that happened before the app existed on the device. The two share vocabulary, which is why teams often assume that making one work makes the other work.

Apple’s developer documentation describes the not-installed case this way: “If the person hasn’t installed your app, the system opens the URL in their default web browser, allowing your website to handle it.” That sentence describes a fallback to your website. It does not describe a stored destination that the app reads after installation. React Navigation’s linking guide likewise covers initial and runtime URL handling, and points to deferred deep linking as a separate topic for the not-installed case.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build the solution in four layers, and add the fourth only if your product needs it:

  1. Domain and app association. The website and the app claim each other, so the operating system routes matching HTTPS URLs to the app.
  2. Delivery into the React Native process. The app receives the URL at cold start or while running, through the Linking API.
  3. Mapping to navigation. A validated path and its parameters become React Navigation state.
  4. Deferred install handoff. A destination saved before installation is read back on first launch. This layer is needed only for pre-install clicks.

Layer 1: Associate your domain with the app

iOS: Associated Domains and the association file

  1. In Xcode, select the app target, open the Signing & Capabilities tab, click + Capability, and add Associated Domains.
  2. Add an entry such as applinks:www.example.com.
  3. Host a JSON file at https://www.example.com/.well-known/apple-app-site-association and serve it over HTTPS without redirects.

The association file names the app by Team ID and bundle identifier and lists the paths it claims. This example uses the components format with sample values:

{
  "applinks": {
    "details": [
      {
        "appIDs": ["ABCDE12345.com.example.shop"],
        "components": [
          { "/": "/product/*", "comment": "Product pages" },
          { "/": "/orders/*", "comment": "Order status" }
        ]
      }
    ]
  }
}

Expo-managed projects declare the same entries in app config, under ios.associatedDomains and android.intentFilters, and the hosted files are the same either way. Changes to the association file may not take effect on a device immediately, so test with a freshly installed build.

Android: App Links with Digital Asset Links

Android Developers’ App Links guide describes the capability this way: “Android App Links is a special deep linking capability in Android 6 and later that allows your verified website URLs to immediately open corresponding content in your Android app, without requiring the user to select your app from a disambiguation dialog.” Two pieces make it work. The first is the manifest, which declares the URLs the app handles. The android:autoVerify="true" attribute requests verification. Add one data element for each path family you claim:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<activity android:name=".MainActivity" android:launchMode="singleTask" ...>n  <intent-filter android:autoVerify="true">n    <action android:name="android.intent.action.VIEW" />n    <category android:name="android.intent.category.DEFAULT" />n    <category android:name="android.intent.category.BROWSABLE" />n    <data android:scheme="https" android:host="www.example.com" android:pathPrefix="/product" />n    <data android:scheme="https" android:host="www.example.com" android:pathPrefix="/orders" />n  </intent-filter>n</activity>

The second piece is a Digital Asset Links file hosted on the website at https://www.example.com/.well-known/assetlinks.json. It ties the domain to the app’s package name and release signing certificate:

[n  {n    "relation": ["delegate_permission/common.handle_all_urls"],n    "target": {n      "namespace": "android_app",n      "package_name": "com.example.shop",n      "sha256_cert_fingerprints": ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]n    }n  }n]

The fingerprint above is a sample value; use the SHA-256 fingerprint of your own release signing certificate. Check the result on a device with adb shell pm get-app-links com.example.shop, which reports the verification state of each host (available on Android 12 and later). After you correct the hosted file, re-run verification with adb shell pm verify-app-links --re-verify com.example.shop.

Android Developers also describes Dynamic App Links, which add on-device behavior refinement from Android 15 on devices with Google services. That refines how verified links behave on a device. It does not decide whether a link clicked before installation reaches the app after installation.

Layer 2: Receive the URL in the React Native process

The React Native Linking API is the delivery point on both platforms. Its documentation notes that Android commonly calls these links deep links, while iOS calls them Universal Links. Use standard HTTPS URLs for any link meant to work outside the app. A custom scheme such as shop:// still opens the app, but it does not provide the same web fallback.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Cold start

When a link launches a closed app, Linking.getInitialURL() returns that URL, or null if the app was opened another way. If you pass a linking prop to React Navigation’s NavigationContainer, as in the next section, React Navigation calls this for you and renders the fallback element while it resolves.

App already running

Links that arrive while the app is open are delivered as events. Use this listener only if you are not passing a linking prop; with that prop, React Navigation subscribes for you.

useEffect(() => {n  const subscription = Linking.addEventListener('url', ({ url }) => {n    handleIncomingUrl(url);n  });n  return () => subscription.remove();n}, []);

React Native documents launchMode="singleTask" on MainActivity for the case where an incoming intent must reach an existing activity. Without it, Android can create a second instance of the activity when a link arrives while the app is open. The manifest in Layer 1 already sets it.

Layer 3: Map validated paths to screens

React Navigation turns a URL into navigation state through a config that lists the paths it accepts. Any path not listed is not mapped, so the config also works as your route allowlist.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const linking = {n  prefixes: ['https://www.example.com', 'shop://'],n  config: {n    screens: {n      Home: '',n      Product: 'product/:id',n      Orders: 'orders/:orderId',n    },n  },n};nnexport default function App() {n  return (n    <NavigationContainer linking={linking} fallback={<SplashScreen />}>n      <RootStack />n    </NavigationContainer>n  );n}

Route parameters arrive as strings, and they remain untrusted input. Validate them inside the screen before use:

const PRODUCT_ID = /^[A-Za-z0-9_-]{1,64}$/;nnfunction ProductScreen({ route, navigation }) {n  const id = route.params?.id;n  const valid = typeof id === 'string' && PRODUCT_ID.test(id);nn  useEffect(() => {n    if (!valid) navigation.replace('Home');n  }, [valid, navigation]);nn  if (!valid) return null;n  return <ProductDetail id={id} />;n}

Put authentication checks in the navigator or the screen, not in the URL parser. If an Orders link arrives while the user is signed out, redirect to sign-in and keep the intended destination in app state rather than in the URL.

Layer 4: Hand off the destination across installation

Deferred recovery needs a value that exists before installation and is still readable after the first launch. Platform routing cannot supply that by itself, because the link that started the process was consumed by the browser or the store. Choose one of the following handoffs deliberately:

Approach What carries the destination Platforms Trade-offs
Managed deferred-link service A service-issued link plus an SDK call on first launch Set by each provider; verify iOS and Android separately Vendor dependency; pricing, data handling and partner terms need review
Google Play install referrer A URL-encoded referrer parameter on the Play Store link, read by the app after install Android only Works only for installs that start from a Play Store link
Your own backend with install matching A server record matched to the new install Both platforms, with probabilistic matching Matches can be wrong; you take on the privacy and consent obligations
No handoff Nothing Both platforms First launch opens the default screen and the original destination is lost

Android: the Play install referrer

Google Play’s Install Referrer API is documented by Google Play rather than by the App Links pages cited above. When the Play Store link carries a referrer parameter, for example https://play.google.com/store/apps/details?id=com.example.shop&referrer=product%3D42, the app can read that string on first launch through Google’s Install Referrer library. The referrer is only the carrier. Map it to a route through the same allowlist from Layer 3 and reject anything that fails validation.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iOS: no store referrer in the Universal Links model

The Universal Links behavior covered above does not carry a destination through an App Store install. On iOS, deferred recovery therefore depends on a managed provider or on your own matching, and both carry the privacy trade-offs listed in the table.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Test each path separately

Use a signed build on your release domain for the Universal Link and App Link tests, because the association files must match the signing identity. Run each scenario and record the result.

Scenario How to reproduce Expected result
Installed, terminated (cold start) iOS simulator: xcrun simctl openurl booted "https://www.example.com/product/42". Android: adb shell am force-stop com.example.shop, then adb shell am start -a android.intent.action.VIEW -d "https://www.example.com/product/42" The app opens the Product screen; getInitialURL() returns the URL
Installed, already open Send the same command while the app is in the foreground The Product screen opens through the URL event; Android does not create a second activity instance
App absent Uninstall the app and open the same HTTPS URL from a browser or message The website loads, as Apple’s documentation describes for the not-installed case
Malformed or unknown path Open https://www.example.com/admin and https://www.example.com/product/%00 No crash; the app goes to Home or a not-found screen and shows no product data
Deferred handoff (only if implemented) Click the link while the app is absent, install, then launch for the first time The stored destination resolves once, expires after your chosen window, and falls back to Home when missing

Common failures and their causes:

  • A chooser appears on Android instead of the app opening directly. Verification has not succeeded. Recheck the assetlinks.json file for HTTPS, the package name and the certificate fingerprint, then run pm get-app-links.
  • A universal link stays in Safari on iOS. Safari can keep a same-domain link in the browser. Test from Notes or Messages, or long-press the link and choose the option to open it in the app.
  • The app opens but shows a blank screen. The prefixes entry does not match the host or scheme, so React Navigation maps nothing.
  • Cold start works but a running app ignores links. A manual Linking listener is either missing or duplicated alongside the linking prop.

Migrating links away from Firebase Dynamic Links

Firebase’s Dynamic Links deprecation FAQ states: “On August 25th, 2025, Firebase Dynamic Links will shut down.” The FAQ also says that all served links, including custom domains and page.link links, stop working and cannot be newly created. Page.link domains are not available after shutdown, so they cannot be moved into your project. Any Firebase link still in circulation is now a migration task.

  1. Inventory every place a Firebase link lives: email templates, paid campaigns, QR codes, printed material, support articles and push payloads. Search the React Native code for Dynamic Links calls and their handlers.
  2. Choose a domain you control, host the association files from Layer 1 on it, and map each old link’s intent to a route in your Layer 3 config.
  3. Replace links in active channels first. Because the hosted service no longer serves old links, you cannot add a redirect through Firebase, so printed or shared copies that still point at Firebase will fail and must be reissued on your domain.
  4. Remove the Firebase SDK and its handlers, and route all incoming URLs through Linking and React Navigation.
  5. Keep a web page on your domain for each campaign destination so that visitors without the app still reach the content.

Security rules for inbound links

A deep link is a request to navigate, not proof that the user may see the target. Apply these rules to every inbound URL:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Treat every path, query parameter and route parameter as untrusted input. Parse them against your route allowlist and reject unknown keys.
  • Validate identifiers against a strict pattern and a length limit, as in the Product example above.
  • Do not trigger destructive or money-moving actions directly from a link. Open a confirmation screen instead.
  • Run authentication and authorization after navigation, not as a side effect of the URL.
  • Keep session tokens, password-reset tokens and personal data out of query strings, because URLs are recorded by servers, browsers and analytics tools.
  • Use HTTPS links for sensitive routes. A custom scheme can be claimed by more than one app on the device.
  • Apple’s guidance on incoming links warns developers to validate malformed URLs and to avoid exposing sensitive information or triggering risky actions from a link.

Choosing a managed deferred-link provider

Apple’s, Android’s, React Native’s and React Navigation’s documentation covers installed-app routing. None of those official sources compares the post-Firebase deferred-linking providers on deferred recovery per platform, pricing or data practices, so a vendor decision has to be checked against each vendor’s current documentation. Use this checklist:

  • Deferred install recovery demonstrated on each target platform. iOS and Android can behave differently.
  • React Native and Expo or native SDK support for your versions, with current documentation.
  • Domain ownership: whether links run on your own domain, and a documented path for moving off the provider.
  • Control over browser and store fallback behavior.
  • Analytics and attribution needs, and whether they require data you are not otherwise collecting.
  • Reliability, privacy and data handling terms.
  • Price, usage limits and current partner terms.

Older React Navigation documentation named Branch as an example of an external incoming-link service. That reference shows the category of tool, not current support for deferred recovery on your platforms.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.