


Flutter Deep Linking: Pathways to specific app content
By:
Sunil Kumar Muduli
12 Jun 2025
In the mobile-first world, users expect seamless navigation between apps and websites. Deep linking bridges that gap by allowing you to link directly to specific content within a mobile app, and in Flutter, it's easier than ever to implement.
In this blog, we’ll dive into what deep linking is, why it matters, and how to implement it in your Flutter application.
What is Deep Linking?
Deep Linking refers to the practice of launching an app and opening a specific page (or route) within it using a URL. For example, clicking a link like myapp://product/123 opens the product detail page for item ID 123 in your app.
There are three main types of deep links:
1. Traditional Deep Links: Work if the app is already installed.
2. Deferred Deep Links: Work even if the app isn’t installed; the user is taken to the app store first and then routed correctly post-install.
3. Universal Links (iOS) / App Links (Android): Secure and recommended way of implementing deep linking using HTTP URLs (https://example.com/product/123).
Why Use Deep Linking?
Deep linking enhances:
• User experience: Take users to the exact content they need.
• Marketing campaigns: Track and route users from ads or emails.
• Onboarding: Guide new users directly to referral codes or shared content.
• Cross-platform consistency: Unified behavior across Android and iOS.
Anatomy of a Deep Link
A deep link is a link that sends users to a destination in your app, rather than a web page. To grasp what a deep link is made of, consider this example:
https://share.fiole.app/book/67c57a875dfb8c9776dd3ce4
Deep links contain a string of characters known as a URI, which contains:
1. Scheme: This is the first part of the link, often spotted as http or https. The scheme tells us what protocol to use when fetching the resource online.
2. Host: This is the domain name of the link. In our case, codewithandrea.com is the host, showing us where the resource lives.
3. Path: This identifies the specific resource in the host that the user wants to access. For our example, /articles/parse-json-dart/ is the path.
Sometimes, you'll also see these:
1. Query Parameters: These are extra options tacked on after a ? mark. They're usually there to help sort or filter data.
2. Port: This is for reaching the server's network services. We often see it in development setups. When not mentioned, HTTP and HTTPS will stick to their default ports (80 and 443).
3. Fragment: Also called an anchor, this optional bit follows a # and zooms in on a specific part of a webpage.
Here’s an annotated example showing all of the above:

Android Setup:
1. Add supported host to your manifest
• Open the android/app/src/main/AndroidManifest.xml file
• Add an intent filter to your activity tag
• Specify your scheme and host
• Optional: define supported paths
<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="yourScheme" /> <data android:host="yourDomain.com" /> </intent-filter>
2. Verify your domains
• Create a new file named assetlinks.json. This file will contain the digital asset links that associate your site with your app. Here’s what should be inside:
[{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.example.app",//your android package name "sha256_cert_fingerprints": ["00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"] // your app's unique SHA256 fingerprint } }]
• Upload the assetlinks.json file to your website. It must be accessible via https://yourdomain/.well-known/assetlinks.json.
• To check if the assetlinks.json is correctly set up, use the statement list tester tool provided by Google at https://developers.google.com/digital-asset-links/tools/generator
3. How to Test Deep Links on Android
Just open an Android emulator and pop open the terminal to run these commands.
• For HTTP/HTTPS links:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d https://yourDomain.com \ <package name>
• And for custom schemes:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d yourScheme://yourDomain.com \ <package name>
iOS Setup
1. Setup associated domains
• Open ios/Runner.xcworkspace in Xcode.
• Head to Runner > Signing & Capabilities > + Capability > Associated Domains.
• Prefix your domain with applinks: when adding it.

2. Add URL Schemes in your info.plist
• Open the Info.plist file.
• Set up an identifier like below.
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>yourScheme</string> </array> <key>CFBundleURLName</key> <string>yourIdentifier</string> </dict> </array>
3. Verifying the iOS Server for Deep Links:
on iOS, the file hosted on the server contains not only the app info but also the supported paths. Here's how to get it done:
• Create a new file named apple-app-site-association with no file extension. This file will contain the digital asset links tying your website and app together. Fill it with something like this:
{ "webcredentials": { "apps": [ "<TEAM ID>.<BUNDLE ID>" ] }, "applinks": { "apps": [], "details": [ { "appIDs": [ "<TEAM ID>.<BUNDLE ID>" ], "appID":"<TEAM ID>.<BUNDLE ID>", "paths": [ "*", "/" ] } ] } }
• Host the apple-app-site-association file on your website. It must be accessible via https://yourDomain.com/.well-known/apple-app-site-association.
• The apple-app-site-association file must be served with the application/json content type (but not have the .json file extension!) and should not be signed or encrypted.
Handling Deep Links with GoRouter in Flutter
GoRouter is a go-to choice for many Flutter developers when it comes to navigation. It uses the Router API to offer a URL-based approach for navigating between screens, which aligns perfectly with deep linking.
• First, set up your app with MaterialApp.router like so:
void main() { runApp(const App()); } class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: goRouter, ); } }
• Defining routes for your app
i. A main screen that serves as the app's entry point, corresponding to https://yourdomain.com.
ii. A details screen with a URL like https://yourdomain.com/product/itemId.
final goRouter = GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const MainScreen(), routes: [ GoRoute( path: product/:itemId', builder: (context, state) => ProductDetailsScreen(id: state.pathParameters['itemId']!), ) ], ) ], );
Navigating to the Deep Link Destination
Now that the routes are set up, we need to handle the deep link and send the user to the specific screen of our app.
On the web, it needs no extra setup. It will navigate to desired screen accordingly.
For Android:
Add this metadata into the AndroidManifest.xml within the activity tag:
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
And on iOS, you'll need to add this snippet to your Info.plist:
<key>FlutterDeepLinkingEnabled</key> <true
Test deep link implementation
1. Android:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d https://yourDomain.com/product/3 \ <package name>
2. iOS:
xcrun simctl openurl booted https://yourDomain.com/product/3
After running these commands, your app should navigate to the screen associated with the deep link URL.
Live Preview


Conclusion
Deep links can significantly enhance the user experience by delivering direct passage to specific areas within an app. This guide has offered a comprehensive overview, from setting up native Android and iOS code to managing routes with GoRouter.
Frequently Asked Questions
1. What is the difference between deep linking and universal linking in Flutter?
A. Universal links use HTTP/HTTPS and work even if the app isn't installed, while deep links rely on custom schemes and work only if the app is installed.
2. How to implement deep linking in Flutter for Android and iOS?
A. Set up intent filters in AndroidManifest.xml
for Android and associated domains plus URL schemes in Info.plist
for iOS.
3. Can GoRouter handle deep linking in Flutter?
A. Yes, GoRouter supports deep linking with URL-based navigation across Android, iOS, and web.
In the mobile-first world, users expect seamless navigation between apps and websites. Deep linking bridges that gap by allowing you to link directly to specific content within a mobile app, and in Flutter, it's easier than ever to implement.
In this blog, we’ll dive into what deep linking is, why it matters, and how to implement it in your Flutter application.
What is Deep Linking?
Deep Linking refers to the practice of launching an app and opening a specific page (or route) within it using a URL. For example, clicking a link like myapp://product/123 opens the product detail page for item ID 123 in your app.
There are three main types of deep links:
1. Traditional Deep Links: Work if the app is already installed.
2. Deferred Deep Links: Work even if the app isn’t installed; the user is taken to the app store first and then routed correctly post-install.
3. Universal Links (iOS) / App Links (Android): Secure and recommended way of implementing deep linking using HTTP URLs (https://example.com/product/123).
Why Use Deep Linking?
Deep linking enhances:
• User experience: Take users to the exact content they need.
• Marketing campaigns: Track and route users from ads or emails.
• Onboarding: Guide new users directly to referral codes or shared content.
• Cross-platform consistency: Unified behavior across Android and iOS.
Anatomy of a Deep Link
A deep link is a link that sends users to a destination in your app, rather than a web page. To grasp what a deep link is made of, consider this example:
https://share.fiole.app/book/67c57a875dfb8c9776dd3ce4
Deep links contain a string of characters known as a URI, which contains:
1. Scheme: This is the first part of the link, often spotted as http or https. The scheme tells us what protocol to use when fetching the resource online.
2. Host: This is the domain name of the link. In our case, codewithandrea.com is the host, showing us where the resource lives.
3. Path: This identifies the specific resource in the host that the user wants to access. For our example, /articles/parse-json-dart/ is the path.
Sometimes, you'll also see these:
1. Query Parameters: These are extra options tacked on after a ? mark. They're usually there to help sort or filter data.
2. Port: This is for reaching the server's network services. We often see it in development setups. When not mentioned, HTTP and HTTPS will stick to their default ports (80 and 443).
3. Fragment: Also called an anchor, this optional bit follows a # and zooms in on a specific part of a webpage.
Here’s an annotated example showing all of the above:

Android Setup:
1. Add supported host to your manifest
• Open the android/app/src/main/AndroidManifest.xml file
• Add an intent filter to your activity tag
• Specify your scheme and host
• Optional: define supported paths
<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="yourScheme" /> <data android:host="yourDomain.com" /> </intent-filter>
2. Verify your domains
• Create a new file named assetlinks.json. This file will contain the digital asset links that associate your site with your app. Here’s what should be inside:
[{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.example.app",//your android package name "sha256_cert_fingerprints": ["00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"] // your app's unique SHA256 fingerprint } }]
• Upload the assetlinks.json file to your website. It must be accessible via https://yourdomain/.well-known/assetlinks.json.
• To check if the assetlinks.json is correctly set up, use the statement list tester tool provided by Google at https://developers.google.com/digital-asset-links/tools/generator
3. How to Test Deep Links on Android
Just open an Android emulator and pop open the terminal to run these commands.
• For HTTP/HTTPS links:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d https://yourDomain.com \ <package name>
• And for custom schemes:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d yourScheme://yourDomain.com \ <package name>
iOS Setup
1. Setup associated domains
• Open ios/Runner.xcworkspace in Xcode.
• Head to Runner > Signing & Capabilities > + Capability > Associated Domains.
• Prefix your domain with applinks: when adding it.

2. Add URL Schemes in your info.plist
• Open the Info.plist file.
• Set up an identifier like below.
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>yourScheme</string> </array> <key>CFBundleURLName</key> <string>yourIdentifier</string> </dict> </array>
3. Verifying the iOS Server for Deep Links:
on iOS, the file hosted on the server contains not only the app info but also the supported paths. Here's how to get it done:
• Create a new file named apple-app-site-association with no file extension. This file will contain the digital asset links tying your website and app together. Fill it with something like this:
{ "webcredentials": { "apps": [ "<TEAM ID>.<BUNDLE ID>" ] }, "applinks": { "apps": [], "details": [ { "appIDs": [ "<TEAM ID>.<BUNDLE ID>" ], "appID":"<TEAM ID>.<BUNDLE ID>", "paths": [ "*", "/" ] } ] } }
• Host the apple-app-site-association file on your website. It must be accessible via https://yourDomain.com/.well-known/apple-app-site-association.
• The apple-app-site-association file must be served with the application/json content type (but not have the .json file extension!) and should not be signed or encrypted.
Handling Deep Links with GoRouter in Flutter
GoRouter is a go-to choice for many Flutter developers when it comes to navigation. It uses the Router API to offer a URL-based approach for navigating between screens, which aligns perfectly with deep linking.
• First, set up your app with MaterialApp.router like so:
void main() { runApp(const App()); } class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: goRouter, ); } }
• Defining routes for your app
i. A main screen that serves as the app's entry point, corresponding to https://yourdomain.com.
ii. A details screen with a URL like https://yourdomain.com/product/itemId.
final goRouter = GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const MainScreen(), routes: [ GoRoute( path: product/:itemId', builder: (context, state) => ProductDetailsScreen(id: state.pathParameters['itemId']!), ) ], ) ], );
Navigating to the Deep Link Destination
Now that the routes are set up, we need to handle the deep link and send the user to the specific screen of our app.
On the web, it needs no extra setup. It will navigate to desired screen accordingly.
For Android:
Add this metadata into the AndroidManifest.xml within the activity tag:
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
And on iOS, you'll need to add this snippet to your Info.plist:
<key>FlutterDeepLinkingEnabled</key> <true
Test deep link implementation
1. Android:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d https://yourDomain.com/product/3 \ <package name>
2. iOS:
xcrun simctl openurl booted https://yourDomain.com/product/3
After running these commands, your app should navigate to the screen associated with the deep link URL.
Live Preview


Conclusion
Deep links can significantly enhance the user experience by delivering direct passage to specific areas within an app. This guide has offered a comprehensive overview, from setting up native Android and iOS code to managing routes with GoRouter.
Frequently Asked Questions
1. What is the difference between deep linking and universal linking in Flutter?
A. Universal links use HTTP/HTTPS and work even if the app isn't installed, while deep links rely on custom schemes and work only if the app is installed.
2. How to implement deep linking in Flutter for Android and iOS?
A. Set up intent filters in AndroidManifest.xml
for Android and associated domains plus URL schemes in Info.plist
for iOS.
3. Can GoRouter handle deep linking in Flutter?
A. Yes, GoRouter supports deep linking with URL-based navigation across Android, iOS, and web.
In the mobile-first world, users expect seamless navigation between apps and websites. Deep linking bridges that gap by allowing you to link directly to specific content within a mobile app, and in Flutter, it's easier than ever to implement.
In this blog, we’ll dive into what deep linking is, why it matters, and how to implement it in your Flutter application.
What is Deep Linking?
Deep Linking refers to the practice of launching an app and opening a specific page (or route) within it using a URL. For example, clicking a link like myapp://product/123 opens the product detail page for item ID 123 in your app.
There are three main types of deep links:
1. Traditional Deep Links: Work if the app is already installed.
2. Deferred Deep Links: Work even if the app isn’t installed; the user is taken to the app store first and then routed correctly post-install.
3. Universal Links (iOS) / App Links (Android): Secure and recommended way of implementing deep linking using HTTP URLs (https://example.com/product/123).
Why Use Deep Linking?
Deep linking enhances:
• User experience: Take users to the exact content they need.
• Marketing campaigns: Track and route users from ads or emails.
• Onboarding: Guide new users directly to referral codes or shared content.
• Cross-platform consistency: Unified behavior across Android and iOS.
Anatomy of a Deep Link
A deep link is a link that sends users to a destination in your app, rather than a web page. To grasp what a deep link is made of, consider this example:
https://share.fiole.app/book/67c57a875dfb8c9776dd3ce4
Deep links contain a string of characters known as a URI, which contains:
1. Scheme: This is the first part of the link, often spotted as http or https. The scheme tells us what protocol to use when fetching the resource online.
2. Host: This is the domain name of the link. In our case, codewithandrea.com is the host, showing us where the resource lives.
3. Path: This identifies the specific resource in the host that the user wants to access. For our example, /articles/parse-json-dart/ is the path.
Sometimes, you'll also see these:
1. Query Parameters: These are extra options tacked on after a ? mark. They're usually there to help sort or filter data.
2. Port: This is for reaching the server's network services. We often see it in development setups. When not mentioned, HTTP and HTTPS will stick to their default ports (80 and 443).
3. Fragment: Also called an anchor, this optional bit follows a # and zooms in on a specific part of a webpage.
Here’s an annotated example showing all of the above:

Android Setup:
1. Add supported host to your manifest
• Open the android/app/src/main/AndroidManifest.xml file
• Add an intent filter to your activity tag
• Specify your scheme and host
• Optional: define supported paths
<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="yourScheme" /> <data android:host="yourDomain.com" /> </intent-filter>
2. Verify your domains
• Create a new file named assetlinks.json. This file will contain the digital asset links that associate your site with your app. Here’s what should be inside:
[{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.example.app",//your android package name "sha256_cert_fingerprints": ["00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"] // your app's unique SHA256 fingerprint } }]
• Upload the assetlinks.json file to your website. It must be accessible via https://yourdomain/.well-known/assetlinks.json.
• To check if the assetlinks.json is correctly set up, use the statement list tester tool provided by Google at https://developers.google.com/digital-asset-links/tools/generator
3. How to Test Deep Links on Android
Just open an Android emulator and pop open the terminal to run these commands.
• For HTTP/HTTPS links:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d https://yourDomain.com \ <package name>
• And for custom schemes:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d yourScheme://yourDomain.com \ <package name>
iOS Setup
1. Setup associated domains
• Open ios/Runner.xcworkspace in Xcode.
• Head to Runner > Signing & Capabilities > + Capability > Associated Domains.
• Prefix your domain with applinks: when adding it.

2. Add URL Schemes in your info.plist
• Open the Info.plist file.
• Set up an identifier like below.
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>yourScheme</string> </array> <key>CFBundleURLName</key> <string>yourIdentifier</string> </dict> </array>
3. Verifying the iOS Server for Deep Links:
on iOS, the file hosted on the server contains not only the app info but also the supported paths. Here's how to get it done:
• Create a new file named apple-app-site-association with no file extension. This file will contain the digital asset links tying your website and app together. Fill it with something like this:
{ "webcredentials": { "apps": [ "<TEAM ID>.<BUNDLE ID>" ] }, "applinks": { "apps": [], "details": [ { "appIDs": [ "<TEAM ID>.<BUNDLE ID>" ], "appID":"<TEAM ID>.<BUNDLE ID>", "paths": [ "*", "/" ] } ] } }
• Host the apple-app-site-association file on your website. It must be accessible via https://yourDomain.com/.well-known/apple-app-site-association.
• The apple-app-site-association file must be served with the application/json content type (but not have the .json file extension!) and should not be signed or encrypted.
Handling Deep Links with GoRouter in Flutter
GoRouter is a go-to choice for many Flutter developers when it comes to navigation. It uses the Router API to offer a URL-based approach for navigating between screens, which aligns perfectly with deep linking.
• First, set up your app with MaterialApp.router like so:
void main() { runApp(const App()); } class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: goRouter, ); } }
• Defining routes for your app
i. A main screen that serves as the app's entry point, corresponding to https://yourdomain.com.
ii. A details screen with a URL like https://yourdomain.com/product/itemId.
final goRouter = GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const MainScreen(), routes: [ GoRoute( path: product/:itemId', builder: (context, state) => ProductDetailsScreen(id: state.pathParameters['itemId']!), ) ], ) ], );
Navigating to the Deep Link Destination
Now that the routes are set up, we need to handle the deep link and send the user to the specific screen of our app.
On the web, it needs no extra setup. It will navigate to desired screen accordingly.
For Android:
Add this metadata into the AndroidManifest.xml within the activity tag:
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
And on iOS, you'll need to add this snippet to your Info.plist:
<key>FlutterDeepLinkingEnabled</key> <true
Test deep link implementation
1. Android:
adb shell am start -a android.intent.action.VIEW \ -c android.intent.category.BROWSABLE \ -d https://yourDomain.com/product/3 \ <package name>
2. iOS:
xcrun simctl openurl booted https://yourDomain.com/product/3
After running these commands, your app should navigate to the screen associated with the deep link URL.
Live Preview


Conclusion
Deep links can significantly enhance the user experience by delivering direct passage to specific areas within an app. This guide has offered a comprehensive overview, from setting up native Android and iOS code to managing routes with GoRouter.
Frequently Asked Questions
1. What is the difference between deep linking and universal linking in Flutter?
A. Universal links use HTTP/HTTPS and work even if the app isn't installed, while deep links rely on custom schemes and work only if the app is installed.
2. How to implement deep linking in Flutter for Android and iOS?
A. Set up intent filters in AndroidManifest.xml
for Android and associated domains plus URL schemes in Info.plist
for iOS.
3. Can GoRouter handle deep linking in Flutter?
A. Yes, GoRouter supports deep linking with URL-based navigation across Android, iOS, and web.
Explore our services
Explore other blogs
Explore other blogs

let's get in touch
Have a Project idea?
Connect with us for a free consultation !
Confidentiality with NDA
Understanding the core business.
Brainstorm with our leaders
Daily & Weekly Updates
Super competitive pricing

let's get in touch
Have a Project idea?
Connect with us for a free consultation !
Confidentiality with NDA
Understanding the core business.
Brainstorm with our leaders
Daily & Weekly Updates
Super competitive pricing
DEFINITELY POSSIBLE
Our Services
Technologies
Crafted & maintained with ❤️ by our Smartees | Copyright © 2025 - Smartters Softwares PVT. LTD.
Our Services
Technologies
Created with ❤️ by our Smartees
Copyright © 2025 - Smartters Softwares PVT. LTD.