{"id":2054,"date":"2026-08-17T09:00:00","date_gmt":"2026-08-17T14:00:00","guid":{"rendered":"https:\/\/tolinku.com\/blog\/?p=2054"},"modified":"2026-03-07T03:50:30","modified_gmt":"2026-03-07T08:50:30","slug":"universal-links-ios-version-differences","status":"publish","type":"post","link":"https:\/\/tolinku.com\/blog\/universal-links-ios-version-differences\/","title":{"rendered":"Universal Links Across iOS Versions: A Compatibility Guide"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Universal Links have been available since iOS 9, but their behavior has changed with nearly every major iOS release. AASA file format changes, new validation rules, CDN caching behavior, and Safari interaction quirks all vary by version. If you support a range of iOS versions, you need to know what works where.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This article documents the significant Universal Links changes across iOS versions so you can test and configure accordingly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For Universal Links fundamentals, see <a href=\"https:\/\/tolinku.com\/blog\/universal-links-everything-you-need-to-know\/\">universal links: everything you need to know<\/a>. For iOS 17 specifically, see <a href=\"https:\/\/tolinku.com\/blog\/universal-links-ios-17-changes\/\">Universal Links changes in iOS 17<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">iOS 9: The Beginning<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">iOS 9 (2015) introduced Universal Links. The initial implementation established the core concepts that remain today:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Apps declare supported domains via the Associated Domains entitlement.<\/li>\n<li>The domain hosts an AASA file at <code>\/.well-known\/apple-app-site-association<\/code> or <code>\/apple-app-site-association<\/code>.<\/li>\n<li>iOS downloads the AASA file when the app is installed and checks it periodically.<\/li>\n<li>Tapping a matching URL opens the app instead of Safari.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The original AASA format used <code>appID<\/code> (singular) and a <code>paths<\/code> array:<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;applinks&quot;: {\n    &quot;apps&quot;: [],\n    &quot;details&quot;: [\n      {\n        &quot;appID&quot;: &quot;TEAMID.com.example.app&quot;,\n        &quot;paths&quot;: [&quot;\/product\/*&quot;, &quot;\/category\/*&quot;]\n      }\n    ]\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>apps<\/code> key was required to be an empty array. Apple&#39;s documentation at the time: <a href=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/General\/Conceptual\/AppSearch\/UniversalLinks.html\" rel=\"nofollow noopener\" target=\"_blank\">Support Universal Links<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Key Behaviors in iOS 9<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>AASA file downloaded directly from your domain (no Apple CDN).<\/li>\n<li>The file had to be served with <code>Content-Type: application\/json<\/code>.<\/li>\n<li>No support for query parameter or fragment matching.<\/li>\n<li>WKWebView did not dispatch Universal Links to the system.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">iOS 10-11: Stability<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">iOS 10 and 11 did not introduce major changes to Universal Links behavior. The core functionality remained the same. Notable points:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>iOS 11 introduced SFAuthenticationSession<\/strong> (later replaced by ASWebAuthenticationSession) for OAuth flows, reducing the need to use SFSafariViewController for authentication. See <a href=\"https:\/\/tolinku.com\/blog\/sfsafariviewcontroller-deep-links\/\">SFSafariViewController and deep links<\/a>.<\/li>\n<li><strong>Intelligent Tracking Prevention (ITP)<\/strong> in iOS 11 Safari affected third-party cookie behavior, which impacted some deep linking attribution flows that relied on cross-domain cookies.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">iOS 13: The Modern AASA Format<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">iOS 13 was the biggest change since the introduction of Universal Links. Apple introduced the modern AASA format with the <code>components<\/code> array:<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;applinks&quot;: {\n    &quot;details&quot;: [\n      {\n        &quot;appIDs&quot;: [&quot;TEAMID.com.example.app&quot;],\n        &quot;components&quot;: [\n          { &quot;\/&quot;: &quot;\/product\/*&quot;, &quot;comment&quot;: &quot;Product pages&quot; },\n          { &quot;\/&quot;: &quot;\/admin\/*&quot;, &quot;exclude&quot;: true, &quot;comment&quot;: &quot;Exclude admin&quot; }\n        ]\n      }\n    ]\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">What Changed<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>appIDs<\/code> (plural)<\/strong> replaced <code>appID<\/code> (singular). You can now list multiple app IDs in a single entry.<\/li>\n<li><strong><code>components<\/code> array<\/strong> replaced <code>paths<\/code>. Each component is an object with a <code>\/<\/code> key for the path pattern.<\/li>\n<li><strong>Exclusions<\/strong> use <code>&quot;exclude&quot;: true<\/code> instead of the <code>NOT<\/code> prefix.<\/li>\n<li><strong>Query parameter matching<\/strong> via the <code>?<\/code> key in components.<\/li>\n<li><strong>Fragment matching<\/strong> via the <code>#<\/code> key in components.<\/li>\n<li><strong><code>comment<\/code> field<\/strong> for documentation within the AASA file.<\/li>\n<li><strong>Scene-based lifecycle.<\/strong> Apps using <code>UIWindowSceneDelegate<\/code> receive Universal Links via <code>scene(_:continue:)<\/code> instead of the app delegate method. Both still work.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Backward Compatibility<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The legacy format is still supported on iOS 13+. If you need to support iOS 9-12, you can include both formats in the same AASA file. iOS will use the format it understands:<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;applinks&quot;: {\n    &quot;apps&quot;: [],\n    &quot;details&quot;: [\n      {\n        &quot;appID&quot;: &quot;TEAMID.com.example.app&quot;,\n        &quot;paths&quot;: [&quot;\/product\/*&quot;]\n      },\n      {\n        &quot;appIDs&quot;: [&quot;TEAMID.com.example.app&quot;],\n        &quot;components&quot;: [\n          { &quot;\/&quot;: &quot;\/product\/*&quot; }\n        ]\n      }\n    ]\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For details on the modern format, see <a href=\"https:\/\/tolinku.com\/blog\/aasa-wildcards-and-paths\/\">AASA wildcards and path matching<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">iOS 14: Apple CDN and App Clips<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">iOS 14 introduced two significant changes:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Apple CDN for AASA Files<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Starting with iOS 14, Apple&#39;s CDN fetches and caches AASA files from your domain. Devices no longer download the AASA file directly from your server. Instead:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Your server hosts the AASA file.<\/li>\n<li>Apple&#39;s CDN (<code>app-site-association.cdn-apple.com<\/code>) periodically fetches it.<\/li>\n<li>iOS devices download the cached version from Apple&#39;s CDN.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">This improved reliability (your server being down does not break Universal Links for already-installed apps) but introduced caching delays. Changes to your AASA file may take hours to days to propagate through Apple&#39;s CDN.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can check Apple&#39;s cached version:<\/p>\n\n\n\n<pre><code>https:\/\/app-site-association.cdn-apple.com\/a\/v1\/yourdomain.com\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For CDN caching details, see <a href=\"https:\/\/tolinku.com\/blog\/cdn-and-aasa-caching\/\">CDN and AASA caching<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">App Clips<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">iOS 14 also introduced App Clips, which share the AASA infrastructure. The AASA file gained an <code>appclips<\/code> section alongside <code>applinks<\/code>. See <a href=\"https:\/\/tolinku.com\/blog\/universal-links-vs-app-clips\/\">Universal Links vs App Clips<\/a> for a comparison.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">iOS 15: Managed Associated Domains<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">iOS 15 added support for managed Associated Domains via MDM (Mobile Device Management). This is relevant for enterprise apps:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>MDM profiles can configure Associated Domains for managed apps.<\/li>\n<li>This allows enterprise apps distributed outside the App Store to use Universal Links.<\/li>\n<li>The <code>managed<\/code> key in the AASA file&#39;s <code>components<\/code> controls which paths are available to managed apps.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Apple&#39;s documentation: <a href=\"https:\/\/developer.apple.com\/documentation\/xcode\/supporting-associated-domains\" rel=\"nofollow noopener\" target=\"_blank\">Supporting Associated Domains<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">iOS 16: Developer Mode and Alternate Modes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">iOS 16 introduced:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Developer Mode requirement.<\/strong> On iOS 16+, testing Universal Links on a physical device requires Developer Mode to be enabled in Settings &gt; Privacy &amp; Security.<\/li>\n<li><strong>Alternate mode for Associated Domains.<\/strong> The <code>?mode=developer<\/code> flag for the Associated Domains entitlement allows bypassing Apple&#39;s CDN validation during development:<\/li>\n<\/ul>\n\n\n\n<pre><code>applinks:yourdomain.com?mode=developer\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In developer mode, iOS fetches the AASA file directly from your server instead of Apple&#39;s CDN, making development and testing faster.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For testing approaches, see <a href=\"https:\/\/tolinku.com\/blog\/testing-universal-links\/\">testing Universal Links<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">iOS 17: Stricter Validation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">iOS 17 brought the most significant tightening of Universal Links validation since iOS 14. Key changes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Stricter AASA validation.<\/strong> iOS 17 is less forgiving of AASA formatting issues that older versions tolerated.<\/li>\n<li><strong>HTTPS enforcement.<\/strong> The AASA file must be served over HTTPS with a valid certificate. Self-signed certificates no longer work in production.<\/li>\n<li><strong>Content-Type requirements.<\/strong> The AASA file must be served with <code>Content-Type: application\/json<\/code>. Some servers that previously served it with <code>application\/octet-stream<\/code> saw breakage.<\/li>\n<li><strong>CDN refresh behavior changes.<\/strong> The frequency and timing of Apple CDN refreshes changed, requiring developers to be more deliberate about AASA updates.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For detailed iOS 17 changes, see <a href=\"https:\/\/tolinku.com\/blog\/universal-links-ios-17-changes\/\">Universal Links changes in iOS 17<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">iOS 18: Continued Refinement<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">iOS 18 continued the trend of incremental improvements:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Improved CDN update propagation.<\/strong> Apple reduced the delay between AASA file changes and CDN cache updates.<\/li>\n<li><strong>Better error reporting.<\/strong> Console logs for Universal Link failures became more descriptive, making debugging easier.<\/li>\n<li><strong>SwiftUI improvements.<\/strong> The <code>onOpenURL<\/code> modifier in SwiftUI received better integration with the scene lifecycle.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For SwiftUI-specific handling, see <a href=\"https:\/\/tolinku.com\/blog\/universal-links-with-swiftui\/\">Universal Links with SwiftUI<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Version Compatibility Matrix<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Feature<\/th>\n<th>iOS 9-12<\/th>\n<th>iOS 13<\/th>\n<th>iOS 14<\/th>\n<th>iOS 15<\/th>\n<th>iOS 16<\/th>\n<th>iOS 17+<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Legacy AASA format<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Modern AASA format<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Query\/fragment matching<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Apple CDN caching<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Developer mode bypass<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>App Clips integration<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Managed domains (MDM)<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Strict AASA validation<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Practical Recommendations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>If you support iOS 13+<\/strong> (the majority of active devices), use the modern AASA format exclusively. The <code>components<\/code> array is more expressive and better documented.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>If you still support iOS 12 or earlier<\/strong>, include both legacy and modern format entries in your AASA file. iOS will use the format it understands.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Always test on the oldest iOS version you support.<\/strong> AASA parsing differences between versions can cause Universal Links to work on iOS 17 but fail on iOS 14.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Use developer mode during development.<\/strong> The <code>?mode=developer<\/code> flag (iOS 16+) bypasses CDN caching and makes iteration faster.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Monitor Apple&#39;s CDN.<\/strong> After updating your AASA file, check <code>app-site-association.cdn-apple.com<\/code> to verify the update propagated. See <a href=\"https:\/\/tolinku.com\/blog\/cdn-and-aasa-caching\/\">CDN and AASA caching<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tolinku for Cross-Version Compatibility<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/tolinku.com\/features\/deep-linking\">Tolinku<\/a> generates AASA files that are compatible across all supported iOS versions. The platform handles format differences, ensuring your deep links work whether the user is on iOS 14 or iOS 18. See the <a href=\"https:\/\/tolinku.com\/docs\/developer\/universal-links\/\">Universal Links developer guide<\/a> for setup details, or the <a href=\"https:\/\/tolinku.com\/docs\/troubleshooting\/ios\/\">iOS troubleshooting guide<\/a> if you encounter version-specific issues.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For the complete Universal Links guide, see <a href=\"https:\/\/tolinku.com\/blog\/universal-links-everything-you-need-to-know\/\">universal links: everything you need to know<\/a>. For deep linking standards across platforms, see <a href=\"https:\/\/tolinku.com\/blog\/deep-linking-standards-2026\/\">deep linking standards in 2026<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Track Universal Links behavior changes across iOS versions. From iOS 9 to iOS 18+, know what works and what to test for each release.<\/p>\n","protected":false},"author":2,"featured_media":2053,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Universal Links Across iOS Versions: A Compatibility Guide","rank_math_description":"Track Universal Links behavior changes across iOS versions. From iOS 9 to iOS 18+, know what works and what to test for each release.","rank_math_focus_keyword":"universal links iOS versions","rank_math_canonical_url":"","rank_math_facebook_title":"","rank_math_facebook_description":"","rank_math_facebook_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-universal-links-ios-version-differences.png","rank_math_facebook_image_id":"","rank_math_twitter_title":"","rank_math_twitter_description":"","rank_math_twitter_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-universal-links-ios-version-differences.png","footnotes":""},"categories":[12],"tags":[648,122,654,20,24,69,31,80,87,22],"class_list":["post-2054","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ios","tag-app-development","tag-apple","tag-compatibility","tag-deep-linking","tag-ios","tag-mobile-development","tag-swift","tag-testing","tag-troubleshooting","tag-universal-links"],"_links":{"self":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/2054","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/comments?post=2054"}],"version-history":[{"count":1,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/2054\/revisions"}],"predecessor-version":[{"id":2055,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/2054\/revisions\/2055"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media\/2053"}],"wp:attachment":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media?parent=2054"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/categories?post=2054"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/tags?post=2054"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}