universal-links

Use bunx setup-safari to configure and test universal links (deep links) on iOS.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "universal-links" with this command: npx skills add evanbacon/evanbacon.dev/evanbacon-evanbacon-dev-universal-links

Use bunx setup-safari to configure and test universal links (deep links) on iOS.

Important: When Custom Builds Are Needed

Universal links with custom domains require custom native builds. Your app will no longer work in Expo Go.

However, for basic deep linking during development:

  • Expo Go supports the exp:// URL scheme and Expo-hosted URLs

  • Custom builds required for your own domain's universal links (applinks:yourdomain.com)

If you only need deep linking for development/testing, try npx expo start with Expo Go first. Only create custom builds when you need production universal links with your own domain.

Automated Setup (Recommended)

Run setup-safari with your Apple ID to automate credential lookup:

EXPO_APPLE_ID="your-apple-id@email.com" bunx setup-safari

This will:

  • Authenticate with Apple Developer Portal

  • Enable Associated Domains for your bundle ID

  • Output the AASA file content and meta tag

After running, you must manually:

  1. Create the AASA file

Create public/.well-known/apple-app-site-association (no file extension):

{ "applinks": { "details": [ { "appIDs": ["TEAM_ID.com.your.bundleid"], "components": [ { "/": "*", "comment": "Matches all routes" } ] } ] }, "activitycontinuation": { "apps": ["TEAM_ID.com.your.bundleid"] }, "webcredentials": { "apps": ["TEAM_ID.com.your.bundleid"] } }

  1. Create src/app/+html.tsx with Smart App Banner

import { ScrollViewStyleReset } from "expo-router/html";

export default function Root({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta httpEquiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <meta name="apple-itunes-app" content="app-id=YOUR_ITUNES_ID" /> <ScrollViewStyleReset /> </head> <body>{children}</body> </html> ); }

  1. Add Associated Domains to app.json

{ "expo": { "ios": { "associatedDomains": [ "applinks:yourdomain.com", "activitycontinuation:yourdomain.com", "webcredentials:yourdomain.com" ] } } }

  1. Deploy and Rebuild

Deploy web (AASA file must be accessible)

npx expo export -p web && npx eas-cli deploy

Rebuild iOS app with new entitlements

npx expo run:ios

Or for TestFlight: npx testflight

Interactive Setup (Alternative)

For interactive mode (requires TTY):

bunx setup-safari

How Universal Links Work

Universal links require two parts:

  • AASA file on your server - Tells iOS which paths your app handles

  • Associated Domains entitlement - Tells your app which domains to claim

AASA File Format

Host at https://yourdomain.com/.well-known/apple-app-site-association :

{ "applinks": { "apps": [], "details": [ { "appID": "TEAM_ID.com.example.app", "paths": ["*"] } ] } }

Path patterns:

  • Match all paths

  • /products/*

  • Match paths starting with /products/

  • /item/???

  • Match exactly 3 characters after /item/

  • NOT /admin/*

  • Exclude paths

Associated Domains Entitlement

In your app.json or app.config.js :

{ "expo": { "ios": { "associatedDomains": [ "applinks:yourdomain.com", "applinks:www.yourdomain.com" ] } } }

Testing Universal Links

After setup, test with setup-safari:

npx setup-safari

Or manually test in Safari:

  • Open Safari on iOS device/simulator

  • Navigate to a URL that should open your app

  • Pull down to reveal the banner, or long-press the link

Testing with Tunnel (No Server Required)

Test universal links without deploying a website using Expo's tunnel feature:

  • Set a consistent tunnel subdomain:

export EXPO_TUNNEL_SUBDOMAIN=my-app-name

  • Configure associated domains with the ngrok URL:

{ "expo": { "ios": { "associatedDomains": ["applinks:my-app-name.ngrok.io"] } } }

  • Build the development client:

npx expo run:ios

  • Start the dev server with tunnel:

npx expo start --tunnel

The tunnel creates a public HTTPS URL that serves the AASA file automatically, letting you test the full universal links flow during development.

Debugging

Check if Apple has cached your AASA:

curl "https://app-site-association.cdn-apple.com/a/v1/yourdomain.com"

Validate AASA file format:

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

Common issues:

  • AASA must be served with Content-Type: application/json

  • HTTPS required (no self-signed certs)

  • Apple caches AASA files - changes may take time to propagate

Expo Router Integration

With Expo Router, handle incoming links automatically:

// app/[...path].tsx handles all deep link paths // app/products/[id].tsx handles /products/:id links

Access link parameters:

import { useLocalSearchParams } from "expo-router";

export default function Product() { const { id } = useLocalSearchParams(); return <Text>Product: {id}</Text>; }

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

expo-chat-ui

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

healthkit-cli

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

expo-devtools-cli

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

device-testing

No summary provided by upstream source.

Repository SourceNeeds Review