Glossary/Failure modes
Migrating off Firebase Dynamic Links
Definition
Migrating off Firebase Dynamic Links means replacing the link generation, the hosting domain, and the SDK integration of a service that was shut down on 25 August 2025, after which page.link URLs stopped resolving.
The single question that determines how much work this is, and how much is even possible, is whether you used a *.page.link subdomain or your own custom domain. Custom domain users keep every link they ever published. page.link users do not, and no vendor can change that, because the domain belongs to Google. Establish which you are before planning anything else.
What is recoverable and what is not
| What you had | Status now | Recoverable? |
|---|---|---|
https://yourapp.page.link/abc | Dead. Does not resolve | No. Google owns page.link; you cannot redirect it |
https://goo.gl/… short links | Dead | No |
https://links.yourdomain.com/abc (custom domain) | Dead only because nothing serves it | Yes. Point the DNS at a replacement and honour the same paths |
| Links stored in your own database | The destinations are intact | Yes — regenerate against the new service |
| Analytics history in Firebase | Read-only or gone | Export what remains; it will not carry over |
If you used page.link, the links in the wild are gone
Every page.link URL already printed on packaging, embedded in a QR code, pasted into a forum, sent in a past email, or saved in a user's bookmarks is permanently dead. This is not a limitation of any replacement product — the domain is Google's, and nobody else can answer requests for it. Plan for the loss rather than for a migration that recovers it.
For custom domain users the migration is genuinely tractable: your links were always on a host you control, so the DNS points somewhere new, the new service resolves the same paths, and published URLs keep working. That difference is worth stating to anyone who is still choosing a link vendor — a branded domain is what makes any future migration survivable.
The parameter mapping
FDL long-form links encode everything in query parameters, which makes them straightforward to parse and translate. If you generated links in code, this table is most of your migration.
https://yourapp.page.link/?
link=https%3A%2F%2Fexample.com%2Fproducts%2F42 # the actual destination
&apn=com.example.shop # Android package name
&ibi=com.example.shop # iOS bundle ID
&isi=123456789 # iOS App Store ID
&afl=https%3A%2F%2Fexample.com%2Fandroid # Android web fallback
&ifl=https%3A%2F%2Fexample.com%2Fios # iOS web fallback
&st=Product+42 # social title
&sd=A+description # social description
&si=https%3A%2F%2Fexample.com%2Fog.png # social image
&utm_source=newsletter&utm_campaign=spring # campaign tags
&efr=1 # skip the preview page| FDL parameter | Meaning | Replacement concept |
|---|---|---|
link | Destination URL | The link's destination or deep link path |
apn | Android package name | App configuration, set once — not per link |
ibi / isi | iOS bundle ID and App Store ID | App configuration, set once |
afl / ifl | Per-platform web fallback | Platform fallback rules |
ofl | Fallback for other platforms (desktop) | Desktop fallback URL |
st / sd / si | Social preview title, description, image | Open Graph metadata on the link |
utm_* | Campaign tags | Campaign parameters, carried to the app |
efr=1 | Skip the app preview interstitial | Interstitial behaviour setting |
amv | Minimum Android version | Minimum version rules |
d=1 | Debug the link's resolution | A debugger instead |
Note the shape change in rows 2 and 3. FDL put app identity in every link; most replacements set it once at the account level, so generated links get shorter and the App Store ID stops being copy-pasted into thousands of URLs.
The migration, in order
- Inventory where links actually live. Not just the app: transactional and marketing email templates, push payloads, ad creative and tracking templates, QR codes in print and packaging, help centre articles, social profiles, partner integrations, and any backend that generates links at runtime. The backend is usually the one that gets missed and the one that matters most.
- Decide the domain, and make it yours. If you had a custom FDL domain, keep it — that is what makes published links survive. If you were on
page.link, choose a branded subdomain now, so that this migration is the last one that loses links. - Stand up the association files on that host. apple-app-site-association and assetlinks.json, served with no redirects and the right content type, plus the Associated Domains entitlement and the Android intent filter for the new host.
- Recreate the link structure, paths included. For a custom domain, honouring the original paths is what keeps every published URL alive. This is the step that determines whether the migration is invisible to users.
- Swap the SDK. Replace FDL link handling with the new SDK's, and keep the old handler in place through at least one release so users on older builds are not stranded.
- Re-point the DNS. Custom domain only, and the moment the links come back.
- Re-test the paths that were never obvious. Email campaigns with click tracking, links inside social apps, QR codes, deferred routing on a fresh device. These are the ones that FDL handled quietly and that break silently on a replacement.
# Links hard-coded in the codebase
grep -rIn --exclude-dir=node_modules \
-e 'page\.link' -e 'goo\.gl' -e 'firebasedynamiclinks' \
-e 'FirebaseDynamicLinks' -e 'dynamicLinks' .
# The SDK, still in your dependency manifests
grep -rn "firebase-dynamic-links\|FirebaseDynamicLinks" \
app/build.gradle Podfile pubspec.yaml package.json 2>/dev/null
# Links in a database column
# SELECT id, url FROM links WHERE url LIKE '%page.link%';
# Whether your custom FDL domain still resolves anywhere
dig +short links.example.com
curl -sSI --max-redirs 0 https://links.example.com/abc123Keep the old SDK handler for one release
Users on an older build still have the FDL handler and no other. Removing it in the same release that adds the replacement strands anyone who has not updated. Ship both, then remove the old one a release later once your version adoption supports it.
FDL migration checker
Paste a Firebase Dynamic Link and it decodes every parameter — destination, per-platform fallbacks, social metadata, campaign tags — and shows the equivalent configuration. It also tells you whether your links were on page.link or a custom domain, which is the fact that decides how much of your link estate is recoverable.
Frequently asked questions
- When did Firebase Dynamic Links shut down?
- 25 August 2025. Since then page.link URLs no longer resolve and new ones cannot be created. Any FDL link still embedded in emails, push notifications, ads, QR codes, printed material, or backend code stopped working on that date, along with the associated goo.gl short links.
- Can I recover my page.link URLs after the shutdown?
- No. The page.link domain belongs to Google, so no replacement service can answer requests for it or redirect it to a new destination. Every page.link URL published in the wild is permanently dead. If you used a custom domain with Firebase Dynamic Links instead, those links are fully recoverable by pointing the DNS at a replacement that honours the same paths.
- How do I migrate Firebase Dynamic Links to another service?
- Inventory everywhere links are generated or stored, including backend code and email templates. Choose a branded domain — keeping your existing custom FDL domain if you had one, since that preserves published links. Host apple-app-site-association and assetlinks.json on it, recreate the link structure with the same paths, swap the SDK while keeping the old handler for one release, then re-point the DNS.
- What replaces the apn, ibi, and isi parameters from FDL?
- Nothing per link. Firebase Dynamic Links required the Android package name, iOS bundle ID, and App Store ID on every URL, whereas most replacements set app identity once at the account level. The practical effect is much shorter generated links and no App Store IDs copy-pasted through thousands of URLs.
- Why should I use a custom domain instead of a provider subdomain?
- Because it is what makes any future migration survivable. Links on a provider's domain belong to the provider, so if that service shuts down — as Firebase Dynamic Links did — every published URL dies with no possible recovery. Links on a domain you own can be re-pointed to a different service while every URL already in the wild keeps working.
- Do I need to keep the Firebase Dynamic Links SDK during migration?
- Keep the old handler in place for at least one release. Users running an older build have only the FDL handler, so removing it in the same release that adds the replacement strands anyone who has not updated. Ship both handlers, then drop the old one a release later once version adoption is high enough.
Related terms
- Apple App Site Association (AASA) — The apple-app-site-association file is a JSON document hosted at a domain's /.well-known/ path that tells iOS which app is allowed to handle which URLs on that domain.
- assetlinks.json — assetlinks.json is a Digital Asset Links statement file hosted at a domain's /.well-known/ path that authorises a named Android app, identified by package name and signing certificate fingerprint, to handle that domain's URLs.
- Unattributed installs — An install is unattributed when no signal linking it to a prior ad click or link tap survived the journey through the app store, which can mean the install was organic or that the signal existed and was lost.