Everything you need to know about implementing iOS and Android Mobile Deep Linking

Real-world implementation in as few words as possible

What is Mobile App Deep Linking?

Normally when a user clicks a link to a website, the website opens in a web browser. Mobile App Deep Linking allows a corresponding native iOS/Android native app to open instead of a web browser:

Apple calls it Universal Links and Google calls it App Links, but those are just brand names for the same thing — opening a specific app instead of a web browser.

Why would you want to implement Deep Links for your website?

There are some good arguments for pushing users into your native app instead of towards your website:

Google shows their own restaurant guide before any organic search results.

Your native app might provide a better user experience on small screens or provide extra features that aren’t possible on the web (like location-based searches) Native app users are possibly more loyal and possibly spend more money than your website users (you need to measure this yourself) You might be worried about competition from Google!

If your business depends on search traffic from Google, you run the risk of Google displacing your entire business when they decide to compete with you. They do this by showing their own competing products on search result pages above even the top organic search results. Getting a number one rank on a search result page doesn’t matter of the user doesn’t see any of the search results!

To fight back, some companies are trying to covert as many SEO users as possible into native app users by forcing them into downloading a native app. The theory is that Google will continually siphon off new SEO traffic, but new native app users will build a habit to skip Google and come back to your app instead. No one knows if this will be a winning strategy in the long run.

Why might you not want to use Deep Links?

If your native app isn’t top notch, don’t force your users into using it. Only force users into your app if you really believe it’s a better user experience than your website. Otherwise you will frustrate your users.

Deep linking works well for apps that provide a dedicated market place experience (like eBay) or apps that need features like push notifications or location that you can’t do as well on a website (like Twitter). But they don’t work well when users feel like you are forcing them to use your app for no good reason. That results in angry users and attrition.

Implementing Deep Links

Both iOS (9.0 and newer) and Android (all versions) provide good APIs for deep linking. You can implement deep linking on both platforms at the same time and a lot of the work overlaps.

Step 1: Mapping website URLs to screens in your app

First, you need to decide which urls on your website should link to which screens in your mobile app.

For example, let’s pretend you have a shopping website is called example.com. On your website, you have products with urls like https://www.example.com/products/skinny-jeans. You also have a blog on your website at https://www.example.com/company-blog.

Based on this, you might create a mapping like this:

According to this mapping, you only want to deep link the user into the app when they click on a /products/ link. If they click on a link to your company blog, it’s probably better to just show them the normal website.

Make sure you only deep link users into your app when you can actually show them the exact information they wanted from inside the native app. Few things are as frustrating as clicking a link to a blog post and then getting redirected into an iPhone app and seeing a generic welcome page instead of that blog post. That kind of poor app integration is a good way to lose customers.

Step 2: iOS and Universal Links

Apple introduced a new deep linking API in iOS 9.0 called “Universal Links”. It provides a better user experience than the hacky deep linking options that existed in iOS 8.0 and below.

I recommend that you only implement Universal Links and don’t implement support for iOS 8.0 and below if you can possibly avoid it. Not only is this a lot less work, but the older deep linking solutions for iOS 8 constantly break in iOS 9 updates. Apple is sending a not so subtle message that you shouldn’t use the old methods anymore.

Of course, that means deep linking won’t work for users still on iOS 8. Apple provides estimates of how many users have upgraded to iOS 9. Right now, around 85% of users globally have upgraded. That percentage is growing daily and is probably higher for US/Canada and western Europe.

Implementing iOS Universal Links

In Step 1, we decided that links to https://www.example.com/products/* should launch our iOS app and show the correct product screen. This requires changes on both our website and in our native app.

First, you have to create a file on your website called https://www.example.com/.well-known/apple-app-site-association that tells Apple that you own your mobile app and that it should intercept all links to /products/.

Important Tips:

This file will be downloaded automatically by every single user that installs or upgrades your iOS app. If you have a lot of app users, that means app upgrades will trigger lots of traffic to this file all at once. I highly recommend hosting this file on a CDN to prevent the flood of traffic from taking down your website.

If you have a lot of app users, that means app upgrades will trigger lots of traffic to this file all at once. I highly recommend hosting this file on a CDN to prevent the flood of traffic from taking down your website. The file must be served over https:// with a valid SSL certificate.

The file has to be located on your website at exactly /.well-known/apple-app-site-association . You can leave off “/.well-known/” and iOS will still find the file at the root of your website. But iOS always checks /.well-known/ first, so you’ll get lots of junk traffic if do that.

. You can leave off “/.well-known/” and iOS will still find the file at the root of your website. But iOS always checks /.well-known/ first, so you’ll get lots of junk traffic if do that. Because this file is only fetched once when the user first installs or upgrades the app, this file must be live on your website before your app is released. This also means that you can’t add new deep linking url patterns to your app until you push out a new app update to force users to refresh the file.

your app is released. This also means that you can’t add new deep linking url patterns to your app until you push out a new app update to force users to refresh the file. Check the Apple Docs for more options, like matching url patterns with wildcards.

The second part of implementing Universal Links is updating your iOS app to respond correctly when it receives a deep link.

This involves:

Adding the “Associated Domains” capability to your app in Xcode and adding an entry to associated domains list with your domain name prefixed with “applinks:” (for example, “applinks:www.example.com”).

Adopting the UIApplicationDelegate method application:continueUserActivity:restorationHandler: which is called when a user clicks on a deep link. You will be passed a NSUserActivity object with the webpageURL the user was trying to access. You can use that to figure out the correct screen to pop up in your app. It’s completely up to you to slice up the url, figure out what the user intended to see based on the url, and show the right screen in your app.

The docs from Apple are pretty straightforward, so check those out for specific details.

Congrats, deep links should now work for iOS!

Step 3: Android and App Links

Android has supported deep links via Intent Filters for many years. But in Android Marshmallow (6.0), they expanded deep linking with App Links to give you more control over the user experience.

Implementing Android Intent Filters

In Android, Intent Filters let your app declare all the ways it can be launched by other apps. By adding a BROWSABLE intent filter, you are saying that your app can be started by a user clicking on a website url.

Adding Intent Filters to your Android app does not require any server-side changes at all. You only have to modify your app.

First, you update your AndroidManifest.xml file and add a new <intent-filter> declaration telling Android which Activity to start when the user clicks on a https://www.example.com/products/* link:

Next, you add code to that Activity to grab the url the user clicked and show the right feature in the app:

Google’s Docs on implementing Intent Filters are really simple and clear, so check them out for more details.

The Problem with Intent Filters

There’s one big problem with Intent Filters — any app can register them! You don’t have to prove you own a website to capture clicks on that website. This means your competition’s app can capture deep links from your website instead of your app!

Look what happens when I click on a link to www.reddit.com on my phone:

Seven apps on my phone are trying to claim they own links to “reddit.com”!

Instead of opening the official Reddit app, I have to choose from a list of all the apps on my phone that claim to support reddit.com urls. I have seven apps on my phone that are competing to be opened!

Android App Links with verification was created to address this. It lets you declare that you own the official app for your website and it your app should be used by default.

Implementing Android App Links with Verification

First, update your AndroidManifest.xml file again to request that Android verify that you own your website:

Second, you need to create a file on your website called https://www.example.com/.well-known/assetlinks.json that proves to Google that you own the app.

Important Tips:

The file must be served over https:// with a valid SSL certificate.

You can generate the “sha256_cert_fingerprints” value with this command:

$ keytool -list -v -keystore my-release-key.keystore

For more complex cases (like if you have multiple website domains or multiple apps), check Google’s docs.

Asset Link Verification only owns for Android 6.0 and above. Unfortunately that currently only represents 7.5% of users. The rest of your users will see the old Intent Filter behavior.

Congrats, deep links should now work for Android!

Promoting your app to website visitors

Now you have deep links implemented and it is working great for all of your existing users!

But deep links only trigger when a user already has your native app installed before they visit your site. Brand new users will still land on your website. For those website users, you’ll probably want to ask them to download your app.

