Skip to content
Tolinku
Tolinku
Sign In Start Free
iOS Development · · 6 min read

AASA Wildcards and Path Matching: Advanced Patterns

By Tolinku Staff
|
Tolinku universal links dashboard screenshot for ios blog posts

The Apple App Site Association (AASA) file controls which URLs on your domain open your app via Universal Links. For simple apps, a single path pattern is enough. For complex apps with hundreds of routes, multiple subdomains, or paths that should explicitly not open the app, you need advanced path matching.

This article covers the full path matching syntax available in AASA files, including wildcards, exclusions, query parameter matching, and the differences between the legacy and modern AASA formats.

For AASA basics, see AASA file setup guide. For Universal Links fundamentals, see universal links: everything you need to know.

AASA Format Versions

Apple introduced two AASA formats. Understanding which you are using matters because they handle path matching differently.

Legacy Format (iOS 9-12)

{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "TEAMID.com.example.app",
        "paths": ["/product/*", "/category/*", "NOT /admin/*"]
      }
    ]
  }
}

Key characteristics:

  • Uses appID (singular) and paths array.
  • Wildcards use * (matches any characters).
  • Exclusions use NOT prefix.
  • Paths are evaluated in order (first match wins).

Modern Format (iOS 13+)

{
  "applinks": {
    "details": [
      {
        "appIDs": ["TEAMID.com.example.app"],
        "components": [
          { "/": "/product/*", "comment": "Product pages" },
          { "/": "/category/*", "comment": "Category pages" },
          { "/": "/admin/*", "exclude": true, "comment": "Exclude admin" }
        ]
      }
    ]
  }
}

Key characteristics:

  • Uses appIDs (plural) and components array.
  • Each component is an object with a / key for the path.
  • Exclusions use "exclude": true.
  • Supports query parameter and fragment matching.
  • Components are evaluated in order (first match wins).

Apple recommends the modern format for new implementations. The legacy format is still supported for backward compatibility. Apple's documentation: Supporting Associated Domains.

Wildcard Syntax

Both formats support two wildcard characters:

Character Meaning Example
* Matches zero or more characters within a path component /product/* matches /product/123 and /product/abc
? Matches exactly one character /product/?? matches /product/ab but not /product/abc

The * Wildcard

The * wildcard matches any sequence of characters, but its behavior depends on context:

{
  "components": [
    { "/": "/product/*" },
    { "/": "/blog/*/comments" },
    { "/": "/*" }
  ]
}
  • /product/* matches /product/123, /product/shoes, /product/shoes/red.
  • /blog/*/comments matches /blog/my-post/comments.
  • /* matches every path on the domain.

Important: * matches across path separators (/). So /product/* will match /product/shoes/red/size/10. If you only want to match a single path segment, you need a different approach (the ? wildcard or more specific patterns).

The ? Wildcard

The ? wildcard matches exactly one character:

{
  "components": [
    { "/": "/item/??" },
    { "/": "/v?/api/*" }
  ]
}
  • /item/?? matches /item/ab but not /item/abc or /item/a.
  • /v?/api/* matches /v1/api/users and /v2/api/users.

Exclusion Patterns

Exclusions tell iOS that certain paths should NOT open the app, even if they match a broader wildcard.

Modern Format Exclusions

{
  "components": [
    { "/": "/admin/*", "exclude": true, "comment": "Never open admin pages in app" },
    { "/": "/api/*", "exclude": true, "comment": "API endpoints stay in browser" },
    { "/": "/*", "comment": "Everything else opens the app" }
  ]
}

Legacy Format Exclusions

{
  "paths": [
    "NOT /admin/*",
    "NOT /api/*",
    "/*"
  ]
}

Evaluation Order Matters

Components and paths are evaluated in order. The first match wins. This means exclusions must come before the broader patterns they override:

{
  "components": [
    { "/": "/blog/draft/*", "exclude": true },
    { "/": "/blog/*" }
  ]
}

This excludes draft blog posts but includes all other blog paths. If you reversed the order, /blog/* would match first and the exclusion would never apply.

Query Parameter Matching (Modern Format Only)

The modern format supports matching on query parameters using the ? key:

{
  "components": [
    {
      "/": "/share",
      "?": { "id": "?*" },
      "comment": "Share links with an id parameter"
    }
  ]
}

This matches /share?id=abc123 but not /share without the id parameter. The ?* pattern means "one or more characters" for the parameter value.

You can match multiple parameters:

{
  "components": [
    {
      "/": "/product",
      "?": { "sku": "?*", "ref": "?*" },
      "comment": "Product links with both sku and ref"
    }
  ]
}

This requires both sku and ref parameters to be present.

Fragment Matching (Modern Format Only)

The modern format also supports matching URL fragments (the part after #):

{
  "components": [
    {
      "/": "/page",
      "#": "section-*",
      "comment": "Page links with section fragments"
    }
  ]
}

This matches /page#section-intro and /page#section-details.

Common Patterns

E-Commerce App

{
  "applinks": {
    "details": [
      {
        "appIDs": ["TEAMID.com.example.store"],
        "components": [
          { "/": "/checkout/*", "exclude": true, "comment": "Keep checkout in browser" },
          { "/": "/product/*", "comment": "Product pages" },
          { "/": "/category/*", "comment": "Category browsing" },
          { "/": "/cart", "comment": "Shopping cart" },
          { "/": "/order/*/track", "comment": "Order tracking" },
          { "/": "/sale", "comment": "Sale landing page" }
        ]
      }
    ]
  }
}

