# Debugging Deep Links in Flutter: Complete Troubleshooting Guide
> Fix Universal Links, App Links, and deferred deep links in Flutter. A step-by-step debugging guide with solutions for the most common issues.
- Canonical: https://redirectly.app/blog/debugging-deep-links-flutter
- Site: [Redirectly](https://redirectly.app) — deferred deep linking for Flutter & React Native
- Published: 2026-03-07
- Author: Redirectly
- Category: Flutter · 8 min read
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.
## #1 Universal 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:
[Open AASA Validator](https://redirectly.app/aasa-validator.md)
### Step 2: Check Associated Domains in Xcode
Your Xcode project must have the Associated Domains entitlement configured:
```xml
com.apple.developer.associated-domains
applinks:example.com
applinks:www.example.com
```
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.
## #2 App 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:
[Open assetlinks.json Validator](https://redirectly.app/assetlinks-validator.md)
### 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
```
### 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"
```
## #3 Deferred 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](https://dashboard.redirectly.app)
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.
## #4 Testing 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
## #5 Common Issues Checklist
Go through this checklist systematically when debugging deep links:
- [ ] **AASA/assetlinks.json file exists and is valid JSON** — Use our validators to check
- [ ] **Files are hosted at correct URLs (.well-known/)** — Test with curl to verify accessibility
- [ ] **iOS: Associated Domains entitlement added in Xcode** — With applinks: prefix, HTTPS domain only
- [ ] **Android: Intent filter has autoVerify="true"** — In AndroidManifest.xml for App Links to work
- [ ] **Android: SHA-256 fingerprint matches your signing key** — Debug key and release key have different fingerprints
- [ ] **iOS: Using HTTPS (not HTTP) domain** — Universal Links require HTTPS
- [ ] **iOS: Content-Type header is application/json** — Verify with curl -v
- [ ] **Flutter app correctly handles deep link routes** — Route paths must match your link structure
- [ ] **Deferred links: Redirectly SDK initialized at app startup** — Before any route handling logic
- [ ] **Testing on real devices (not simulators/emulators)** — Simulators don't fully support Universal 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:
- [AASA Validator](https://redirectly.app/aasa-validator.md) — Validate your Apple App Site Association file
- [assetlinks.json Validator](https://redirectly.app/assetlinks-validator.md) — Validate your Android assetlinks.json file
- [Flutter Deferred Deep Linking](https://redirectly.app/flutter-deferred-deep-linking.md) — Complete Flutter deferred deep linking guide
- [More Resources](https://redirectly.app/blog.md) — Explore our complete deep linking guides
---
Full site index for AI agents: https://redirectly.app/llms.txt