developer

URI Schemes Explained: Custom App Links Made Simple (2026)

URI schemes explained in plain English: what they are, how they work on iOS and Android, the setup, the security gotchas, and where they still make sense in 2026.

Team U2L 18 min read

A URI scheme is the first part of a URL, before the colon, that tells the operating system which app should handle the link. https:// routes to the browser; spotify://track/4iV5W9uYEdYUVa79Axb7Rh routes to Spotify. Any mobile app can register a custom URI scheme (like myapp://) so that tapping myapp://path opens the app directly to a specific screen. They were the original way to deep link into apps, and they still exist in 2026, but they have been superseded by verified HTTPS deep links (universal links on iOS, app links on Android) for anything customer-facing.

If you have ever wondered why whatsapp://send?text=hello opens WhatsApp but myfaveapp://home opens nothing, you have already met a URI scheme. They are the oldest deep-linking mechanism on mobile, they still power a surprising amount of routing you use every day, and every developer will run into them the moment they try to open one app from another. The frustrating part is that most explainers either treat them as a beginner concept and skip the useful bits, or dive straight into iOS/Android registration files without saying what a scheme actually is.

This guide is the middle ground. We will define URI schemes properly, show how they are registered on iOS and Android, list the ones you have probably tapped without noticing, and be honest about why they got quietly replaced. If you are choosing between a URI scheme and something newer for a real product, the last two sections tell you when the answer is still "scheme" and when it isn't.

Table of Contents

What Is a URI Scheme?

A URI scheme is the identifier at the start of a URI (before the colon) that tells software which protocol or handler should process the rest of the string. https is a scheme, mailto is a scheme, tel is a scheme, and spotify is a scheme. A custom URI scheme is one that a specific mobile app registers with the operating system so that URIs starting with that prefix are handed to the app instead of a browser.

Every URL you have ever tapped is technically a URI with a scheme in front. The scheme is not a decoration - it is the routing instruction. https://u2l.ai tells the operating system "hand this to whatever handles HTTPS," which is nearly always a browser. tel:+14155551212 tells it "hand this to the phone dialer." mailto:hello@u2l.ai tells it "hand this to the default mail client." The system keeps an internal registry of which apps handle which schemes, and it consults that registry every time a link is tapped.

Custom URI schemes are the same mechanism, just claimed by an app that isn't the browser, dialer, or mail client. When Instagram installs, it registers instagram:// in the OS's registry. Any time a user taps a instagram://user?username=u2lai link, the OS looks up instagram, finds Instagram, and hands the URL to it. Instagram parses the rest of the URL (user?username=u2lai) and opens the right profile.

The word "scheme" comes from RFC 3986, the internet standard that defines URI syntax. Standardization is why mailto: works on every mail app on every OS. Custom schemes are outside that standard - each app picks its own, hopes nobody else picks the same one, and tells the OS "this is mine." That freedom is both the appeal and, as we will see, the source of every problem.

The Anatomy of a URI

Before we go further, a quick anatomy lesson makes everything after this cleaner. A URI in the shape scheme://host/path?query breaks down into four labeled pieces.

  • Scheme. The bit before the ://. Tells the OS which handler to invoke. Examples: https, mailto, tel, spotify, whatsapp.
  • Host (optional). Sometimes called the authority. In spotify://track/xyz, track acts as a host-ish route indicator. Custom schemes often drop the traditional host role and use this slot for a top-level route.
  • Path. The specific content or screen inside the app. /track/4iV5W9uYEdYUVa79Axb7Rh targets a specific song.
  • Query string. Key-value pairs for options and parameters. ?utm_source=email&autoplay=1.

For custom URI schemes, host and path get bent to serve as an in-app router. youtube://watch?v=dQw4w9WgXcQ uses no traditional host and packs the video ID into the query. twitter://user?screen_name=u2lai uses user as the route and screen_name as the query key. Every app makes its own rules. There is no cross-app convention and no directory that documents them - you either find the scheme in the app's docs, reverse-engineer it, or use a tool that has already done both.

How Custom URI Schemes Work

Under the hood, custom URI schemes are a small conversation between the OS and installed apps.

Step 1: Registration. When an app installs, its manifest (Info.plist on iOS, AndroidManifest.xml on Android) declares "I handle this scheme." The OS reads this and updates its internal handler registry.

Step 2: Tap. The user taps a link somewhere - Safari, Chrome, Notes, a chat app, a QR scan. The tapping surface passes the URI to the OS.

Step 3: Lookup. The OS strips out the scheme (spotify) and searches its handler registry. If there is a match, it launches the corresponding app and passes the full URI as an argument. If not, on iOS you usually get a "Cannot open page" dialog; on Android it either fails silently or opens a browser that has no idea what to do with spotify://.

Step 4: In-app routing. The launched app receives the URI, parses it, and navigates to the right screen. On iOS this typically fires the application(_:open:options:) app-delegate method or a SwiftUI onOpenURL handler. On Android the URI arrives as the intent's data attribute, and your activity handles the routing.

The whole flow is fast, straightforward, and hides some cliffs. There is no confirmation, no chooser dialog (on iOS at least), no verification that the app claiming the scheme is legitimate. That trust-by-default model is exactly what a lot of newer standards were designed to fix, but it is also what makes URI schemes so lightweight for internal use inside a single app.

Registering a Custom URI Scheme on iOS

On iOS, you register a scheme in Info.plist under the CFBundleURLTypes key. Apple's own documentation on defining a custom URL scheme is the canonical reference.

The minimum plist entry looks like this in XML form:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>com.u2lai.myapp</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>u2laiapp</string>
    </array>
  </dict>
</array>

Two things worth flagging. First, Apple recommends using reverse-DNS format for CFBundleURLName to reduce collision risk (com.yourcompany.appname). The scheme itself (u2laiapp) should be equally distinctive - myapp is asking for trouble. Second, once registered, the app receives incoming URIs via the application(_:open:options:) method on UIApplicationDelegate, or through the SwiftUI .onOpenURL { url in ... } view modifier. The URL comes in as a URL value with scheme, host, path, and query properties ready to read.

Testing on device is easy: open Safari, type your custom URI in the address bar, tap Go. If your app opens, registration works. If Safari shows "Cannot open page," either your scheme is wrong or the app is not installed. The iOS Simulator can also test schemes via xcrun simctl openurl booted "u2laiapp://path" in the terminal.

Registering a Custom URI Scheme on Android

On Android, you declare a scheme with an intent filter on the activity you want to receive the deep link. Google's Create deep links guide is the reference. A minimal AndroidManifest.xml snippet:

<activity android:name=".MainActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="u2laiapp"
              android:host="path" />
    </intent-filter>
</activity>

Three pieces you have to include or it silently fails. action.VIEW says "this filter matches view-style intents." category.DEFAULT lets the URL be opened without a specific component target. category.BROWSABLE lets a browser or webview launch it, which is what you want if the link will ever appear in Chrome, an email, or an SMS. Miss BROWSABLE and links tapped from web contexts do nothing.

The incoming intent arrives at your activity in onCreate (or onNewIntent if the activity was already alive), and the URI is available via intent.data. From there you can pull scheme, host, path, and query using the standard Uri API. Testing with adb is quick: adb shell am start -a android.intent.action.VIEW -d "u2laiapp://path" fires an intent as if the URI had been tapped.

For a deeper look at Android's newer, verified deep-link model, our Android app links setup guide covers the assetlinks.json handshake that goes beyond raw schemes.

Well-Known URI Schemes You Already Use

You have tapped more custom URI schemes than you think. A short tour of the ones that show up in real apps:

  • tel: - opens the phone dialer with a pre-filled number. Standardized in RFC 3966, works everywhere.
  • mailto: - opens the default mail client to compose. Also standardized.
  • sms: - opens the SMS composer. Both iOS and Android honor it; some support sms:number?body=text for a pre-filled message.
  • whatsapp://send?phone=...&text=... - opens a WhatsApp chat with a phone number pre-populated. The web equivalent (wa.me) proxies to this scheme when the app is installed.
  • spotify://track/<id> - opens a specific Spotify track. Same shape for album, playlist, artist, episode.
  • instagram://user?username=u2lai - opens a specific Instagram profile. Also instagram://media?id=... for a specific post.
  • twitter://user?screen_name=... - opens an X (formerly Twitter) profile. Now aliased with x-twitter:// in newer versions.
  • youtube://watch?v=<id> - opens the YouTube app to a specific video.
  • fb://profile/<id> - opens a Facebook profile by numeric ID.
  • geo:37.7749,-122.4194 - standard geographic URI, launches Maps on both platforms.
  • intent://...#Intent;...;end - Android-specific "intent URI" that wraps a scheme plus a fallback URL, so browsers can trigger the app when installed and fall back to a Play Store URL when not.

