Skip to main content
guides

Firebase Dynamic Links Migration Guide

Migrate Firebase Dynamic Links to WarpLink with a tested link inventory, domain cutover, SDK steps for four stacks, and checks for old links and analytics.

WarpLink Team25 min read

To migrate from Firebase Dynamic Links, recreate your links on a domain you control, swap the Firebase Dynamic Links SDK for one that handles taps and deferred installs, and test every path on real devices. Links on Google's page.link domains cannot be saved, so replace them wherever they appear. Links on your own custom domain can keep working.

This guide walks through the full cutover to WarpLink: inventory, field mapping, SDK code for iOS, Android, React Native, and Flutter, old-URL handling, and a test matrix. Every code example shows the Firebase pattern you are removing next to the WarpLink code replacing it.

Google says all Firebase Dynamic Links now return HTTP 404. On October 8, 2026 we requested 32 real page.link short links from 25 domains found in the September 2026 Common Crawl, the way an iPhone does. 25 still redirected, 15 to the app's own website or store and 10 to a Firebase preview page. The other 7 returned an error or no redirect. A redirect only sends the tap to a web destination. Link creation, the console, and SDK updates are gone, and Google can end the redirects at any time. We do not know when, so migrate before they stop. To see which of your own links still redirect, run them through our free Firebase Dynamic Links checker.

DateWhat happenedSource
August 25, 2025Firebase Dynamic Links shut down. Google says links on page.link subdomains and custom domains started returning HTTP 404, and creating new links stopped.Deprecation FAQ
From August 25, 2025The Short Links API and Link Stats API started returning HTTP 400 or 403, gradually at first and then for every request.Deprecation FAQ
After August 25, 2025Google deleted the page.link URL prefix domains. They cannot be kept or transferred, so links on them cannot be redirected. Links on your own custom domain can be.Deprecation FAQ

The FDL SDK depends on a decommissioned service. handleUniversalLink() and its Android, React Native, and Flutter equivalents cannot be relied on to resolve any link, and the SDK gets no fixes for new Xcode, Android, or React Native releases.

Google's own migration guide moves you to plain App Links and Universal Links. By Google's own comparison, that path restores deep links into an installed app but not store routing, deferred deep links, click analytics, or short links. This guide restores all of them, and adds install attribution. If you are still choosing a replacement, compare Firebase Dynamic Links alternatives first.

Decide this before you touch any code. Whether an old URL can keep working depends only on who controls its domain and what its path looks like.

Where the old link livesExampleCan the old URL keep working?What to do
A Google-hosted page.link subdomainyourapp.page.link/aBc1No. Google deleted these domains, and you never controlled their DNS.Recreate the link on your app's subdomain or a custom domain, then replace every copy you can still edit.
Your own subdomain, lowercase one-segment pathslinks.yourapp.com/spring-saleYes, served directly.Point the subdomain at WarpLink and recreate each link with its old path as the slug.
Your own subdomain, mixed-case suffixes or a path prefixlinks.yourapp.com/aBc1, links.yourapp.com/go/saleYes, through a redirect.Keep the domain on a host you run and answer each old path with a 301 to its new WarpLink URL.
Your root domainyourapp.com/aBc1Yes, through a redirect.Add 301 rules for the old paths on your web host. Put new links on a subdomain.

Three product facts drive the table:

  • Slugs are one lowercase segment. A WarpLink slug is 2 to 100 characters of lowercase letters, digits, and non-consecutive hyphens, with no slashes. Firebase's generated suffixes are mixed case, such as aBc1, so they cannot be reused as slugs.
  • Custom domains are subdomains. Setup uses a CNAME record, and DNS does not allow a CNAME at the root of a domain, so WarpLink accepts links.yourapp.com but not yourapp.com.
  • DNS records do not redirect. A DNS record points a hostname at a server. It cannot map an old path to a new URL. A redirect has to come from an HTTP server, CDN rule, or edge function that answers on the old domain.

Every organization can run one custom domain free for 3 months. After that, custom domains are on every paid plan, from 3 domains on Starter.

