Back to Blog
Debugging
12 min read
March 7, 2026

Debugging Deep Links in Flutter: Complete Troubleshooting Guide

Deep links are critical for user experience, but they're notoriously difficult to debug when things go wrong. This comprehensive guide walks you through systematically diagnosing and fixing deep linking issues in Flutter apps.

Why Deep Links Break

Deep links often fail silently, meaning your app receives no error messages when a link doesn't work. The user just gets sent to the home screen instead of the intended deep-linked screen. This happens because deep linking involves multiple systems:

  • iOS: Apple's AASA (Apple App Site Association) file, Xcode entitlements, and Safari handling
  • Android: assetlinks.json file, intent filters, and app signing certificates
  • Your App: Proper route handling and link parsing in your Flutter code

When any part of this chain breaks, the entire deep link fails. Let's walk through how to systematically debug each component.

#1Universal Links Not Working (iOS)

iOS Requires HTTPS

Universal Links only work with HTTPS domains. HTTP will not work, even during testing.

Step 1: Validate Your AASA File

The Apple App Site Association (AASA) file is the foundation of iOS Universal Links. Use our validator to ensure it's correctly formatted:

Step 2: Check Associated Domains in Xcode

Your Xcode project must have the Associated Domains entitlement configured:

xml
<key>com.apple.developer.associated-domains</key>
<array>
    <string>applinks:example.com</string>
    <string>applinks:www.example.com</string>
</array>

To do this in Xcode: Select your target → Signing & Capabilities → Add Capability → Associated Domains → Add your domain with the applinks: prefix.

Step 3: Verify AASA File Hosting

Your AASA file must be hosted at exactly: https://example.com/.well-known/apple-app-site-association

bash
# Test if your AASA file is accessible (replace example.com)
curl -v https://example.com/.well-known/apple-app-site-association

Check the response headers. The Content-Type must be:

text
Content-Type: application/json

Step 4: Test on a Real Device

iOS Simulator does NOT validate AASA files or properly handle Universal Links. You must test on a real device:

bash
# Install your app on a real device
# Then test the link in Safari

# For real device:
# 1. Open Safari
# 2. Paste your deep link URL
# 3. Tap the link
# 4. Your app should launch with the route

Step 5: Check AASA File Caching

iOS aggressively caches AASA files. After updating your AASA file:

  1. Uninstall the app completely from the device
  2. Restart the device
  3. Reinstall the app
  4. Test the deep link again

iOS Caching Gotcha

If your deep link worked once but now doesn't after updating AASA, it's likely a cache issue. Force refresh by fully uninstalling and reinstalling.

#2App Links Not Working (Android)

Android App Links require the assetlinks.json file, correct intent filters, and matching app signatures. Let's go through each:

Step 1: Validate assetlinks.json

Use our validator to ensure your assetlinks.json is correctly formatted:

Step 2: Get Your App's SHA-256 Fingerprint

Your assetlinks.json needs the SHA-256 fingerprint of your signing certificate. Get it differently for debug vs. release:

For Debug Key:

bash
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android | grep "SHA1"

For Release Key:

bash
keytool -list -v -keystore /path/to/your/keystore.jks -alias your-alias

Critical: Debug vs Release Keys

Your debug and release keys have different SHA-256 fingerprints. If you test with the debug APK but your assetlinks.json has the release fingerprint, deep links won't work. Use the correct fingerprint for each build type.

Step 3: Configure AndroidManifest.xml

Your intent filter must have autoVerify="true":

xml
<activity
    android:name=".MainActivity"
    android:launchMode="singleTop">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="https"
            android:host="example.com"
            android:pathPrefix="/deep-link" />
    </intent-filter>
</activity>

Step 4: Host assetlinks.json

Your assetlinks.json must be hosted at: https://example.com/.well-known/assetlinks.json

bash
curl -v https://example.com/.well-known/assetlinks.json

Step 5: Test with adb

Test deep links directly using Android Debug Bridge:

bash
adb shell am start -W -a android.intent.action.VIEW -d "https://example.com/deep-link" com.your.package

If the intent filter matches correctly, you'll see the app launch. Check Logcat for any errors:

bash
adb logcat | grep "your-package-name"

#3Deferred Deep Links Not Firing After Install

Deferred deep links (links that fire after app installation) have additional complexity. Here's how to debug:

Understanding the Attribution Window

Deferred deep links work within an "attribution window" (typically 24-48 hours). If the user installs the app after the attribution window closes, the deferred link won't fire. You can:

  • Extend the attribution window in your Redirectly dashboard
  • Use server-side link resolution for longer-lived attribution

Step 1: Verify SDK Initialization

Your Redirectly SDK must be initialized early in your app lifecycle, before checking for deep links:

dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize Redirectly FIRST
  await Redirectly.initialize(apiKey: "YOUR_API_KEY");

  // Then check for deferred links
  await Redirectly.checkDeepLink((deepLink) {
    // Handle the deferred deep link
    print("Deferred link: ${deepLink.url}");
  });

  runApp(MyApp());
}

Step 2: Check Your API Key

Deferred deep links require a valid API key. Verify it's correct in your Flutter code:

  1. Go to your Redirectly Dashboard
  2. Navigate to Settings → API Keys
  3. Copy your production API key
  4. Paste it in your Redirectly.initialize() call

Step 3: Verify Link Was Created with Deferred=True

Your link must be created with the deferred parameter set. Check in your dashboard:

  1. Go to your Redirectly Dashboard
  2. Find the link you created
  3. Verify that "Deferred Deep Linking" is enabled
  4. Check that the link hasn't expired (past the attribution window)

Step 4: Debug with Redirectly Dashboard

The Redirectly dashboard shows real-time attribution data:

  1. Create a test deferred link
  2. Open your app's link on a new device
  3. Uninstall the app on that device
  4. Install it again within the attribution window
  5. Check the dashboard link analytics to see if the device was attributed

Testing Deferred Links Locally

To test deferred links on your computer, use Redirectly's test endpoint or create a temporary link and immediately uninstall/reinstall your debug app on a connected device.

#4Testing Deep Links

iOS Simulator Limitations

The iOS Simulator has limited deep link support. Use the command:

bash
xcrun simctl openurl booted "https://example.com/deep-link"

However, this doesn't validate AASA files or truly test Universal Links. For accurate testing, you must use a real device.

Android Emulator Testing

Android Emulator supports deep link testing better than iOS Simulator:

bash
adb shell am start -W -a android.intent.action.VIEW -d "https://example.com/deep-link" com.your.package

Real Device Testing Workflow

  1. iOS: Open Safari → Paste your deep link URL → Tap the link → Verify your app launches to the correct screen
  2. Android: Use adb with the command above, or open your browser → Paste link → Tap → Verify
  3. Capture logs: Check logcat (Android) or Xcode console (iOS) for any errors
  4. Verify route handling: Confirm your Flutter app correctly parses and navigates to the intended route

Using Redirectly Dashboard to Verify

Redirectly's dashboard shows link click analytics in real-time:

  1. Create a test link in your dashboard
  2. Click the link from your device browser
  3. Check if it opens your app
  4. Check the dashboard to see if the click was recorded

#5Common Issues Checklist

Go through this checklist systematically when debugging deep links:

Next Steps

Deep link debugging requires methodically checking each layer of the system. Start with validating your AASA and assetlinks.json files, then verify your Xcode and Android configurations, and finally test thoroughly on real devices.

If you're still having issues, use these resources to diagnose further: