How to Test Your Universal Links Locally (iOS)

Hi, in this article I'll explain how you can setup and test your universal links on iOS, the Android part will be another article.

An overview of universal links

Universal links have one goal: To open the most suitable frontend for a specific domain available on the user's platform

For example, let's say you have a website hosted on . You want to provide a better experience for mobile user and you decide to develop an app for Android and iOS called SN App. If a user clicks on a link for your website on his smartphone, it would be friendlier to open the link in the SN App (if installed) than the mobile version of the website, wouldn't it?

That's what universal links are here for: they create an association between an app and a domain telling the OS how certain links should be handle. But you cannot just tell in your app to handle all links. Imagine you could publish an app and every Facebook link would open this app ?

No, for the association to be valid, you need two things :

  • An app wanting to handle link
  • A server hosting your website allowing your app to do so via a configuration file

Here is a drawing to help you understand the mechanics:

Schema article Universal Links (2)

1: SN App asks Apple to have the permission to handle links from

2: Apple checks with if BAMApp is declared as a reliable source

3: confirms the authenticity of BAMApp

4: Apple update its list of reliable sources for and authorize BAMApp

Now we'll see how we can simulate this flow locally.


Ok so we need three things to check our workflow :

  • A configuration file (apple-app-site-association)
  • A server with a domain name exposing our file over https
  • An app wanting to handle links from this domain

Configuration file

The apple-app-site-association is a JSON like file but without any extension. Here is an example :

++pre>++code>++code class="has-line-data" style="background-color: transparent;" data-line-start="63" data-line-end="75">{
 "applinks": {
   "apps": [],
   "details": [
       "appID": "",
       "paths": ["*"]
++/code class=++/code>++/pre>

The key ++code>applinks++/code> indicates we are about to declare all universal links configuration.

In ++code>details++/code>, we put an array of objects containing :

  • ++code>appID++/code>: <YOUR_IOS_TEAM_ID>.<YOUR_APP_ID>
  • ++code>paths++/code>: a regex of what links you want to intercept, here we want to handle all links

Now that we have our apple-app-site-association file, we must expose it on a server that can be reached by Apple.


We need to expose our configuration file: here enters ngrok

ngrok is a tool that allows you to expose publicly your machine on a random domain.

Install it and simply type

++pre>++code>++code class="has-line-data" style="background-color: transparent;" data-line-start="94" data-line-end="96">./ngrok http 80++/code>++/pre>

Capture d'e?cran 2020-08-07 a? 17.54.31

Now my machine is accessible over https on the domain

All we need is a node and express instance to serve our file. The file should be accessible on the endpoint

++pre>++code>++code class="has-line-data" style="background-color: transparent;" data-line-start="102" data-line-end="104">\<DOMAIN_NAME>/.well-known/apple-app-site-association

Generate a project with

++pre>++code>++code class="has-line-data" style="background-color: transparent;" data-line-start="108" data-line-end="110">yarn init

and add express

++pre>++code>++code class="has-line-data" style="background-color: transparent;" data-line-start="114" data-line-end="116">yarn add express

Copy-paste your apple-app-site-association in your folder, create an index.js file, and paste the following code :

++pre>++code>++code class="has-line-data" style="background-color: transparent;" data-line-start="120" data-line-end="129">var express = require('express');
var server = express();

server.get('/.well-known/apple-app-site-association', function(request, response) {
 response.sendFile(__dirname +  '/apple-app-site-association');


Run your server with

++pre>++code>++code class="has-line-data" style="background-color: transparent;" data-line-start="133" data-line-end="135">node index.js

Now we just have to associate our app with the ngrok domain and we'll be good to go!

App configuration

First, go to the official documentation to allow your app to handle universal link.

Open your project in Xcode and go in the "Signing & Capabilities" tab. Under "Associated Domains", click on the plus sign and rename the associated domain: ++code style="background-color: #f9f2f4;">applinks:<NGROK_DOMAIN_NAME>++/code>

++code>style="background-color: #f9f2f4;">

Capture d'e?cran 2020-08-17 a? 18.15.14


++code>style="background-color: #f9f2f4;">++/code>

To check that your app configuration works, build your app. When the app is launching, you should see Apple trying to access the apple-app-site-association file (see below)

Capture d'e?cran 2020-08-07 a? 18.06.43

Now let's test a universal link!


To test you could copy paste a link in the messaging app in your simulator/device and click on it but Apple provides a very useful command line

++pre>++code>++code class="has-line-data" style="background-color: transparent;" data-line-start="155" data-line-end="157">xcrun simctl openurl booted

You app should open :)

After that, you can try different URLs and decide how to handle them in your app


This way of testing will not be useful for every use case but it allows you to quickly check if your configuration file is ok and you don't need a server instance to do so. I'm still learning a lot on universal links so if you have any comments, improvements in this article, feel free!

Hope you liked it, I'll try to write a piece on how to configure on Android soon.

Développeur mobile ?

Rejoins nos équipes