Originally published on AppRanker.
Picking a Firebase Dynamic Links alternative usually starts with a bug report: an invite link, a QR code on a flyer or a password-reset email that now lands on a 404. Google switched the service off on August 25, 2025, and every page.link URL has returned 404 ever since. Here is how to rebuild what it did with native, mostly free pieces, including the config and code for each.
Split the problem into three jobs
Dynamic Links bundled three features behind one URL. You rarely need to replace all three, so start by naming the ones your app actually relied on:
- Routing: open the app on the right screen when it is installed, otherwise send people to a store or a web page.
- Deferred deep linking: carry the link's context (an invite code, a product ID) through the install so the app can read it on first launch.
- Short links and analytics: compact URLs, click counts and campaign parameters.
Google's own FAQ suggests the same split. If you only need deep linking after install, Google recommends the native options, Universal Links and App Links. If you want everything Dynamic Links offered, it names Adjust, Branch and AppsFlyer, with the caveat that it has not vetted them.
Before writing code, audit where old links still live. In-app share text and referral flows are the obvious ones. Printed QR codes, old newsletters, social posts and store descriptions are easy to forget. So is Firebase Authentication: password resets, email verification and passwordless email-link sign-in only keep working after you move to the latest Auth SDKs. Anything already printed or sent on page.link cannot be redirected, which is the best argument for hosting links on a domain you own from now on.
Routing: Universal Links and App Links
Both platforms check a file on your domain before letting your app claim a link. Pick a host you control (for example links.example.com) and serve two files over HTTPS with no redirects.
On iOS, /.well-known/apple-app-site-association has no file extension:
{ "applinks": { "details": [{ "appIDs": ["ABCDE12345.com.example.app"], "components": [ { "/": "/invite/*" }, { "/": "/p/*" }, { "/": "/help/*", "exclude": true } ] }] } } Add the Associated Domains capability with applinks:links.example.com, then route incoming URLs in one place, such as SwiftUI's .onOpenURL. A testing gotcha: since iOS 14, devices fetch this file from Apple's CDN, not from your server. The CDN picks up your file within 24 hours and devices recheck roughly weekly, so append ?mode=developer to the entitlement while you iterate.
On Android, /.well-known/assetlinks.json lists your package and certificate fingerprint:
[{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.example.app", "sha256_cert_fingerprints": ["14:6D:E9:83:..."] } }] If you use Play App Signing, use the fingerprint of Google's app signing key, not your upload key. That one mismatch breaks verification silently. Declare an https intent filter with android:autoVerify="true" for the same host. Devices on Android 15+ also support Dynamic App Links, which let you adjust routing rules server-side through dynamic_app_link_components, but those rules can only narrow what the manifest declares, so put the broadest host in the manifest.
When the app is missing, the same URL opens your web page. Make that page useful: show what was shared, add store badges, and include a Smart App Banner for iOS visitors whose app-argument passes the URL to the app after download:
<meta name="apple-itunes-app" content="app-id=123456789, app-argument=https://links.example.com/invite/ABC123"> Deferred deep links without a vendor
Android has a built-in answer. Put the context in the Play Store URL's referrer parameter (URL-encoded), for example &referrer=utm_source%3Dinvite%26utm_content%3DABC123, and fetch it when the app first opens using the Install Referrer library from Play (com.android.installreferrer:installreferrer:2.2):
val client = InstallReferrerClient.newBuilder(context).build() client.startConnection(object : InstallReferrerStateListener { override fun onInstallReferrerSetupFinished(code: Int) { if (code == InstallReferrerClient.InstallReferrerResponse.OK) { handleReferrer(client.installReferrer.installReferrer) } client.endConnection() } override fun onInstallReferrerServiceDisconnected() { /* retry */ } }) The response also includes click and install timestamps, which help you ignore stale referrers.
iOS has no install referrer. App Store campaign links count installs per campaign in App Store Connect, but the app never sees the campaign. Practical workarounds:
- display an invite code on the landing page and have onboarding prompt for it;
- copy the link on the web page and offer a
UIPasteControlbutton, which reads the pasteboard without the system paste prompt because the user tapped it; - attach the invite to the account server-side and restore it after sign-in;
- start the flow in an App Clip if it is short enough.
Do not match clicks to installs with IP address, device model or screen size. Apple's privacy rules forbid deriving data to uniquely identify a device, and apps whose SDKs fingerprint may be rejected.
Which replacement fits
| Need | Replacement | Cost |
|---|---|---|
| Deep link into an installed app | Universal Links + App Links | Free |
| Keep context through install (Android) | Play Install Referrer | Free |
| Keep context through install (iOS) | Typed code, UIPasteControl, sign-in or App Clip | Free |
| Installs per campaign | App Store campaign links + Play UTM referrer | Free |
| All of it in one SDK with a dashboard | Deep linking vendor | Paid |
Most indie apps only need the first four rows. If you do evaluate a vendor, ask how they match installs on iOS (anything based on IP or device traits is fingerprinting), whether links can live on your own domain, whether you can export links and data, and what happens to live links if you stop paying.
Key takeaways
- Dynamic Links did three jobs; replace routing, deferred linking and analytics separately.
- Universal Links and App Links handle routing for free on a domain you own.
- Use the Play App Signing key fingerprint in
assetlinks.json, not the upload key. - The Play Install Referrer API gives Android deferred deep links with no SDK vendor.
- On iOS, carry context with an invite code, UIPasteControl, account state or an App Clip, never fingerprinting.
- Host all links on a domain you control; then a future shutdown means updating a redirect, not reprinting QR codes.
The original article includes a step-by-step migration plan and a full checklist: replacing Firebase Dynamic Links with Universal Links, App Links and Install Referrer. For more practical guides on getting iOS and Android apps found, browse the AppRanker app discovery leaderboard and blog.
What did you replace Dynamic Links with, and how are you handling deferred deep links on iOS without fingerprinting?