Content App

{
  "applinks": {
    "details": [
      {
        "appIDs": ["TEAMID.com.example.news"],
        "components": [
          { "/": "/admin/*", "exclude": true },
          { "/": "/api/*", "exclude": true },
          { "/": "/article/*", "comment": "Articles" },
          { "/": "/author/*", "comment": "Author profiles" },
          { "/": "/topic/*", "comment": "Topic pages" },
          { "/": "/search", "?": { "q": "?*" }, "comment": "Search with query" }
        ]
      }
    ]
  }
}

Multi-App Domain

If multiple apps share a domain, list them in the details array:

{
  "applinks": {
    "details": [
      {
        "appIDs": ["TEAMID.com.example.consumer"],
        "components": [
          { "/": "/shop/*" },
          { "/": "/product/*" }
        ]
      },
      {
        "appIDs": ["TEAMID.com.example.merchant"],
        "components": [
          { "/": "/merchant/*" },
          { "/": "/dashboard/*" }
        ]
      }
    ]
  }
}

iOS checks each entry in order. The first app with a matching path wins.

Debugging Path Matching

If your path patterns are not working as expected:

Test the AASA file directly. Fetch your AASA file and verify the JSON is valid:

curl -s https://yourdomain.com/.well-known/apple-app-site-association | jq .

Check evaluation order. Remember that components are evaluated top-to-bottom. An overly broad pattern early in the list can prevent more specific patterns from matching.

Verify wildcard behavior. The * wildcard matches across path separators. If you intended to match only one segment, your pattern may be matching more than expected.

Check Apple's CDN cache. Apple caches AASA files on its CDN. Changes may take time to propagate. See CDN and AASA caching for details.

Use the AASA validator. Apple provides validation through Xcode's Associated Domains diagnostics. See debugging AASA files for step-by-step instructions.

For testing Universal Links in general, see testing Universal Links.

Tolinku and AASA Path Configuration

Tolinku manages your AASA file automatically based on the routes you configure in the dashboard. When you create a route in Tolinku, the AASA file is updated to include the corresponding path pattern. This eliminates manual AASA editing and reduces the risk of syntax errors or evaluation-order mistakes. See the Universal Links developer guide for configuration details.

For the complete Universal Links guide, see universal links: everything you need to know. For deep link parameter handling, see deep link parameters.

Get deep linking tips in your inbox

One email per week. No spam.

Ready to add deep linking to your app?

Set up Universal Links, App Links, deferred deep linking, and analytics in minutes. Free to start.