Firebase Dynamic Links has no working export path. The REST APIs return errors and the console section is gone, so rebuild the list from what you still control:

  • App code. Deep link URLs hardcoded in source, push notification payloads, and App Store or Play Store listings.
  • Marketing materials. Emails, ads, social bios, partner pages, and printed QR codes.
  • Analytics referrers. Any tool that logged traffic from your page.link or custom domain shows which links and campaigns carried traffic.
  • A Google Takeout export. If your team exported Dynamic Link metadata before the shutdown, that CSV holds the short link, destination, platform identifiers, fallbacks, social text, and UTM values for each link.
  • The links themselves. For a link that still redirects, our Firebase Dynamic Links checker shows where it sends visitors, which recovers the destination you need to recreate it.

Record each link in a spreadsheet with these columns: old URL, decision-table row, destination URL, iOS and Android behavior, social preview text, UTM values, where it is published, and recent traffic. The last two columns tell you which links to recreate first and which copies you can still edit.

Step 2: Register Your App and Map Firebase Fields

Create your account and register the app

  1. Create your WarpLink account with email, GitHub, or Google, and create an organization.
  2. Open Apps and register your app. An organization registers an app before it creates links, and one app covers iOS and Android together, including a React Native or Flutter app.
  3. Open Keys and create an SDK key for the app. Mobile apps authenticate with an SDK key. An API key looks identical but cannot record installs, so deep links would work while attribution silently fails.

WarpLink generates and hosts your apple-app-site-association and assetlinks.json files from the app registration and serves them on your link domain. Leave the path patterns empty to claim every path, or list specific paths. Any later change to the app regenerates both files.

Map app-level fields

Firebase set platform details per link. WarpLink sets them once per app.

Firebase sourceWarpLink app field
iOS bundle ID (ibi)iOS bundle identifier
Apple Team ID (Firebase project settings)iOS team ID
iOS App Store ID (isi)iOS App Store URL, written as https://apps.apple.com/app/id followed by the ID
Android package name (apn)Android package name, and the Android Play Store URL, written as https://play.google.com/store/apps/details?id= followed by the package name
SHA-256 certificate fingerprints (Firebase project settings)Android SHA-256 fingerprints

The store URLs are the default fallbacks for every link. A per-link fallback overrides them.

Firebase parameterWarpLink link field
link (deep link)destination_url. The SDK hands it to your app as deepLink.destination.
ifl (iOS fallback link)ios_fallback_url
afl (Android fallback link)android_fallback_url
ofl (desktop fallback link)No separate field. Desktop browsers open destination_url.
st / sd / si (social title, description, image)og_title / og_description / og_image_url
utm_source / utm_medium / utm_campaignutm_source / utm_medium / utm_campaign
efr (forced redirect, skip the preview page)Not needed. WarpLink redirects real users with a 302 and serves preview tags only to bots.

ios_url and android_url have no Firebase counterpart. They hold an optional per-platform deep link URL, such as yourapp://product/123, which the SDK returns as deepLink.deepLinkUrl.

If your app routed on the URL in Firebase's link parameter, set destination_url to the same URL and route on deepLink.destination. Your router keeps working unchanged. The full parameter list is in the Firebase migration reference.

Step 3: Move iOS, Android, React Native, and Flutter Handling

WarpLink's SDKs are at version 1.1.1 on iOS, Android, React Native, and Flutter. Each one takes a single onLink callback in configure(). Cold start, warm start, and deferred installs all arrive there, and deepLink.isDeferred tells a post-install match apart from a direct tap. There is no separate deferred call to port.

Declare your app's subdomain in linkDomains. The SDK decides whether an incoming URL is a WarpLink link the moment it arrives, so a host it has not been told about is handed back to your own router on a fresh install. Find the subdomain in the dashboard under the app's Settings, or see Moving to your app's subdomain.

iOS (Swift)

In Xcode, go to File > Add Package Dependencies, add https://github.com/WarpLinkApp/warplink-ios-sdk, select version 1.1.1 or later, and add the WarpLink library to your app target.

If your app uses a scene delegate, iOS calls the scene instead. Forward the activity there with WarpLink.continue(userActivity) in scene(_:continue:), or set your scene delegate class to WarpLinkSceneDelegate. The iOS SDK guide covers SwiftUI and the cold-start scene methods.

Then update Signing & Capabilities > Associated Domains:

If you serve links from a custom domain, add an applinks: entry for it too, and list it in linkDomains.

Android (Kotlin)

Swap the dependency in your module-level build.gradle.kts:

Cold start needs no Activity code. onNewIntent forwards warm-start links, and android:launchMode="singleTask" makes Android reuse the running Activity instead of starting a second one. Then point the intent filter at your new host:

React Native

The iOS SDK ships through Swift Package Manager and needs dynamic linkage. Add use_frameworks! :linkage => :dynamic inside your app target in ios/Podfile, then run cd ios && pod install.

Android needs no host code beyond android:launchMode="singleTask". On iOS, replace the Firebase line in your existing application(_:continue:restorationHandler:) with WarpLinkModule.handleIncomingURL(url) and keep returning what your linking library returns, so React Navigation and OAuth callbacks keep working. The React Native SDK guide shows the full hook, the Objective-C form, and Expo prebuild.

Flutter

The plugin wraps the native iOS and Android SDKs, so there is no delegate or MainActivity code to write. Set minSdk = 26 in android/app/build.gradle.kts. The iOS SDK ships through Swift Package Manager, so there is no Podfile change. On Flutter 3.38 to 3.43, run flutter config --enable-swift-package-manager once.

Flutter has its own deep link handler, enabled by default. Switch it off so your router does not also receive WarpLink URLs as routes. In ios/Runner/Info.plist:

In android/app/src/main/AndroidManifest.xml, inside <activity>:

Call configure from the initState of your root widget and give MaterialApp a navigatorKey. A cold-start link can arrive before the first frame, when no navigator exists yet, so navigateTo waits for it.

Update the Associated Domains entitlement and the Android intent filter host exactly as in the iOS and Android sections above. The Flutter SDK guide covers both.

Migration is a replacement, not a coexistence. Remove the SDK and every FDL code path as you wire WarpLink in:

  • iOS: remove the FirebaseDynamicLinks package or pod, the handleUniversalLink and dynamicLink(fromCustomSchemeURL:) calls, the old applinks: entry, and the FirebaseDeepLinkPasteboardRetrievalEnabled Info.plist key if you set it.
  • Android: remove firebase-dynamic-links-ktx, the getDynamicLink(intent) calls, and the intent filter for the old host.
  • React Native: remove @react-native-firebase/dynamic-links and its onLink() and getInitialLink() calls.
  • Flutter: remove firebase_dynamic_links and its getInitialLink() and onLink calls.

Keep FirebaseApp.configure() or Firebase.initializeApp() only if the app uses other Firebase services.

Step 4: Move Existing URLs

Create links in the dashboard, or script them from your inventory with the REST API. Use an API key here. The SDK key belongs in the app.

The response holds the short link, on your app's subdomain by default, such as https://yourapp.aplnk.to/spring-sale. Add "domain": "links.yourapp.com" once that custom domain is live. Social crawlers get a full HTML page with Open Graph and Twitter Card tags, and real users get the redirect. The links API reference lists every field.

Serve old URLs from a custom domain you own

For row 2 of the decision table, the old URLs keep working with no redirect hop:

  1. Recreate each link with the same slug, for example spring-sale for links.yourapp.com/spring-sale.
  2. Add the subdomain under Settings > Domains and add the two CNAME records the dashboard shows: one routes traffic, one lets WarpLink issue and renew the HTTPS certificate.
  3. Remove the Dynamic Links rewrite from firebase.json and switch DNS. Most changes apply in 5 to 15 minutes.
  4. Add the domain to Associated Domains, the intent filter, and linkDomains, so a tap opens the app instead of the browser. See custom domains for the full setup.

Redirect old URLs with mixed-case or nested paths

For rows 3 and 4, keep the old domain on a host you run and answer each old path with an HTTP 301 to its new WarpLink URL. Any HTTP server, CDN redirect rule, or edge function works. Build the rule list straight from your inventory spreadsheet, one old path to one new URL.

Universal Links and App Links do not always open the app after a redirect from another domain, so a tap on an old URL can reach the WarpLink link in the browser. WarpLink then sends a phone to the app's store page, which shows Open when the app is installed, and a desktop browser to the destination_url. A user who installs from that store page still gets the deferred deep link. Test old URLs on a device with the app installed.