Some are public and stable (whatsapp, geo, tel). Others are undocumented and can change without notice (fb, instagram). Because there is no central registry, "well-known" here means "figured out and shared by the community." Any tool that promises to open a specific in-app screen for these apps is doing exactly this parsing behind the scenes.

Where URI Schemes Fall Over

The moment you leave the safe box of internal-only routing, URI schemes start to hurt. Four failure modes cover almost every real-world complaint.

No verified ownership. Any app can register any scheme. Nothing prevents a second app from also claiming mybank://. iOS resolves conflicts by install order, which is not something you should rely on for anything security-sensitive. A well-known FireEye analysis of URL scheme hijacking documented this class of attack years ago, and it is still the reason Apple pushed universal links.

No web fallback. If the app is not installed, a URI scheme just fails. Depending on where the link is opened, you either see an error dialog, a blank page, or nothing at all. To hack around this you have to serve an HTML page that tries the scheme, then falls back to a web URL after a timeout - and that timeout hack is exactly what modern in-app browsers block.

Blocked inside webviews. Instagram, Facebook, TikTok, and LinkedIn's in-app browsers filter unknown schemes for security reasons. Even legitimate spotify:// links often die inside these webviews with no user-visible feedback. Our explainer on why links open in an in-app browser covers what is really happening and why it costs conversions.

No cross-platform consistency. iOS and Android agree on the concept but differ on registration syntax, intent semantics, and how failures manifest. Anything you learn from the WhatsApp scheme on iOS you have to unlearn slightly for Android's intent URI wrapper. There is no single scheme that works identically on both.

None of these are dealbreakers for internal navigation inside a single app. All of them are dealbreakers for anything you plan to share with customers.

The three flavors of mobile deep link get compared constantly, and the differences are worth memorizing.

Aspect Custom URI Scheme iOS Universal Link Android App Link
URL format myapp://path https://yourdomain.com/path https://yourdomain.com/path
Opens app when installed Yes Yes Yes
Web fallback when missing No Yes (Safari) Yes (browser)
Verified against domain No Yes (AASA file) Yes (assetlinks.json)
Hijack-proof No Yes Yes
Works in Instagram webview Usually no Usually yes Usually yes
Requires developer setup Small (manifest only) Medium (AASA + entitlements) Medium (assetlinks.json + autoVerify)
Best for Internal app routing, other apps calling yours Customer-facing iOS links Customer-facing Android links

For a longer breakdown of the last two rows, our deep link vs universal link explainer walks through the fallback and security semantics. The important sentence is this: universal links and app links did not replace URI schemes because URI schemes were bad at internal use - they replaced them because URI schemes were bad at shared, cross-app, cross-user use. If your scheme never leaves your own app's process, you are still fine.

When URI Schemes Still Make Sense in 2026

Nobody has actually deprecated URI schemes. They are alive, well, and useful for a shrinking but real list of jobs.

Internal navigation inside your own app. Push-notification payloads, in-app buttons, notification action extensions, and Widget/AppIntents deep links inside iOS all hand you a URI. Using your own custom scheme keeps that routing independent of your web infrastructure. If your marketing site goes down, your push notifications still open the right screen.

App-to-app handoff for well-known partners. Payment SDKs, OAuth libraries (with PKCE), and share-extensions frequently use URI schemes to return the user to your app after an interaction. Google's, Apple's, and Facebook's login SDKs all rely on scheme-based callback URIs, and there is no plan to change that.

Fallback path inside a universal link. Some teams register both a universal link and a custom scheme, and if the universal link fails to catch (a Safari address bar paste, for example), a small landing page fires the custom scheme as a plan B. This is the pattern most deep-linking tools use internally.

Command URIs for advanced users. slack://open, things:///show?id=abc, raycast://extensions/... - power-user apps expose functionality via schemes so scripts, keyboard shortcuts, and automation tools can trigger them.

For anything customer-facing that will show up in an email, a QR code, a bio link, or an SMS, the answer in 2026 is not a URI scheme. It is a verified HTTPS URL that acts as a universal link on iOS and an app link on Android, ideally with a deferred fallback for users who don't have the app yet. Our mobile deep linking guide is the pillar article for that broader picture, and our roundup of the best deep link generators compares tools that handle it end-to-end.

The No-Code Shortcut for Everyone Else

