Dive Into Deep Linking

In the mobile world, deep linking is a technology that launches an app and opens a specific page once a user clicks a URL on a web page or in another app. We will dive into the details of implementing deep linking for your app in this article.

Why do you need deep linking?

Let’s assume you’ve published a music app. To celebrate the release of a new song, you’ve paid tons of money to run a campaign on a popular website. In your campaign, you feature a brief sample of the song – and you probably want the user to listen to the sample inside of your app rather than on your website, where they would only see the album cover. In another example, let’s say you want to regain inactive users through a sales campaign. In this campaign, users would be directed to the sale products page in your app with a single click, without having to search for it or manually type a coupon code. This is where deep links come into play: in both examples, deep linking makes these campaigns possible.

In short, deep linking brings seamless user experience and can increase your conversion rate and retention rate significantly. More information on the effects of deep linking in campaigns can be found on our company blog.

How do you implement deep links?

I won’t dive into how to implement deep links. Both scheme-based deep linking (Android and iOS) and iOS 9+ Universal Link are fully documented. The basic ideas are quite similar: associate a URL (scheme based youapp:// or universal link https://yourdomain.com/) with your app and when the URL is clicked, the system will open the app if it’s installed.

But the world isn’t perfect

You’re probably wondering, “What if someone clicks on a deep link URL but doesn’t have the app installed?” Unfortunately, they’ll either see an error message or nothing will happen. This is the problem we’re going to discuss in this article.

Deep Links for Android

Let’s assume your deep link URL is yourapp://path/, and your App’s bundle ID is com.yourapp.example.

JavaScript solution

A common and old technique to solve this problem is using iframe to load the deep link URL and having a delayed JavaScript to redirect to store:

1
2
3
4
5
6
7
8
...
<iframe style="display:none" height=0 width=0 src="yourapp://path/"></iframe>
<script>
      setInterval(function () {
              window.location.replace("http://play.google.com/store/apps/details?id=com.yourapp.example");
      }, 2000);
</script>
...

By doing this, the browser will try to load yourapp://path/ first.

  • If your app is installed, then it will be opened and the following JavaScript won’t run.
  • If your app is not installed, then nothing will happen while loading yourapp://path/. After 2 seconds, the page will be redirected by the JavaScript to to the Play Store, and the user can install the app from there.

The above code has a little problem, though – after the app is opened and the user switches back to their browser, the JavaScript may continue and redirect them back to the Play Store. So we can do some optimization by checking the time a user switches back to their browser in order to determine whether they need to be redirected to the store or not:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
<iframe style="display:none" height=0 width=0 src="yourapp://path/"></iframe>
<script>
      var start = Date.now();
      function try_close(){
          location.replace('about:blank');
      }

      function store_or_close(){
          var now = Date.now();
          if (now - start > 3000) {
              try_close();
          } else {
              window.location.replace("http://play.google.com/store/apps/details?id=com.yourapp.example");
              setInterval(try_close, 1000);
          }
      }

      setInterval(store_or_close, 2000);
</script>
...

Intent solution

Since Chrome for Android version 25 and later, the above code stopped working according to Chrome documentation. Fortunately, Google provides theIntent URL for a better solution. When a user clicks on the URL intent://path/#Intent;scheme=yourapp;package=com.yourapp.example;end, then

  • if the app is installed, it will be opened by Chrome.
  • if the app is not installed, Chrome will open Play Store.

Which solution should I use?

The Intent solution is highly recommended because it’s much simpler to implement and the user experience is more seamless. However, it requires browser support, and the Android system is unfortunately so fragmented that there are still plenty old OSes and browsers out there. Moreover, the Android WebView used by tons of apps don’t support Intent URLs by default. The following table shows which solution you should use for mainstream Android browsers:

Browser JavaScript Intent
Chrome 24 or below
Chrome 25 or above
Firefox
Android Browser
Facebook in-app Browser
Twitter in-app Browser
Other Browsers

Deep links for iOS

Assuming your deep link URL is yourapp://path/ and your app ID in app Store is 12345678.

JavaScript solution

Similar to Android, there is also a JavaScript trick for iOS:

1
2
3
4
5
6
<script>
window.location.replace("yourapp://path/");
setTimeout(function () {
  window.location.replace("https://itunes.apple.com/app/id12345678");
}, 2000);
</script>
  • if the app is installed, the first relocation code will open the app and the following script won’t run.
  • if the app is not installed, the first relocation code will do nothing and the timeout function will redirect to App Store.

But as we discovered, this script works well in iOS 8 or below with Safari but doesn’t always work with other versions. Here is the table:

Browser JavaScript
iOS 8 or below Safari
iOS Chrome
iOS 8 Facebook in-app Browser √ *
iOS 8 Twitter in-app Browser
iOS 9 or above

* partially working depends on Facebook app Version

Universal link solution

Starting with iOS 9, Apple published the universal link, which works similar to Android’s Intent but requires more setup. And moreover, since iOS 9.2, the JavaScript solution stopped working since Apple made the prompt window non-modal. You can read more about this here.

In order to enable universal links, you need to have a SSL certificated domain (https://yourdomain.com/, for example) associated with your app, and to serve a special JSON file under https://yourdomain.com/apple-app-site-association similar to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "[Team ID].[Bundle ID]",
                "paths": [ "/path1/", "/path2/*"]
            },
            {
                "appID": "[Team ID].[Bundle ID]",
                "paths": [ "*" ]
            }
        ]
    }
}

This file tells your device which path serves as deep link for which app.

Then, in XCode you need to enter applinks:yourdomain.com in your com.apple.developer.associated-domains entitlement ulink. One domain can be associated with multiple apps and vice versa.

Next, you need to adopt the UIApplicationDelegate methods for Handoff (specifically application:continueUserActivity:restorationHandler:) so that your app can receive a link and handle it appropriately.

Let’s assume you associate https://yourdomain.com/dress/* with your app by setting "paths": [ "/dress/*"] in the JSON file. When user clicks the link https://yourdomain.com/dress/1 in Safari,

  • if the app is installed, your app will be opened and https://yourdomain.com/dress/1 will be passed to UIApplicationDelegate. You can handle it there to decide which View to open.
  • if the app is not installed,https://yourdomain.com/dress/1 will be opened with Safari and you can still display the product on your website or redirect the user to App Store

Universal links sound like a perfect solution for iOS. But again, unfortunately, they have their limitations.

  • Universal links only work with Safari and Chrome
  • When another site redirects with a universal link, it works only if the click happens within Safari and Chrome. For instance, if there is a link in your Email app https://anotherDomain.com/ redirecting to the universal link https://yourDomain.com/dress/1, it won’t deeplink into your App. But if the link https://anotherDomain.com is clicked from Safari, it works.
  • Universal links won’t work if you paste the link directly into address bar.
  • Universal links won’t work if the redirect is triggered by JavaScript.
  • Universal links won’t work when you open the link programmatically inside your app (with openUrl, for instance)

Welcome to the world of deep links

Deep linking is complicated – there is no silver bullet that works in all scenarios. Fortunately, Adjust will detect all those scenarios and use the best strategy to make deep linking functional. You can read more about Adjust deep linking here and ping [email protected] if you have more questions.

Comments