top of page
Search

How I Implemented Universal Links For Apps Without a Personal Website (and Why You Should Too)

  • Writer: Rafi Saar
    Rafi Saar
  • May 27
  • 6 min read

Updated: May 28

If you’ve ever tried to set up Universal Links for your iOS apps and hit a wall because you couldn’t host the required file on your personal website — this post is for you. I recently set this up for RealMaze AR, my AR maze game, and I’ll walk you through how I made it work using Firebase Hosting.


I’ll also show you how I handled promo codes through Universal Links like this:

https://yourfirebaseapp.web.app/promo?code=XYZ123

If you want to do something similar, keep reading!



Why Use Universal Links?


Universal Links are Apple’s secure, modern way of linking into your app from the web. If your app is installed, a Universal Link takes users straight into your app — not Safari. If the app isn’t installed, the link opens your hosted fallback page (which we’ll set up to redirect to the App Store).


For me, this was essential. I wanted users to receive promo codes through shareable links. With Universal Links, I could:

• Open the app directly and extract the promo code

• Redirect users to the App Store if they didn’t have the app yet


See the Universal Link in action using an example from my game:

  • If the app isn’t yet installed on your device, this link should bring you to the App Store so you could download it.

  • And if the app is already installed, the same link will open the app and reward you with the promo prize.



Video example promoting the app using Universal Link with promo code



Step 1: Host the apple-app-site-association File on Firebase


I do have a personal web site for my apps, but I couldn’t host static files at arbitrary paths. That’s a problem because Universal Links require an exact path and filename.


So here’s what I did: used Firebase Hosting. Google’s Firebase lets you create a free project and host files at exactly the paths you need.

Set up a directory on your drive where you’ll mirror all the hosted files.

Follow Google’s instructions here on setting up Firebase Hosting: https://firebase.google.com/docs/hosting


File Content

At the root of your hosting directory, create a file called "apple-app-site-association"

With the following content:

{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "TEAMID.com.yourcompany.yourapp",
        "paths": [ "/promo/*" ]
      }
    ]
  }
}

Replace:

TEAMID with your Apple Developer Team ID

com.yourcompany.yourapp with your app’s full bundle ID

• The path /promo/* matches my promo URL format - change this to fit your own needs


🔥 Important: The file name must be exactly "apple-app-site-association" (with no file extension) and must be served with the correct application/json MIME type. Luckily, Firebase handles the MIME type automatically.



Configure Firebase Hosting to Serve the File Correctly


Firebase Hosting needs to serve your AASA file with the correct Content-Type header. To do this, modify your firebase.json file by adding a headers configuration.


Edit firebase.json:

In your firebase.json, add a headers block to ensure the AASA file is served as JSON. Here’s an example configuration:


{
   "hosting": {
    "public": "public",
    "headers": [
      {
        "source": "/apple-app-site-association",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      },
      {
        "source": "/.well-known/apple-app-site-association",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      }
    ]
  }
}

Notes:

• The first rule covers requests to https://yourfirebaseapp.web.app/apple-app-site-association.

• The second rule covers requests to https://yourfirebaseapp.web.app/.well-known/apple-app-site-association (an alternative location Apple supports).


Upload and Deploy


In Terminal, in your hosting root directory, where both apple-app-site-association and firebase.json files are stored, run the following command to deploy:

firebase deploy

Test It


Verify the file is served correctly using:


Just paste in your domain, like https://yourfirebaseapp.web.app.



Step 2: Enable Associated Domains in Xcode


Next, link your app to the hosted file.

1. In Xcode, open your app target

2. Go to Signing & Capabilities

3. Add Associated Domains

4. Under Domains, add:

applinks:yourfirebaseapp.web.app

That’s it — no https://, no slashes.



Step 3: Handle the Universal Link in Code


When a user opens the link in Safari and your app is installed, iOS will pass control to your app.

Handle this in "AppDelegate.swift":


func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {

     guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
              let incomingURL = userActivity.webpageURL else { return false }

     // Example URL: https://yourfirebaseapp.web.app/promo?code=XYZ123
        if let components = URLComponents(url: incomingURL, resolvingAgainstBaseURL: false),
           let queryItems = components.queryItems,
           let promoCode = queryItems.first(where: { $0.name == "code" })?.value {
            // Process the promo code
            handlePromoCode(promoCode)
            return true
        }
        return false
    }

I wanted users to get a bonus if they clicked a special promo link. So I extracted the promo code from the URL and called handlePromoCode(_:), passing the promo code to my Firestore handler (as you've guessed, I manage all my promo codes using Firestore). This in turn has its own logic to validate the promo code and present some animation to the user. I’m skipping those private parts here, but this is where you’d plug in your own logic to validate and reward the promo code the way you want.



Test Your Setup


At this point, you can:

• Click a link like https://yourfirebaseapp.web.app/promo?code=XYZ123

• If your app is installed, it opens automatically and AppDelegate handles it

• If not, it opens your Firebase-hosted web page — and that’s the problem we’ll fix next



Step 4: Handle Users Without the App (Redirect to App Store)


You don’t want users seeing a blank Firebase page if they don’t have your app yet. You want them in the App Store!


To fix that, edit your "firebase.json" to redirect all paths to your App Store link when it’s not handled as a Universal Link. Add a “redirects” block giving your App Store app’s page as the destination. Here’s the fully updated "firebase.json" file (if you only add the new rows at the bottom, make sure not to forget to add a comma at the end of the “headers” block before the “rewrites” - see comma in red below):


{
   "hosting": {
    "public": "public",
    "headers": [
      {
        "source": "/apple-app-site-association",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      },
      {
        "source": "/.well-known/apple-app-site-association",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      }
    ],
    "rewrites": [],
    "redirects": [
      {
        "source": "/promo**",
        "destination": "https://apps.apple.com/us/app/<your-app-name>/id<your-app-id>",
        "type": 302
      }
    ]
  }
}

So if iOS doesn’t open the app (because it’s not installed), Firebase will automatically redirect to the App Store.

Just make sure to replace with your own app's App Store link.


Now once again deploy this change to Firebase:

firebase deploy --only hosting


What’s Coming Next


There’s one major edge case I haven’t covered here: links clicked inside apps like Instagram, Facebook, or Twitter. These apps often open links in internal WebViews, not Safari — so Universal Links don’t work.


In the next blog post, I’ll show how I detected that case and redirected users to Safari to force the Universal Link to work. It’s a bit hacky, but effective — and a must-have for social media promo links.


Stay tuned for that 👇

And if you try this setup yourself, let me know how it goes!



Sources:



Kommentare


© 2025 Syncopa

  • Instagram
  • TikTok
  • Youtube
  • Threads
  • X
  • Facebook
  • Mastodon_logotype_smaller
bottom of page