For row 1, there is no redirect to set up. Replace the old URL wherever you can still edit it: email templates, CMS content, store listings, website buttons, social bios, and push templates. Reprint QR codes that carry a page.link URL. Ship an app update for any page.link URL hardcoded in the app.

Step 5: Verify Installed and First-Install Paths

Test on real devices. Simulators and emulators do not fully support Universal Links and App Links. Run every case on each platform you ship:

CaseHow to testExpected result
Installed, cold startForce-quit the app, then tap a link in Notes or MessagesThe app opens on the linked screen. onLink fires with isDeferred false.
Installed, warm startBackground the app, then tap a linkThe same screen opens in the running app.
Not installedDelete the app, then tap a linkThe per-link fallback opens, or the store URL from the app registration.
First installTap a link, install the app, and open it on the same device and networkOn a match, onLink fires with isDeferred true and the original destination. With no match, onLink does not fire and the app opens on its normal start screen.
DesktopOpen the link in a laptop browserThe destination_url loads.
Social previewPaste the link into Slack or iMessageThe title, description, and image from the og_ fields appear.
AttributionCheck the link's analytics after the first-install testThe install appears on the link.
AnalyticsTap the link a few times from different appsClicks appear on the link in real time.
Old URLOpen an old custom-domain URLIt lands on the same screen as the new link.

iOS checks

  1. Open https://yourapp.aplnk.to/.well-known/apple-app-site-association and confirm your team ID, bundle ID, and paths.
  2. Paste a link into Notes and long-press it. The menu should offer to open it in your app.
  3. If links open Safari, check Settings > Developer > Associated Domains Diagnostics on the device.
  4. To repeat the first-install test, delete the app. The completion marker goes with it, so the next install runs the check again, and it is reported as a reinstall that still counts as an install. To exercise a true first install, use a device that has never run your app.

Android checks

  1. Open https://yourapp.aplnk.to/.well-known/assetlinks.json and confirm your package name and SHA-256 fingerprint.
  2. Simulate a tap:
  1. If Android shows an "Open with" chooser, App Links verification failed. Check that the fingerprint matches the key that signed the installed build, including Play App Signing.

React Native and Flutter checks

Run the iOS and Android checks for each platform, then:

  1. Confirm no error reaches onLink on launch. A rejected SDK key or a configuration problem arrives there as an error, and configure() still completes.
  2. Test a cold-start tap with the app force-quit. The link must reach onLink and navigate before your navigator is ready.
  3. On Flutter, if a tap opens a route you did not define, check that Flutter's own deep linking flag is off in both Info.plist and AndroidManifest.xml.

Common test issues

SymptomLikely causeFix
Link opens in the browser instead of the appAssociation file not verified, or the domain is missing from the entitlement or intent filterCheck both well-known files and the applinks: entry or intent filter host
A fresh install hands the link to your own routerThe link domain is not declared to the SDKAdd the host to linkDomains
First-install match never arrivesAn API key in configure() instead of an SDK keyCreate an SDK key under Keys and use it in the app
First-install match arrives on one test but not anotherThe device changed networks between the tap and the first open, or the open came after the link's match windowRepeat the test on one network and open the app soon after install. On Android, install from Google Play so the install referrer carries the match.
App opens but stays on the home screenYour router does not handle the URL from onLinkLog deepLink.destination and deepLink.deepLinkUrl and add the route
Android shows a disambiguation dialogDigital Asset Links not verifiedMatch the SHA-256 fingerprint to your signing certificate
Firebase Dynamic LinksWarpLinkNotes
Short links (page.link/xyz)Short links (yourapp.aplnk.to/xyz)Custom domains: 1 free for 3 months, then on every paid plan
DynamicLinkComponents and the Short Links APIREST API, dashboard, or MCP serverOne API for every platform
socialMetaTagParametersog_title, og_description, og_image_urlBots get OG and Twitter Card tags automatically
analyticsParameters (UTM)utm_source, utm_medium, utm_campaignReported in WarpLink analytics
handleUniversalLink() / getDynamicLink(intent)onLink callback in configure()One callback for cold start, warm start, and deferred
Deferred deep linksAutomatic deferred check in configure()Arrives in onLink with isDeferred
Link open logging in Google AnalyticsWarpLink click analyticsReal time, with click deduplication
First-open counts per linkInstall attributionReferrer, IDFV, and probabilistic match cascade with a confidence score
Custom domainsCustom domainsSubdomains, with managed HTTPS
apple-app-site-association and assetlinks.jsonGenerated and hostedRegenerated on every app change
No AI accessMCP serverFree on every plan

Frequently Asked Questions

It already has. Google shut down Firebase Dynamic Links on August 25, 2025. Link creation, the console, and the Short Links API are gone, and Google says every link on page.link and on custom domains now returns HTTP 404. Some links still redirect in our tests, but Google can end that at any time.

Google says no. Google says all Firebase Dynamic Links now return HTTP 404. On October 8, 2026 we requested 32 real page.link short links from 25 domains found in the September 2026 Common Crawl, the way an iPhone does. 25 still redirected, 15 to the app's own website or store and 10 to a Firebase preview page. The other 7 returned an error or no redirect. A redirect is not proof that your link still reaches the right screen, so migrate before it stops.

Google points to plain App Links and Universal Links. They open an installed app, but they drop store routing, deferred deep links, click analytics, and short links. To keep those, move to a link provider on a domain you control. WarpLink covers all four, adds install attribution, and starts free at 10,000 clicks a month.

Is Firebase getting deprecated?

No. Only Dynamic Links shut down. The rest of Firebase keeps running, so remove only the Dynamic Links SDK and keep FirebaseApp.configure() if your app uses other Firebase services.

Google says all Firebase short links return HTTP 404 since August 25, 2025, including links on page.link subdomains and custom domains. Some still answer with a redirect today, but they can stop at any time. Links on page.link cannot be saved, because Google deleted those domains. Links on a domain you own can keep working once you recreate them on WarpLink and point the domain at WarpLink or at a redirect.

Can I keep my Firebase custom domain?

Yes, if it is a subdomain you control, such as links.yourapp.com. Add it under Settings > Domains, add the two DNS records the dashboard shows, and recreate each link with its old path as the slug. WarpLink slugs are one lowercase path segment, so mixed-case suffixes, path prefixes, and root domains need an HTTP redirect on your own host instead.

Do I need to update my AASA file manually?

No. WarpLink generates and hosts your apple-app-site-association file automatically based on your app registration. When you register your iOS app with your bundle ID, team ID, and path patterns, WarpLink builds the AASA file and serves it from your link domain. Any changes to your app configuration trigger automatic regeneration.

No. The Firebase Dynamic Links service shut down on August 25, 2025, and the FDL SDK no longer gets fixes, so it is not a base to build on. Remove the Firebase Dynamic Links SDK and any FDL-specific code paths as you wire WarpLink in, since leaving the FDL SDK installed only adds binary size and a failing call path.

What about analytics continuity?

WarpLink analytics start from the moment you create your first link. The Dynamic Links section of the Firebase console is gone, so the only Firebase history left is any link-open events Google Analytics logged and any export you ran before the shutdown. The data models differ, so there is nothing to import. Note your cutover date and report the two periods side by side.

Firebase Dynamic Links recovered a link after install and counted first opens per link, but it did not report how each install was matched. WarpLink attributes each install through a match cascade, the Play Install Referrer on Android, the IDFV on iOS, and a probabilistic device match on both, and returns a match type and confidence with every result. The SDK does not use the IDFA or show an App Tracking Transparency prompt. For the mechanics, see The Complete Guide to Deep Linking.

What if I only need simple URL shortening?

WarpLink handles simple URL shortening too. Register your app, then create a link with just a destination_url and you get a short link with click analytics, social previews, and UTM tracking. Add the deep link fields whenever you need them. The Quickstart walks through it.

Sources

Next Steps

If a step does not behave as described, check the common test issues above or reach us through the dashboard.

Try WarpLink on one real link

Deep linking, install attribution, and real-time analytics in one SDK. Free for 10K clicks a month, no sales call.

Stuck on setup? Email support@warplink.app and we will help you get one real link working.

WarpLink Team

Building affordable, reliable link infrastructure for mobile teams. Deep linking, install attribution, and real-time analytics in one SDK.