If your app uses Universal Links and you have not revisited the setup since iOS 16, there are real changes to deal with. iOS 17 brought a revised AASA format, stricter CDN caching behavior, new developer-facing diagnostics, and some SwiftUI quality-of-life improvements. None of these changes break Universal Links outright, but ignoring them can mean links that silently fall back to Safari instead of opening your app.
This article covers what changed, why Apple made those changes, and what you need to update.
A Quick Refresher on How Universal Links Work
When a user taps a link, iOS checks whether any installed app claims that domain. The claim is established through a two-part contract: your app declares the domain in its entitlements, and your server hosts an Apple App Site Association (AASA) file at https://yourdomain.com/.well-known/apple-app-site-association.
Apple's servers fetch and cache that AASA file when the app is installed (and periodically after that). iOS then uses the cached copy to decide whether to route the link to your app or fall through to Safari.
For a deeper look at the fundamentals, our complete guide to Universal Links covers everything from tap to app open, or see the Tolinku Universal Links concept guide for the technical reference.
What Changed in iOS 17
1. The components Syntax Replaces paths
The biggest format change in iOS 17 is the introduction of a components array inside each app entry, alongside deprecation of the older paths array. The two can coexist in the same file, so you do not need to drop paths immediately, but components is the format Apple will continue developing.
Here is what the older paths format looks like:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAMID.com.example.app",
"paths": [
"/products/*",
"/checkout",
"NOT /admin/*"
]
}
]
}
}
And here is the equivalent using components:
{
"applinks": {
"details": [
{
"appIDs": ["TEAMID.com.example.app"],
"components": [
{
"/": "/products/*",
"comment": "Matches all product pages"
},
{
"/": "/checkout"
},
{
"/": "/admin/*",
"exclude": true
}
]
}
]
}
}
A few things to notice. First, appID (singular) becomes appIDs (plural array), which lets you list multiple app identifiers in one block without duplicating the component rules. Second, exclusions move from the NOT /path string syntax to an explicit "exclude": true key, which is much less error-prone. Third, you can also match on query parameters and fragment identifiers using "?" and "#" keys respectively:
{
"/": "/share/*",
"?": { "ref": "?*" },
"comment": "Only match share links with a ref parameter"
}
Apple's Supporting Associated Domains documentation has the full reference for component matching syntax.
2. CDN Caching Is Now More Aggressive
Before iOS 17, Apple's CDN fetched your AASA file and cached it for up to 24 hours. Starting with iOS 17, Apple tightened the caching rules in two directions: the TTL can be longer under stable conditions, but Apple also introduced a faster propagation path for apps submitted through the App Store. For a detailed look at how Apple's CDN fetches and caches your AASA file, see Apple CDN validation for Universal Links.
When you submit a new build to App Store Connect, Apple re-fetches your AASA file as part of the submission pipeline. This means that for App Store distributed apps, changes to your AASA file now reach users faster after a new app release, even if the CDN cache has not expired organically.
The practical implication: if you are testing AASA changes during development, you cannot rely on cache expiry alone. Use TestFlight and the developer diagnostics described below. In production, coordinate AASA file changes with an app release when possible so the re-fetch happens at a predictable time.
Your AASA endpoint must continue to return Content-Type: application/json (not application/pkcs7-mime, which was required years ago and has been optional since iOS 9.3.1). It must be served over HTTPS with a valid certificate.
3. Alternate Modes Are Now Fully Supported
The applinks service type has always been the main use case, but iOS 17 brings stable, documented support for additional modes in the Associated Domains entitlement:
webcredentialsfor AutoFill credential sharingactivitycontinuationfor Handoffappclipsfor App Clips
These were available before, but the AASA format updates mean they can now live alongside applinks in a single file with cleaner syntax. If you are using any of these services, verify your file structure against the Associated Domains WWDC 2023 session notes.
4. New Developer Tools for Diagnostics
iOS 17 ships a proper diagnostic flow for Universal Links in Developer Mode. To access it:
- Go to Settings > Developer > Universal Links.
- Enable "Diagnostics."
- Tap any link in Safari or Mail.
iOS will show you in real time whether it matched the link to an app, which AASA rule matched, and why a link fell through to Safari if it did. Before iOS 17, debugging this required Console.app on a Mac and hunting for swcd log entries, which was tedious.
For command-line debugging, the swcutil tool also gained more readable output. Running xcrun swcutil display on a connected device shows you the full approved-domains list and the AASA payload Apple has cached for each app.
Apple's WWDC 2023 "What's new in universal links" session walks through the new diagnostic tooling in detail.
5. Safari Behavior Changes
In iOS 17, Safari became more selective about showing the Smart App Banner and the "Open in App" prompt for Universal Link domains. Safari now checks the same AASA cache that iOS uses for link routing, and if your AASA file is malformed or missing required fields, Safari will suppress the banner entirely rather than showing it with a fallback.
This is a stricter enforcement of existing rules, not a new policy, but it has caught a lot of teams off guard. If your Smart App Banner disappeared after an iOS 17 update, your AASA file is worth checking first.
Safari also no longer shows the "Open in App" prompt for links that land on pages explicitly excluded from Universal Link handling (via "exclude": true in components or NOT in paths). This is correct behavior, but if your exclusions were too broad, you may have inadvertently suppressed the prompt on pages where you want it.
Migrating Your AASA File
Here is a migration checklist for teams moving from the paths format to components.
Step 1: Add components alongside paths.
Keep paths in place for devices running iOS 16 and earlier. Add a components array for iOS 17+ behavior. iOS 17 will use components and ignore paths when both are present; older versions will use paths.
Step 2: Convert exclusions.
Replace every "NOT /some/path" entry in paths with a matching component entry that has "exclude": true. Be precise. The NOT syntax always did prefix matching, which was sometimes too broad.
Step 3: Switch to the appIDs array.
Replace "appID": "TEAMID.bundle" with "appIDs": ["TEAMID.bundle"]. If you support multiple targets (for example, a main app and an App Clip), list them both here instead of duplicating the entire entry.
Step 4: Validate the file.
Apple's Associated Domains validator accepts your domain and checks the AASA file format and reachability. Our AASA file setup guide walks through common validation errors and hosting requirements, and the Tolinku developer guide for Universal Links covers the full specification.
Step 5: Test on a real device.
Simulator does not fully replicate Universal Link behavior. Use a physical device with Developer Mode enabled and the new diagnostics in Settings. Confirm that your intended paths open the app and your excluded paths fall through to Safari correctly.
Step 6: Submit a new build.
Once your AASA file is updated on the server, submit a new build to App Store Connect to trigger Apple's re-fetch of your file. This shortens the propagation delay significantly.
SwiftUI Deep Link Handling
iOS 17 also brought improvements to onOpenURL and the new NavigationStack-based routing patterns. If you are still using UIApplicationDelegate's application(_:continue:restorationHandler:) to handle incoming Universal Links, you are not doing anything wrong, but SwiftUI now has cleaner native primitives.
The onOpenURL modifier on a NavigationStack or root view handles Universal Links without needing to bridge through UIKit:
NavigationStack(path: $navigationPath) {
ContentView()
.navigationDestination(for: AppRoute.self) { route in
routeView(for: route)
}
}
.onOpenURL { url in
if let route = AppRoute(url: url) {
navigationPath.append(route)
}
}
The key improvement in iOS 17 is that onOpenURL now fires correctly when the app is launched cold from a Universal Link, not just when the app is already in the foreground. Previous versions of SwiftUI had a race condition where cold-launch Universal Links would sometimes arrive before the view hierarchy was ready to handle them. That race is resolved in iOS 17.
If you are implementing deferred deep linking (routing users through an app install to a specific screen), the patterns described in the Tolinku deep linking features guide are still the right approach since iOS itself does not carry the link through installation.
What You Do Not Need to Change
A few things that caused concern when iOS 17 landed are actually non-issues.
The "apps": [] key inside applinks was always a legacy placeholder and can be omitted entirely in the new format. If it is still in your file, that is fine; iOS ignores it.
The file location has not changed. /.well-known/apple-app-site-association is still the canonical path, and the root-level path /apple-app-site-association still works as a fallback.
The entitlements format in Xcode has not changed. Associated Domains are still configured the same way in your target's Signing and Capabilities settings.
Summary
For a broader comparison of how Universal Links behavior has evolved across iOS releases, see our article on Universal Links iOS version differences.
iOS 17 did not break Universal Links, but it introduced enough changes that a passive setup can start showing cracks. The components syntax is cleaner and more powerful than paths, the new diagnostic tools make debugging far less painful, and the App Store re-fetch shortens the propagation delay when you update your AASA file. If you have not revisited your setup since 2022 or 2023, now is a good time to run through the migration checklist above and validate your AASA file format against Apple's current documentation.
The Apple developer documentation for Supporting Associated Domains and the WWDC 2023 Universal Links session are the authoritative references for all of the changes covered here.
Get deep linking tips in your inbox
One email per week. No spam.