Firebase Dynamic Links Migration
A step-by-step guide to migrate from Firebase Dynamic Links to WarpLink, including link mapping, SDK setup, and attribution.
Firebase Dynamic Links shut down on August 25, 2025. Existing FDL short links now return 404. Migrate to restore your deep links.
Concept Mapping
| Firebase Dynamic Links | WarpLink |
|---|---|
| Dynamic Links | Links |
| Firebase console | WarpLink dashboard |
yourapp.page.link domain | aplnk.to domain (or custom domain) |
| Link parameters (social metadata) | Link fields + OG tags |
| Firebase Analytics integration | Built-in click analytics + attribution |
1. Recreate Your Links
Recreate your Firebase Dynamic Links in WarpLink via the dashboard or REST API.
Parameter Mapping
| Firebase Parameter | WarpLink Field |
|---|---|
link (deep link URL) | destination_url |
isi / apn (app identifiers) | Configured per-app in dashboard |
ifl / afl (fallback links) | ios_fallback_url / android_fallback_url |
efr (skip preview page) | N/A (WarpLink uses 302 redirects by default) |
st / sd / si (social metadata) | og_title / og_description / og_image_url |
| Custom parameters | custom_params JSON object |
Create via API
curl -X POST https://api.warplink.app/v1/links \
-H "Authorization: Bearer wl_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"destination_url": "https://yourapp.com/product/123",
"ios_url": "myapp://product/123",
"android_url": "myapp://product/123",
"custom_params": { "referrer": "campaign_spring" }
}'
2. Swap the SDK
Remove Firebase:
- Remove
FirebaseCoreandFirebaseDynamicLinkspackages from Xcode - Remove
FirebaseApp.configure()(unless you use other Firebase services) - Remove
import FirebaseCoreandimport FirebaseDynamicLinks
Add WarpLink:
// Package.swift
dependencies: [
.package(url: "https://github.com/WarpLinkApp/warplink-ios-sdk", from: "1.1.0")
]Remove Firebase:
// Remove from build.gradle.kts
// implementation(platform("com.google.firebase:firebase-bom:33.0.0"))
// implementation("com.google.firebase:firebase-dynamic-links")Add WarpLink:
dependencies {
implementation("app.warplink:sdk:1.1.0")
}Remove Firebase:
npm uninstall @react-native-firebase/dynamic-links
# If no other Firebase packages:
npm uninstall @react-native-firebase/app
cd ios && pod installAdd WarpLink:
npm install @warplink/react-native
cd ios && pod install3. Update SDK Initialization
Mobile apps authenticate with an SDK key, created in the dashboard under API Keys > SDK key. An API key looks identical but cannot record installs, so pasting one here leaves deep links working while attribution silently fails.
Before (Firebase):
import FirebaseCore
FirebaseApp.configure()After (WarpLink):
import WarpLink
WarpLink.configure(
apiKey: "wl_live_yoursdkkeyhere000000000000000000",
options: WarpLinkOptions(onLink: { result in
if case .success(let link) = result, let link {
navigate(to: link) // taps AND deferred installs (check link.isDeferred)
}
})
)Before (Firebase):
// Firebase auto-initializes via FirebaseApp — no explicit callAfter (WarpLink):
import app.warplink.WarpLink
import app.warplink.WarpLinkOptions
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
WarpLink.configure(
context = this,
apiKey = "wl_live_yoursdkkeyhere000000000000000000",
options = WarpLinkOptions(onLink = { result ->
result.onSuccess { link -> navigateTo(link) }
})
)
}
}Before (Firebase):
// Firebase auto-initializes via @react-native-firebase/appAfter (WarpLink):
import { WarpLink } from '@warplink/react-native';
WarpLink.configure({
apiKey: 'wl_live_yoursdkkeyhere000000000000000000',
onLink: ({ deepLink }) => deepLink && navigateTo(deepLink.destination),
});4. Update Domain Configuration
In Signing & Capabilities > Associated Domains:
- applinks:yourapp.page.link
+ applinks:aplnk.toIn AndroidManifest.xml, update the intent filter host:
<data
android:scheme="https"
- android:host="yourapp.page.link" />
+ android:host="aplnk.to" />Moving your links to a custom domain instead? Use that host here, and declare it to the SDK as well: linkDomains at configure(), or the WarpLinkDomains plist key / app.warplink.DOMAINS manifest entry. That is what makes a custom-domain link resolve on the first launch. See Use it in your app.
5. Migrate Deep Link Handling
The onLink callback you set in step 3 already receives resolved links for cold start, warm start, and deferred installs. Firebase's manual handleUniversalLink / getDynamicLink / getInitialLink calls have no equivalent to port: delete them. All that remains is a minimal host hook so the OS hands URLs to the SDK.
Delete the DynamicLinks.dynamicLinks().handleUniversalLink(...) block. Forward the incoming activity to WarpLink (or set your scene delegate class to WarpLinkSceneDelegate):
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
WarpLink.continue(userActivity)
}Resolved links arrive in your onLink callback.
Delete the FirebaseDynamicLinks.getInstance().getDynamicLink(intent) block. Cold start is automatic. For warm start, forward new intents and set android:launchMode="singleTask" on the Activity:
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
WarpLink.onNewIntent(intent)
}Resolved links arrive in your onLink callback.
Delete the dynamicLinks().getInitialLink() and dynamicLinks().onLink(...) calls. Cold and warm start flow into onLink automatically.
On iOS you are removing the Firebase call from a delegate method that already exists and already forwards to your linking library. Swap the Firebase line for the WarpLink call and leave the rest of the method alone. Do not let handleIncomingURL decide the return value: it returns nothing, and replacing the forwarded result breaks React Navigation, Expo Linking, and OAuth callbacks.
// ios/YourApp/AppDelegate.swift
import React
import warplink_react_native
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL {
WarpLinkModule.handleIncomingURL(url) // was DynamicLinks...handleUniversalLink
}
return RCTLinkingManager.application(
application, continue: userActivity, restorationHandler: restorationHandler)
}Android needs no host code, given android:launchMode="singleTask". See the React Native SDK guide for the Objective-C form and Expo prebuild.
6. Migrate Deferred Deep Links
WarpLink runs the deferred deep link check automatically from configure(). The match arrives in the same onLink callback, flagged with isDeferred. There is no separate deferred call to port from Firebase.
Handle the deferred case inside your onLink callback:
options: WarpLinkOptions(onLink: { result in
guard case .success(let deepLink) = result, let deepLink else { return }
if deepLink.isDeferred {
print("Match confidence: \(deepLink.matchConfidence ?? 0)")
}
navigate(to: deepLink)
})Handle the deferred case inside your onLink callback:
options = WarpLinkOptions(onLink = { result ->
result.onSuccess { deepLink ->
if (deepLink.isDeferred) {
Log.d("MyApp", "Match confidence: ${deepLink.matchConfidence}")
}
navigateTo(deepLink)
}
})Handle the deferred case inside your onLink callback:
WarpLink.configure({
apiKey: 'wl_live_yoursdkkeyhere000000000000000000',
onLink: ({ deepLink }) => {
if (!deepLink) return;
if (deepLink.isDeferred) console.log('Match confidence:', deepLink.matchConfidence);
navigateTo(deepLink.destination);
},
});To run the check manually instead, set the deferred opt-out flag and call checkDeferredDeepLink() yourself (see the deferred deep links guides).
What's New with WarpLink Deferred Links
| Feature | Firebase | WarpLink |
|---|---|---|
| Deferred detection | No isDeferred flag | link.isDeferred === true |
| Attribution data | None | matchType, matchConfidence |
| Match confidence | Not available | 0.0–1.0 score |
| Caching | Manual | Automatic (once per install) |
| Matching method | Play Install Referrer only | Referrer + IDFV + fingerprint |
7. API Migration
| Firebase REST API | WarpLink REST API |
|---|---|
POST https://firebasedynamiclinks.googleapis.com/v1/shortLinks | POST https://api.warplink.app/v1/links |
| API key as query parameter | Bearer token in Authorization header |
dynamicLinkInfo object | Flat JSON body |
Feature Comparison
| Feature | Firebase Dynamic Links | WarpLink |
|---|---|---|
| Short links | Yes | Yes |
| Deferred deep links | Yes (limited) | Yes (with confidence scores) |
| Install attribution | No | Yes (deterministic + probabilistic) |
| Custom domains | Yes | Yes |
| Social previews | Built-in | Built-in (bot detection + OG tags) |
| Open source SDK | No | Yes (MIT license) |
| Pricing | Free (deprecated) | Free tier (10K clicks/mo) |
Testing Checklist
After migration, verify on each platform:
- SDK initializes: enable debug logging and check console output
- Deep links open the app: tap a WarpLink URL on a physical device
- Deep link data resolves: destination and custom parameters are correct
- Deferred deep links work: click link, install, verify match. An uninstall is enough to retest on either platform, because the completion marker goes with the app. That second install is reported as a reinstall and still counts as an install
- AASA/assetlinks verified:
curl https://aplnk.to/.well-known/apple-app-site-association - Error handling: test invalid URLs, expired links, no connectivity
- All Firebase code removed: no remaining imports or dependencies
- Clean build: no compilation errors
Next Steps
- Quickstart: create your first link and get an SDK key.
- iOS SDK, Android SDK, and React Native SDK: full setup and API reference.
- Deferred deep links: how WarpLink matches an install back to the original link.
- Step-by-step migration walkthrough: the long-form guide with full before-and-after code for each platform.