A link that opened Telegram or Instagram directly last quarter can dump the same visitor into Safari today, with nothing in your own code having changed. That’s not drift. Vendors are retiring custom URL schemes on purpose, and several of them say so in their own documentation.
The list of apps you can reliably jump into from a link is shrinking, and it’s shrinking because the companies that own those apps decided a scheme was a liability, not a convenience. Knowing which ones still have a working scheme, why the rest lost theirs, and what a Universal Link actually buys you in exchange changes how you build the whole rewrite chain — especially on iOS, where there’s no intent://-style fallback mechanism to lean on when a scheme doesn’t fire.
The schemes vendors killed, in their own words
None of these are missing implementations waiting to be filled in. Each vendor has stated, in its own documentation or help centre, why there’s nothing left to rewrite to.
| App | Status | Vendor’s stated reason |
|---|---|---|
| LINE | line:// deprecated | To stop takeover attacks where the wrong app launches |
| Never published | States in its own help centre that it does not publish templates for third parties | |
| YouTube | No documented scheme | Google’s current docs say Universal Links already open the app on iOS 9+ |
| X | No supported scheme | A DM-compose deep link exists, but it needs a manual send and a paid Account Activity API tier that’s being deprecated |
| Snapchat | No scheme | The developer platform’s full product list has no messaging or chat API at all |
| No clickable link | Its payload mechanism is a QR scene_id, not a URL | |
| No documented scheme | — |
LINE’s reasoning is the plainest statement anywhere on this list of why a scheme is a security surface and not just a convenience. Registering a scheme is a promise that the right app answers it, and nothing in the mechanism stops a different app from registering the same string first. Deprecating the scheme closes that door outright instead of patching it app by app.
X is the cleanest case of a vendor simply never building the door at all. A DM-compose deep link exists on paper, but it needs a manual send from the visitor and sits behind a paid Account Activity API tier that is itself being phased out. For routing purposes, that’s the same as no scheme: nothing you build against it survives contact with the account tier requirement.
Pinterest, Snapchat, WeChat and Reddit round out the list with three different flavors of the same refusal. Pinterest’s help centre is explicit that it doesn’t publish templates for outside developers to build against — there’s no undocumented scheme to reverse-engineer, because the position is that none is meant to exist. Snapchat’s developer platform simply has no messaging or chat surface in its product list, so there’s no API a scheme could even front for. WeChat’s equivalent of a deep link is a QR scene_id, which needs a camera pointed at a screen rather than a URL a browser can carry — a different mechanism entirely, not a scheme by another name. Reddit doesn’t document one either way, which is the “unknown” bucket rather than the “confirmed absent” one, but for a link you’re about to ship in production the practical handling is identical: don’t build a rewrite rule on a scheme nobody has confirmed.
Read as a trend rather than a checklist, the pattern holds across all seven rows: the narrow iOS coverage here is mostly a deliberate industry move toward Universal Links, not a gap anyone forgot to fill in. That’s worth knowing before you spend an afternoon trying to find LINE’s scheme in a decompiled APK — the company that owns it has already told you, in writing, that it doesn’t want that door open.
What’s still standing
A handful of rewrites are confirmed working — see the full reference table of which schemes still work — but each one has its own grammar. There’s no shared pattern you can template across apps the way package=<package> covers every app on Android.
| Public URL | Custom scheme | Note |
|---|---|---|
https://t.me/<bot>?start=<payload> | tg://resolve?domain=<bot>&start=<payload> | |
https://t.me/<channel> | tg://resolve?domain=<channel> | |
https://instagram.com/<username> | instagram://user?username=<username> | |
https://facebook.com/profile.php?id=<n> | fb://profile/<n> | needs the numeric id — the Graph API refuses username lookups (error #803) |
https://open.spotify.com/track/<id> | spotify:track:<id> | colons, not slashes |
https://twitch.tv/<channel> | twitch://stream/<channel> | |
https://twitch.tv/<ch>/v/<id> | twitch://video/v<id> | VOD ids need the v prefix |
Instagram has its own version of the Facebook problem, in reverse. A post or reel URL carries a shortcode; the scheme needs an internal numeric media id, and there’s no public path from one to the other. Facebook has the mirror-image issue: fb://profile/ only accepts the numeric id, and the Graph API refuses to resolve a username into one, so a profile URL you scraped rather than looked up in Business Manager is a dead end.
TikTok deserves its own line rather than a table row, because getting TikTok traffic routed to the wrong scheme id is silent rather than loud. Its iOS scheme is snssdk1233, per TikTok’s own SDK documentation. snssdk1128 belongs to Douyin — a different app, on a different store, built for a different market. A rewrite built against the wrong id either opens nothing, or opens Douyin for the small slice of visitors who happen to have that installed instead, and neither failure mode looks like a typo when you’re staring at it in a debugger.
What a Universal Link buys you, and what it costs
A custom scheme is deterministic: any page that knows the syntax can fire it, and the app either answers or it doesn’t — though answering isn’t the same as keeping the visitor there. A Universal Link isn’t built that way. It’s an https:// URL the whole time, so it degrades safely — a browser can always open it — but whether it also opens the app is a decision made on the vendor’s behalf by the operating system, not something your link controls directly. That’s the trade LINE, Pinterest, X and YouTube each made when they stepped back from maintaining a scheme of their own: hand the “does the app open” decision to the platform’s association mechanism instead of a door they have to keep secure themselves.
Google’s own documentation states plainly that Universal Links have covered YouTube since iOS 9 — this isn’t a recent workaround, it’s been the intended mechanism for most of the platform’s life, and YouTube simply never needed a scheme once it existed. But “the OS decides” cuts in both directions once you’re relying on it. The same link tapped from inside another app’s own in-app browser doesn’t necessarily get the same treatment as one tapped from Safari or Messages — the context a tap happens in is part of what the system weighs, not just the URL string itself. If a meaningful share of your traffic arrives through an in-app browser rather than a native one, that’s precisely the traffic most likely to land in a browser instead of the app — the traffic a Universal Link gives you the least control over.
One string vs. a rulebook per app
Android collapses all of this into a single mechanism. The intent syntax needs exactly one variable per app:
intent://host/path#Intent;scheme=https;package=<package>;end
Get the package name right and the rewrite is done. Instagram, Spotify, Twitch and Telegram all resolve through the identical grammar on Android, just with a different string dropped into the same slot.
iOS gives you no equivalent shortcut. You need the scheme and a rewrite rule shaped to that app’s own URL structure, and the shape changes app by app: a bot needs ?start=, a channel doesn’t; Spotify wants colons where Twitch wants slashes; a Twitch VOD needs a v prefixed onto an id that a live channel link never carries. Seven working schemes in the table above means seven separate rewrite rules, not one rule with seven inputs swapped through it.
That asymmetry is the actual cost of the shrinking scheme list. It isn’t just that fewer apps answer to a custom scheme every year — it’s that each one which still does asks for something slightly different from the last, and a shared template across apps was never really available on iOS the way it is on Android. A routing layer that treats every rewrite as its own editable rule, rather than one generic pattern with a package name dropped in, is what keeps that shrinking list from turning into a growing pile of broken redirects every time a vendor changes its mind. DarkCore’s Streams handle Android package chains and iOS scheme rewrites as separate rules per app, so retiring one app’s scheme is a configuration change on your end, not a redeploy.
None of this is a one-time inventory. A scheme that’s confirmed working today is confirmed working as of the last time someone tapped it on a real device, not as a permanent property of the app — LINE’s own history is the proof, since line:// worked for years before the deprecation notice went up. Treat every row in both tables above as something to re-verify on a real device periodically, not a fact to hardcode once and forget, and treat “confirmed absent” the same way you’d treat “confirmed working”: as the vendor’s current position, which is exactly the kind of thing vendors change without asking your redirect chain first.