Not everyone reading this is a developer. If you got here because you saw a spotify:// link in someone's Instagram bio and wanted to know how to make one, the answer is much simpler than the sections above suggest.

U2L AI generates deep links for popular apps without any of the setup. You paste a regular destination (a YouTube video, a Spotify track, an Instagram post, a WhatsApp chat, an Amazon listing, and more), and we hand back a single short link that uses the right mechanism on each platform: a universal link on iOS, an app link or intent URI on Android, and a graceful web fallback when nothing else fits. If the user taps it from inside Instagram or Facebook, our routing pushes them out of the in-app browser first, so the app opens instead of a broken webview. The full list of supported apps lives at supported deep links, and you can generate one without an account.

For creators, marketers, and small teams, that is 99% of the value URI schemes were originally trying to deliver, without any manifest editing, without any AASA files, and without the hijack risk. Sign up for U2L AI to add branded custom short domains, per-app deep linking, and full click analytics to every link. For an even wider look at what's included, the features overview has the full list.

Frequently Asked Questions

What is the difference between a URI scheme and a URL scheme?

Nothing meaningful. "URI" and "URL" are often used interchangeably, and both refer to the same identifier structure. The term "URI scheme" is technically more correct because URIs are the broader concept (a URL is a URI that also locates something), but "URL scheme" is what most Apple and Android documentation actually uses. Treat them as synonyms.

Do URI schemes still work on iOS 17 and iOS 18?

Yes. Custom URI schemes are still supported and used by every app that has one registered. Apple has not deprecated them and there are no announced plans to. What has changed is where they are the right tool - customer-facing sharing has moved to universal links, but internal routing and callback URIs are still scheme-based.

Can two apps register the same URI scheme?

Yes, and this is the biggest security problem with them. iOS resolves the conflict by install order and gives no user-visible warning. Android may show the intent chooser or pick one deterministically depending on the intent flags. This is exactly why universal links and app links require cryptographic proof of domain ownership - to make claim-jumping impossible.

How do I test a URI scheme?

On iOS, type the URI into Safari's address bar or run xcrun simctl openurl booted "yourscheme://path" in a terminal. On Android, use adb shell am start -a android.intent.action.VIEW -d "yourscheme://path". If the app opens to the right screen, registration is working. If not, check that the scheme string, category flags, and (on Android) the exported attribute all match.

Instagram and Facebook use an in-app browser that blocks unknown URI schemes for security and analytics reasons. Even fully working schemes silently fail inside those webviews. The workaround is to route the link through a service that detects the webview and pushes the user out to the real app or the OS's default browser, which is what U2L AI's app-opener flow does automatically.

Are URI schemes secure?

For internal use inside one app, they are fine. For shared, customer-facing use, they are not - a malicious app can register the same scheme and intercept the URL, including sensitive parameters like auth tokens. Public research on URL scheme hijacking documents the risk. Verified deep-link standards (universal links and app links) exist specifically because URI schemes never had verification.

For customer-facing links, no. A universal link (iOS) plus an app link (Android) covers everything a URI scheme did, with a web fallback and hijack protection you cannot get from a raw scheme. For internal routing (push notifications, widgets, callbacks), you probably still want a scheme registered as well, but it is optional and not exposed to users.

What is an intent URI on Android?

An intent:// URI is Android's way of wrapping a scheme with metadata. It looks like intent://host/path#Intent;scheme=myapp;package=com.example.myapp;S.browser_fallback_url=https%3A%2F%2Fexample.com;end. If the app is installed, Android launches it with the specified scheme; if not, it opens the fallback URL. It is essentially a "URI scheme with a safety net" and is what most deep-linking tools generate for Android when they cannot use a fully verified app link.

The Takeaway

A URI scheme is the routing prefix on a link that tells the OS which app should handle it. Custom schemes let mobile apps claim their own prefix and open specific in-app screens directly. They are simple to register, still supported on every modern OS, and useful for internal routing, callbacks, and app-to-app handoffs. They are also unverified, fallback-less, and increasingly blocked in the very places you would want to share them, which is why customer-facing deep links moved to verified HTTPS-based universal and app links years ago.

If you are a developer, keep your scheme for the jobs it is still good at and use a universal or app link (or a deep-linking tool that handles both) for anything shared publicly. If you are a marketer or creator, skip the setup entirely - generate a single short link at U2L AI that routes to the right app on every platform, and check the features page for what else is included.

Sources:

Ready to try U2L AI?

Free forever plan. No credit card required.