You don’t need to build a custom banner to promote downloading your app. Both iOS and Android provide a nice built-in way to easily pop up a banner on your website prompting the user to download your app. Using the banner provided by the operating system (instead of building your own) gives you less control, but it results in a more integrated and slick app installation experience with less user annoyance.

iOS Smart Banners

On iOS, you can choose to show users a Smart Banner like this:

The banner is “smart” because it can tell if the user has the native app installed and adapt it’s behavior. If the user doesn’t have the app, it will prompt them to download it. If the user already has the app, it will open the app to the corresponding screen.

Implementing this Smart Banner is really easy. You just need to add a <meta> tag to each page on your website where you want to show a banner:

Tips:

You can get your app store id from the iTunes Link Maker page.

The app-argument is passed to your app to tell it which screen to show when the app opens.

Android App Install Banners

Google also has their own version of a smart banner. They call it an App Install Banner. It pops up inside the user’s web browser when they visit your page:

Google’s implementation is slick. You can install and launch the app without ever leaving the web browser.

But it comes with more limitations than Apple’s version:

The banner will only show up for repeat visitors to your website (at least two visits on two separate days within a two week window). First time visitors won’t see it. This prevents users from seeing a banner on every website they visit and getting app fatigue.

The banner only shows up in Chrome, so the user won’t see a banner if they are using a third-party web browser.

Let’s implement it. First, you need to create a web app manifest json file and host it on your site:

Tips:

The file can be hosted anywhere on your site.

The file must be served over https:// with a valid SSL certificate.

You must have a 144x144 png icon with a mime type of “image/png” or it won’t display a banner.

Second, you need to add a <meta> tag to each page of your site linking to the manifest file:

One last tip:

Testing this banner can be tricky because it only shows up after you visit the page twice over two days. Visit chrome://flags/#bypass-app-banner-engagement-checks in your browser to force the banner to show while testing.

That’s it!

Common Problems

So you’ve implemented deep links and smart banners. Everything is working perfectly, right?

Unfortunately there are areas where things don’t work as expected — especially on iOS with Universal Links. Here are the most common issues:

Universal Links used to work on iOS, but stopped working!

Apple made a really strange UI decision when they implemented Universal Links. When you click on a Universal Link, you’ll see the app open like this:

But watch out! Clicking the website link on the right doesn’t just open the website once. It disables Universal Links permanently for this app!

A lot of users click this once by mistake and don’t realize they are turning off deep linking permanently. The only way to turn deep linking back on for that user is to have a Smart Banner on the corresponding webpage so the user has the path back into the app. That’s another reason I highly recommend implementing Smart Banners on your website.

Universal Links don’t work for users on iOS using the Google Gmail or Inbox email apps

Yep, Universal Links won’t trigger for users clicking on email links in the Gmail or Inbox apps. It sucks. Google seems to care more about keeping users in their apps than providing a consistent iOS user experience.

There are some gross ways to hack around this if you really need to, but those are beyond the scope of this article because they constantly break with new iOS updates. Good luck.

Universal Links don’t work when clicking on links in the Facebook (or Twitter) iOS apps

Yep, Universal Links won’t trigger in the Facebook iOS app just like with Gmail. Again, Facebook seems to care more about keeping you inside their app (using a webview widget) than providing a consistent UX.

If you pay Facebook to post mobile ads, they do support deep linking on those ad links. Amazing how that works…

Universal Links don’t trigger if the user is already viewing my website

If a user is already viewing your website in Safari, clicking a link to a different page on that same site won’t make your app launch. This is by design on iOS (note that Android has the opposite behavior).

If you want to implement an “Open this page in our app” button on your web site, you’ll have to do something hacky like sending the user to a different domain name and enabling Universal Links for that second domain name as well. I’d avoid this if possible.

Takeaway Lessons

Deep linking can be a great feature to enable if your native app is top notch.

Don’t enable deep linking if your native app is terrible.

Deep linking pretty much always works as expected on Android, but the website owner has less control over the experience than the user.

Deep linking works well on iOS and the website owner has more control, but there are several cases where it doesn’t work at all (Like links inside the Gmail, Inbox and Facebook apps)

Don’t be hostile to your website users and force them to get your app to use basic features of your website. In other words, don’t do this: