Universal Link — what it is, how it works, and setup

Author: IT Sectr Published: 2026-05-14 Reading time: 9 min

Universal Link is an Apple mechanism (iOS 9+) that allows opening web links directly in the app, bypassing Safari. If the app is not installed, the link seamlessly opens in the browser. The term was introduced by Apple in 2015 at WWDC as part of Handoff and the Continuity ecosystem. According to Apple Developer, Universal Link provides a unified user experience between the web and the native app without choice dialogs.

Key Takeaways

  • Universal Link — a standard https link that opens the app (iOS 9+) or the website (fallback)
  • apple-app-site-association — a JSON file on the server confirming the domain's association with the app
  • Security — only the domain owner can associate links, preventing scheme interception
  • Single URL — one link works both as a webpage and as an entry point to the app
  • Handoff and Spotlight — Universal Link integrates with Apple search and cross-device continuity

Universal Link is a standard HTTPS link like https://example.com/page that, when tapped on an iOS device, opens the installed app instead of Safari. The main difference from Custom URL Scheme: Universal Link does not require registering a custom scheme (myapp://) — it uses a regular domain. This eliminates the URL Scheme hijacking problem, where any app can register the same scheme.

Apple introduced Universal Link at WWDC 2015 as part of iOS 9. The mechanism became part of the Handoff and Spotlight ecosystem: Universal Link works not only in the browser but also in Spotlight search results, Mail, Messages, and other system apps. Additionally, Universal Link is supported on watchOS and macOS — a user can open an app on iPhone via a link on Mac.

The key advantage: single URL. The developer does not manage two different links (one for the web, another for the app). Universal Link is one and the same https link. If the app is installed — it opens the app. If not — the same link opens in Safari as a regular webpage. This provides an ideal fallback without losing traffic.

The Universal Link mechanism consists of three stages: association verification, link handling, and browser fallback. Each stage is critical for proper operation. If the association is not configured, iOS handles the link as a normal Safari redirect. Let us examine each stage in detail.

Association Verification

On the first tap on a link, iOS downloads the apple-app-site-association file from the server at https://example.com/.well-known/apple-app-site-association. The file contains JSON with the app's Team ID and Bundle ID, as well as a list of paths that the app should open. iOS caches this file and periodically checks its freshness (on app update, device restart).

The JSON file apple-app-site-association must be accessible via HTTPS without redirects. The server must return Content-Type: application/json. Importantly, the file has no .json extension — iOS looks for it strictly at /.well-known/apple-app-site-association. Apple also recommends adding Universal Link support in CDN and verifying that the file is not blocked by robots.txt.

json
// apple-app-site-association — minimal configuration
{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "TEAMID.com.example.app",
                "paths": ["/product/*", "/profile/*", "/search"]
            }
        ]
    }
}

appID is formed as Team ID + Bundle ID (TEAMID.com.example.app). paths is an array of URL patterns that the app should handle. You can use *, ? and NOT notation: ["NOT /admin/*", "/product/*"]. Paths are checked in order of listing: the first match determines behavior. If the path does not match — the link opens in Safari.

Link Handling

After successful association verification, iOS passes the link to the app. Handling is done in AppDelegate via the application(_:continue:restorationHandler:) method for NSUserActivity, or in SceneDelegate via scene(_:continue:). The developer receives an NSUserActivity object with type NSUserActivityTypeBrowsingWeb, extracts the URL, and navigates to the corresponding screen.

swift
// Universal Link handling in AppDelegate
func application(
    _ application: UIApplication,
    continue userActivity: NSUserActivity,
    restorationHandler: @escaping UIUserActivityRestorationHandler
) -> Bool {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
          let url = userActivity.webpageURL
    else { return false }

    // Navigate to screen according to URL
    DeepLinkRouter.navigate(to: url)
    return true
}

DeepLinkRouter in the example above is a custom class that parses the URL and calls the corresponding navigation coordinator. For SwiftUI, handling is done via the onOpenURL method or the environment(\.openURL) modifier. It is important to handle not only foreground launch but also the case when the app was not running (cold start): Universal Link opens the app via launch options in this case.

Browser Fallback

If the app is not installed, iOS automatically opens the Universal Link in Safari. This is a key difference from Custom URL Scheme: the user does not see an error. Fallback is the standard webpage of the same domain. The developer can place an App Store link, product information, or alternative content on this page.

Important: the fallback cannot be customized at the iOS level. iOS simply opens the URL in Safari. To show different content for users with and without the app installed, use Smart App Banner (a meta tag for Safari that offers to open the app) or JavaScript app detection. Apple also provides SKAdNetwork for installation attribution via Universal Link.

Universal Link and traditional Deep Link (Custom URL Scheme) solve the same problem but fundamentally differ in architecture and security. Custom URL Scheme is a custom protocol (myapp://) registered in Info.plist. Any app can register the same scheme (myapp://), and iOS cannot determine which one is “real.” This is called URL Scheme hijacking.

Universal Link solves the hijacking problem through domain verification. Only the domain owner can place apple-app-site-association on their server, confirming the connection to a specific Bundle ID. Two apps cannot register the same Universal Link: if a conflict arises, iOS gives priority to the last installed app or opens Safari.

Another difference: Fallback. Custom URL Scheme has no fallback — if the app is not installed, the browser shows an error. Universal Link opens the website. A single URL means that the SEO value of the link is preserved (Google indexes the link), and a user with any device receives relevant content. Universal Link is an evolutionary step from deep link to unified link.

CharacteristicCustom URL SchemeUniversal Link
Formatmyapp://pathhttps://domain/path
VerificationNoneapple-app-site-association
SecurityVulnerable to hijackingOnly domain owner
FallbackErrorWebsite in Safari
iOS versioniOS 3+iOS 9+

Setup of Universal Link includes server-side and client-side parts. Server-side — placing the apple-app-site-association file at https://domain/.well-known/apple-app-site-association. Client-side — registering the domain in Associated Domains in Xcode (Capabilities → Associated Domains → applinks:example.com). After that, the app automatically receives all Universal Links for the specified domain.

Setup steps:

  1. Create apple-app-site-association with the correct appID (TeamID.BundleID) and paths
  2. Place the file on the server at /.well-known/ without a .json extension
  3. Verify availability: curl https://domain/.well-known/apple-app-site-association
  4. Add the domain to Associated Domains (Xcode Capabilities)
  5. Implement handling via NSUserActivity (AppDelegate or SceneDelegate)
  6. Test on a real device (the simulator does not verify association)

Debugging Universal Link is a common headache for iOS developers. Main reasons for non-working links: apple-app-site-association file is not accessible via HTTPS, incorrect appID, Content-Type is not application/json, redirect from /.well-known path, caching of the old file version (reset via Settings → Developer → Associated Domains Development). Apple provides the Validation Checker tool in Apple Developer Console for testing association.

Branch and other MMP platforms simplify Universal Link setup: they generate apple-app-site-association automatically and host it on their domain. The developer just needs to add the Branch domain to Associated Domains and integrate the SDK. This is especially convenient for startups that do not have their own server infrastructure for hosting the AASA file.

Limitations and Compatibility

Universal Link has several limitations. First: the apple-app-site-association file must be accessible strictly via HTTPS (HTTP is not supported). Second: the link must point to the same domain specified in Associated Domains. Cross-domain Universal Links do not work — each domain requires a separate entry in Capabilities and a separate AASA file. Third: Universal Link does not work in WKWebView — only in Safari and system components.

Compatibility: iOS 9.0+ (Universal Link), watchOS 6.0+ (Handoff Universal Link), macOS 10.15+ (Catalyst and Mac apps). On older iOS versions, the link opens in Safari. This means that on iOS 8 (less than 1% of devices) Universal Link will not work. It is recommended to also support Custom URL Scheme as a fallback for older devices if your audience includes users with outdated versions.

iOS 16+ changes: Apple improved Universal Link handling for SwiftUI. A new environment(\.openURL) modifier with deferred processing capability was introduced. iOS 16 also allows opening Universal Links in the app even through SFSafariViewController. For iOS 16 users, it is recommended to fully switch to SwiftUI Universal Link handling, keeping AppDelegate code only for backward compatibility.

Frequently Asked Questions

How is Universal Link different from Custom URL Scheme?

Universal Link uses a standard HTTPS URL and is verified through a file on the server. Custom URL Scheme uses a custom protocol (myapp://) without verification, making it vulnerable to interception by another app that registered the same scheme.

Where to place apple-app-site-association?

The file is placed at the root of the HTTPS server at /.well-known/apple-app-site-association (without .json extension). The server must return Content-Type: application/json. Important: no redirects, the file must be directly accessible.

Why is Universal Link not opening the app?

Main reasons: incorrect Team ID or Bundle ID in the AASA file, file not accessible via HTTPS, redirect, wrong Content-Type, caching of the old version. Check through Developer → Associated Domains Development and reset the cache by restarting the device.

Can I use Universal Link without a website?

No — Universal Link requires an HTTPS server hosting apple-app-site-association. Without a domain, Universal Link does not work. Alternatives: Custom URL Scheme (less secure) or third-party services (Branch, Firebase) with their own domain.

Does Universal Link work on Android?

No — Universal Link is an exclusive Apple technology for iOS, iPadOS, watchOS, and macOS. On Android, the equivalent is called App Link (Android 6.0+), which uses Digital Asset Links (assetlinks.json) instead of apple-app-site-association.

Summary

  • Universal Link — an https link that opens the app on iOS 9+ or the website in Safari as a fallback
  • apple-app-site-association — a JSON file on the server verifying the domain's association with the app
  • Security — unlike Custom URL Scheme, Universal Link is protected from interception by third-party apps
  • Single URL — one link works for both users who have and have not installed the app
  • Handoff and Spotlight — Universal Link integrates with the Apple Continuity ecosystem
  • Setup includes server-side (AASA file) and client-side (Associated Domains + NSUserActivity)
  • Testing only on a real device — the simulator does not verify domain association

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also