Deeplinking is a methodology for launching a native mobile application via a link.
Deeplinking connects a unique url to a defined action in a mobile app, seamlessly linking users to relevant content.
In addition to guidelines and best practices, this document also contains links to open source software development kits (SDKs) so developers can implement effective deeplinking strategies as simply as possible.
This guide provides context and recommendations based on the collective experiences of its authors so you can make informed decisions about implementing deeplinking in your mobile apps.
Please direct any questions to help@mobiledeeplinking.org.
This document as well as the SDKs associated with the Mobile Deeplinking projectare licensed under the Simplified BSD License.
The Mobile Deeplinking project is a collaborative industry effort to provide aconsistent, high-quality source of documentation, sample code, and SDKs to helpmobile app publishers create effective, seamless cross-media user experiencesand marketing campaigns.
We value contributions by individuals and organizationswho share this mission, and we recommend using GitHub's pull request mechanism forsubmitting changes.
This document is broken up into two parts:
Part 1 provides an introduction and overview of mobile applicationdeeplinking and facilitates the thinking, design, communication andplanning that the marketing, product, and technology team members mustdo to ensure a successful implementation.
Part 2 is intended for developers and provides implementation details aswell as a deeplinking framework intended make it easier to get started.
Enabling deeplinking for a mobile application will allow you to invokedeeplinks that open an app and launch specific, defined screens within the app, such as the homepage,product pages, and shopping cart, much as you would on a website.
For example, just as you might link to a particular product on yourwebsite –
http://www.mobiledeeplinking.org/product/123
You can link to a product screen in your mobile app –
mobiledeeplinkingprojectdemo://product/123
Deeplinking is especially useful for promotional efforts because itallows you and any third party to open the app when a link is clicked,rather than driving to a website or to your app’s listing on the iOS AppStore or Google Play.
A deeplink functions much like a traditional hyperlink on a webpage. It is composedof separate elements that make up what is referred to as a UniformResource Identifier (URI). The URI contains all the information that,when invoked, launches a mobile application with a specific screen.
When thinking about deeplink structure, the best practice is toimplement a URL with a unique scheme name and routing parameters (path and query strings) that represent custom actions to take in the app.Unless you have very specific needs, we recommend using a simple URLstructure as shown in the example below:
mobiledeeplinkingprojectdemo://path?query_string
Where mobiledeeplinkingprojectdemo
is the scheme name and path andquery string are the routing parameters used to further route the userto a particular experience in the app.
For the scheme name:
For the routing parameters (path and query string):
Here are a few examples of deeplinks for popular apps on iOS:
Developer | Deeplink – e.g. | Purpose |
---|---|---|
twitter://timeline | Opens the Twitter app and links to the user’s timeline | |
fb://profile | Opens the Facebook app and links to the user’s profile | |
Yelp | yelp:// | Opens the Yelp app (note: this example does not include any routing parameters) |
See below for a few examples of deeplinking for the e-commerce andtravel verticals:
Deeplink – e.g. | Purpose |
---|---|
ecommercebrand:// | Open the app |
ecommercebrand://checkout | Open the app to the shopping cart checkout screen |
ecommercebrand://product/123 | Open the app to a particular product ID |
Deeplink – e.g. | Purpose |
---|---|
travelbrand:// | Open the app |
travelbrand://registration | Open the app to the user registration screen |
travelbrand://hotel/123 | Open the app to a particular hotel ID |
What follows is a developer-focused overview for implementingdeeplinking in your app. To ease the development burden, we created aMobileDeepLinking library that provides a framework for implementingmobile app deeplinking for both iOS and Android (outlined starting inPart 2.3).
We also provide guidance for those that want to implementmobile deeplinking without leveraging our library (outlined in Part2.2).
Regardless of whether you choose to use the MobileDeepLinking library,implementing deeplinking requires you to:
schemename://path?query_string
)Once that’s done, you can start implementing the code that will handlethe path and query string sections of the URL to launch the intendedaction.
It is recommended that you utilize the MobileDeepLinking libraries, butif you wish to implement mobile deeplinking directly, the high levelprocess is as follows –
iOS apps are self-contained entities. There is only one point of entryin the app: the AppDelegate. When a deeplink to your app is initiated,it will call the AppDelegate with the deeplinking metadata.
It is important to maintain a consistent state in your app whileproviding the desired experience. A deeplink may be fired at any timein any app state, and it is your responsibility to keep the app in astable state.
For example, this can mean allowing the user to return tothe main screen of your app. To accomplish this, you must push theappropriate view controllers to send the user to the desired part ofyour app while still maintaining the correct view hierarchy.
When the app is opened, you can recover the URL that was used to launchit and process it according to your needs.
You can find reference documentation on the AppDelegate here.
Android apps are composed of a set of Activities. Each of theseActivities can be called by other apps if configured as such. Dependingon how your app and deeplinks are structured, you can choose to use onecentral endpoint or many.
It is important to maintain a consistent state in your app whileproviding the desired experience. An Android Activity will launch on topof the current context and it is your responsibility to ensure theappropriate view hierarchy is maintained. Additionally, it is importantto have the necessary data ready for the Activity when it is loaded forthe user.
When the app is opened, you can recover the URL that was used to launchit and process it according to your needs.
You can find reference documentation on Android deeplinking here.
To make implementation easier, we created a MobileDeepLinking librarythat provides a framework for implementing mobile app deeplinking forboth iOS and Android.
The basic implementation setup is the same for both platforms:
mobiledeeplinkingprojectdemo://
)This spec is accompanied by libraries for both iOS and Android. Bothlibraries include a JSON file that configures the deeplink mapping.
Both the Android and iOS libraries are configured through a JSON filenamed MobileDeepLinkingConfig.json
.
This file provides the ability to mapincoming deeplink URLs to specific screens in an app, as well asconfigure additional features in the library such as custom callbackhandlers, validation, and logging.
NOTE: Android is typically configured through XML and iOS istypically configured through plists. We opted to use a JSONconfiguration to minimize source code updates and to allow for onestandard deeplinking methodology across both Android and iOS.
This allows you to use an identical configuration format when developingcross platform. The library also allows for custom client logic throughthe use of callback
handlers
which are defined in subsequent sectionsof this document.
Below are two sample JSON configuration files. The first represents abasic configuration for an Android hotel reservation app withreservations feed, reservation details, and account screens.
The seconddemonstrates additional functionality of the library for an iOSe-commerce app with sale details and add to cart screens. More detailsabout the JSON properties can be found after the sample files.
{ "defaultRoute": { "class": "com.myorg.myapp.DefaultActivity" }, "routes": { "reservations": { "class": "com.myorg.myapp.ReservationFeedActivity" }, "reservations/:reservationId": { "class": "com.myorg.myapp.ReservationDetailsActivity" }, "account/:userId": { "class": "com.myorg.myapp.AccountActivity" } }}
In the above example, the deeplinkmobiledeeplinkingprojectdemo://reservations/1234
would route to theReservationDetailsActivity and pass on the path parameterreservationId=1234 to this Activity class. Further details on theseconfigurations are below.
{ "logging": "true", /* must be a string data type */ "storyboard": { "iPhone": "MainStoryboard_iPhone", "iPad": "MainStoryboard_iPad" }, "defaultRoute": { "class": "DefaultViewController", "identifier": "defaultViewController" }, "routes": { "sales/:saleId": { "storyboard": { "iPhone": "SaleStoryboard_iPhone", "iPad": "SaleStoryboard_iPad" }, "class": "SaleViewController", "identifier": "saleViewController", "handlers": [ "logAnalytics" ], "routeParameters": { "saleId": { "required": "true", "regex": "[0-9]" }, "utmSource": { } } }, "addToCart/:productId": { "handlers": [ "authenticate", "logAnalytics", "addProductToCart" ] } }}
Attribute Name | Type | Comments |
---|---|---|
logging (optional, default to false) | boolean | Boolean that controls logging to the console |
storyboard (iOS Only, optional) | Storyboard Object | Default storyboard to be used by the routes |
defaultRoute | Default Route Object | JSON Object that defines default route to use if no matching route can be found or if validation fails |
routes | Routes Object | JSON Object that maps routes to screens and/or handlers in the app |
Contains a list of key value pairs. If creating a universal app, thisobject should have both iPhone
and iPad
attributes. If it is aniPhone-only or iPad-only app, it can simply have one of the attributes.
Attribute Name | Type | Comments |
---|---|---|
Key | string | iPhone or iPad . |
Value | string | The appropriate storyboard name for iPhone or iPad. |
Attribute Name | Type | Comments |
---|---|---|
storyboard (iOS Only, optional) | Storyboard Object | Overrides the default storyboard to use for this route |
class (optional) | string | Controller/Activity Class. Android requires fully qualified Activity class name. |
identifier (iOS Only, optional) | string | ViewController Storyboard identifier. If not included, the library will look for an identifier with the same name as the class except with the first letter in lowercase. Example: Class: MyViewController, Identifier: myViewController |
handlers (optional) | array | Array of custom handler functions to be run before, or in lieu of, class routing |
Contains a list of key-value pairs.
Attribute Name | Type | Comments |
---|---|---|
Key | string | The route to be matched, e.g. sales/:saleId . :saleId signifies that this route will match any string in this position on the path and expose it to the handlers and view. |
Value | Route Object | JSON Object that defines how to handle the route |
Attribute Name | Type | Comments |
---|---|---|
storyboard (iOS Only, optional) | Storyboard Object | Overrides the default storyboard to use for this route |
class (optional) | string | Controller/Activity Class (Android requires fully qualified class name) |
identifier (iOS Only, optional) | string | ViewController Storyboard identifier. If not included, the library will look for an identifier with the same name as the class except with the first letter in lowercase. Example: Class: MyViewController, Identifier: myViewController |
handlers (optional) | array | Array of custom handler functions to be run before, or in lieu of, class routing |
routeParameters (optional) | Route Parameters Object | JSON object that sets expected Path Parameters (sales/:saleId ) or URL Query Parameters (?userId=1234&utmSource=campaignABC ). Path parameters are prefixed with a colon in the path pattern. |
Contains a list of key-value pairs.
Attribute | Type | Comments |
---|---|---|
Key | string | Path or Query Parameter name, e.g. saleId |
Value | Route Parameter Object | JSON Object that defines how to handle the route parameter. |
Attribute Name | Type | Comments |
---|---|---|
required (optional, default to false) | boolean | Specifies whether parameter is required |
regex (optional) | string | Regex to utilize as validation for this parameter value, e.g. [0-9] |
The MobileDeepLinking library allows for flexible and powerful matchingon incoming deeplinks. On each Route Definition (e.g. sale/:saleId
),you have the ability to either specify a wildcard that matches anythingin the path component, or a regular expression that allows for morerestrictive set of accepted inputs.
Wildcard Example:
Definition:
sales/:saleId
Accepted Inputs:
sales/3
,sales/123456
,sales/my-sale-id
Prefix a colon to a path component to mark it as a wildcard. Any matcheswill be passed to the View or Handlers with a key of the same namewithout the preceding colon (in this example, saleId
).
Regular Expression Example:
Definition:
sales/:saleId
Route Parameter Regex:
[0-9]
Accepted Inputs:
sales/2
Rejected Inputs:
sales/11
,sales/my-sale-id
To account for deeplinks in the wild, the MobileDeepLinking libraryprovides a robust fallback strategy for deeplink routing. The strategy,inspired by the JSR-315 Java Servlet Specification, is as follows:
sales/5
did not match a route,the library would then fall back to matching on sales.
The MobileDeepLinking library was created to allow you to quickly getset up while also providing added functionality through the use of custom callback handlers.
When specifying the defaultRoute
or the routes
properties in theJSON Configuration, you may choose to do the following:
These three options allow you full flexibility on how you want to handledeeplinks, while preserving simplicity for more straightforwarduse-cases.
Both path and query parameters that are extracted from the deeplink will be set on the iOS View Controller through theKey-Value-Coding mechanism.
For example:
sales/:saleId
scheme://sales/3?userId=42
(Note, query parameter mustexist on the Route Parameters Object for this route).NOTE: Custom Handlers are callback functions that are registeredwith the library and are called when the appropriate route is matched.They are provided with a dictionary/map of the incoming routeparameters. These handlers allow an easy mapping for a developer toexecute custom code on incoming deeplinks.
Below is how you would configure the above three route options in theJSON configuration for iOS and Android routes.
Screen Class Only:
Custom Handlers Only: omit the class, storyboard, and identifierproperties. Specify one or more handler functions to be utilized.
Screen Class and Custom Handlers: specify the ViewController class,storyboard, identifier, and handler values.
Custom callback handlers (if needed) should be registered on applicationstartup. The handler names specified when registering must be thevalues utilized in the JSON configuration.
The order in which thehandlers are defined in the JSON configuration is the order in whichthey will be executed. Additionally, any modifications made to a handler's NSDictionary/Map will be persisted to the next handler in the chain. Handlers can be re-used across multiple routesthat require the same functionality (authentication, analytics, etc).
Custom handlers should be registered in the below method in theAppDelegate class.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ [[MobileDeepLinking sharedInstance] registerHandlerWithName:@"logAnalytics" handler:^(NSDictionary *properties) { NSLog([properties objectForKey:@"saleId"]); }];}
Custom handlers should be registered in the onCreate method in theApplication class. The Handler interface class is supplied in theMobileDeepLinking library.
public class MyApplication extends Application{ @Override public void onCreate() { super.onCreate(); MobileDeepLinking mobileDeepLinking = MobileDeepLinking.getInstance(); mobileDeepLinking.registerHandler("logAnalytics", new Handler() { @Override public void handle (Map<String, String> properties) { Log.d(properties.get("saleId")); } }); }}
The MobileDeepLinking library will forward on URL parameters andnecessary context objects to the associated route classes and handlers.
Controller classes can access the URL parameters through class variablesset on the class. The MobileDeepLinking library will map therouteParameters to properties of the same name in your ViewControllers.
@implementation MyViewController@synthesize saleId;- (void)viewDidLoad{ [super viewDidLoad]; NSLog(saleId);}
Handler functions can access the URL parameters through an NSDictionarysent to the handler function.
[properties objectForKey:@"saleId"]
Activity classes can access the URL parameters through the Intent sentto the Activity.
public class MyActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String saleId = getIntent().getStringExtra("saleId"); }}
Handler functions can access the URL parameters through a Map sent tothe handler function.
properties.get("saleId");
The MobileDeepLinking library for iOS is available on GitHub and throughCocoaPods.
Update the MobileDeepLinkingConfig.json
with the appropriate routes and classnames.
Configure the Custom URL Scheme (skip below if you already have thisconfigured)
mobiledeeplinkingprojectdemoDemoApp
)Drop the MobileDeepLinking.framework
file and MobileDeepLinkingConfig.json
intoXcode.
Import MobileDeepLinking.h
in your AppDelegate class.
Register custom function handlers if needed in the AppDelegate class.
Place the following line of code into the below method in yourAppDelegate.m
:
- application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{ [[MobileDeepLinking sharedInstance] routeUsingUrl:url];}
The MobileDeepLinking library for Android is available on GitHub andMaven Central. It is available for standalone download or use throughMaven or Gradle.
MobileDeepLinkingConfig.json
with the appropriate routes and classnames.MobileDeepLinkingConfig.json
into your project andreference it in your settings.<activity android:name="com.mobiledeeplinking.MobileDeepLinking" android:theme="@android:style/Theme.NoDisplay"> <intent-filter> <data android:scheme="<YOUR_URL_SCHEME>"/> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <intent-filter><activity>
You can find the MobileDeepLinking libraries on github. These libraries implement the recommended spec laid out in this document.
The iOS Library can be found here.
The Android Library can be found here.