ZIPPY
reference

platforms

the 22 built-in platforms and what each URL shape opens — plus how to add a platform in one PR.

platforms

The deep-link table (services/redirect/src/platforms.ts) is the core of Zippy. Each platform is one data object; from it Zippy derives the iOS, Android, and web link forms uniformly. Zippy ships with these 22:

PlatformKeySchemeAndroid packageHosts
LinkedInlinkedinlinkedincom.linkedin.androidlinkedin.com
Instagraminstagraminstagramcom.instagram.androidinstagram.com
WhatsAppwhatsappwhatsappcom.whatsappwa.me, api.whatsapp.com
Redditredditredditcom.reddit.frontpagereddit.com, old.reddit.com
Product Huntproducthuntproducthuntcom.producthunt.huntproducthunt.com
YouTubeyoutubeyoutubecom.google.android.youtubeyoutube.com, m.youtube.com, youtu.be, music.youtube.com
TikToktiktoktiktokcom.zhiliaoapp.musicallytiktok.com, vm.tiktok.com, m.tiktok.com
X (Twitter)xtwittercom.twitter.androidx.com, twitter.com, mobile.twitter.com
GitHubgithubhttpscom.github.androidgithub.com
Amazonamazoncom.amazon.mobile.shopping.webcom.amazon.mShop.android.shoppingamazon.com, amzn.to, a.co, amzn.com
Spotifyspotifyspotifycom.spotify.musicopen.spotify.com, spotify.link
Facebookfacebookfbcom.facebook.katanafacebook.com, m.facebook.com, fb.com, fb.me, fb.watch
Pinterestpinterestpinterestcom.pinterestpinterest.com
Threadsthreadsbarcelonacom.instagram.barcelonathreads.net, threads.com
Telegramtelegramtgorg.telegram.messengert.me, telegram.me, telegram.dog
Apple Musicapple-musicmusiccom.apple.android.musicmusic.apple.com
Discorddiscorddiscordcom.discorddiscord.com, discord.gg, discordapp.com
Google Mapsgoogle-mapscomgooglemapsurlcom.google.android.apps.mapsmaps.google.com
App Storeapp-storeitms-appscom.android.vendingapps.apple.com, itunes.apple.com
Play Storeplay-storehttpscom.android.vendingplay.google.com
Snapchatsnapchathttpscom.snapchat.androidsnapchat.com
Twitchtwitchtwitchtv.twitch.android.apptwitch.tv, m.twitch.tv

Schemeless (Android-only native open). GitHub, Play Store, and Snapchat register no custom URL scheme — their apps are reachable only via https App Links (Android) and Universal Links (iOS). So their "scheme" is https and Zippy hands the app the genuine URL: Android gets a real native-open; iOS lands on the web page (Universal Links don't fire inside in-app webviews — the exact gap Zippy exists to close). See the GitHub / Snapchat note below.

App Store is iOS-native by design. itms-apps is a built-in iOS system scheme, so apps.apple.com links open the App Store app straight from a webview. There is no Apple store on Android, so those links correctly serve web there (the package shown is inert on the Apple host). Google Play is the separate play-store row, which opens the Play Store app on Android.

Host matching strips a leading www. and is case-insensitive. A destination whose host no platform owns is never matched — it simply 301s.

What each URL shape opens

PlatformURL you shortenOpens in-app
LinkedInlinkedin.com/in/<user>that profile
linkedin.com/company/<name>that company page
anything else on linkedin.comthe app (web fallback lands the page)
Instagraminstagram.com/<user>that profile
instagram.com/p/…, /reel/…the app; web fallback lands the post/reel
WhatsAppwa.me/<phone>a chat with that number
api.whatsapp.com/send?phone=<phone>&text=<text>a chat, prefilled with text
Redditreddit.com/r/<sub>, /u/<user>, /user/<user> (and posts under them)that subreddit / user / post
Product Huntproducthunt.com/posts/<slug>, /products/<slug>that post / product
YouTubeyoutu.be/<id>, youtube.com/watch?v=<id>, youtube.com/shorts/<id>that video
youtube.com/channel/<id>, /c/<id>that channel
TikToktiktok.com/@<user>that profile
tiktok.com/@<user>/video/<id>, vm.tiktok.com/<code>the app; web fallback lands the video
X (Twitter)x.com/<user>/status/<id>that tweet
x.com/<user>that profile
GitHubgithub.com/<owner>/<repo>, /<user>, …/issues/<n>, …/pull/<n>Android: that page in the app
(same URLs)iOS: the browser — no app open (see below)
Amazonamazon.com/dp/<ASIN>?tag=<id> (and any amazon URL)that product in the app — the ?tag= affiliate tag stays in the URL (see caveat)
Spotifyopen.spotify.com/track|album|artist|playlist/<id>that track / album / artist / playlist
Facebookfacebook.com/profile.php?id=<numeric>that profile (numeric ids only)
facebook.com/<anything-else>that page inside the FB app's own webview
Pinterestpinterest.com/pin/<id>that pin
pinterest.com/<user>, /<user>/<board>the app; web fallback lands the profile/board
Threadsthreads.net/@<user>, threads.com/@<user>that profile
…/@<user>/post/<code>the app; web fallback lands the post
Telegramt.me/<user>, t.me/<user>/<post>that channel/user (and post)
t.me/+<hash>, t.me/joinchat/<hash>, t.me/addstickers/<set>join invite / sticker set
Apple Musicmusic.apple.com/<cc>/album|song|playlist/…that album / song / playlist
Discorddiscord.gg/<code>, discord.com/invite/<code>that invite
discord.com/channels/<guild>[/<channel>]that channel
Google Mapsmaps.google.com/…that place / map in the app (iOS)
App Storeapps.apple.com/…/id<n>iOS: that app in the App Store
(same URL)Android: the browser — no Apple store
Play Storeplay.google.com/store/apps/details?id=<pkg>Android: that app in the Play Store
(same URL)iOS: the browser — no Play app
Snapchatsnapchat.com/add/<user>Android: the add-friend screen in the app
(same URL)iOS: the browser — no app open (see below)
Twitchtwitch.tv/<channel>that channel's stream
twitch.tv/videos/<id>, twitch.tv/directory/game/<name>that VOD / that game directory

GitHub / Play Store / Snapchat: Android-only native open (honest limitation)

These apps have no custom URL scheme — only https App Links (Android) and Universal Links (iOS). Zippy hands the app the real URL:

  • Android → a package-targeted intent://…;scheme=https;package=<pkg> opens the app on that page (repo / PR, Play listing, or Snapchat add-friend screen), with the web URL as the native fallback. A real win.
  • iOS → there is no custom scheme, and Universal Links do not fire from inside in-app webviews (Instagram, LinkedIn, …) — which is the exact gap Zippy exists to close. So on iOS these short links land on the web page in the browser: no worse than a plain tap, but no app open either. We deliberately do not invent a fake scheme (a wrong scheme would only add a redirect hop). For Snapchat specifically, snapchat:// exists but only opens the camera — it carries no add-friend username — so there is nothing honest to fire on iOS.

Amazon affiliate tag: opens the app, attribution is Amazon's black box

Amazon's com.amazon.mobile.shopping.web:// scheme loads the full web URL in the app, so a shortened amazon.com/dp/<ASIN>?tag=<your-id-20> link opens the product in the app with the ?tag= still in the URL. What Zippy cannot promise: whether Amazon attributes that tag for commission once inside the app — Amazon does not document this, and it's true of every deep-link method, not just Zippy. If commission matters to you, place a test order through the link and confirm it in your Associates reporting before relying on it.

Best-effort by design

Where a platform has no reliable in-app scheme for a given content type (Instagram posts, TikTok videos, vm.* shortlinks), path returns "" — the app opens to its home screen and the web fallback lands the exact content. Nothing breaks; see how deeplinks work.

Add a platform (PR guide)

Adding a platform is a small, self-contained PR against services/redirect. You touch two files: the table and its test.

1. Add one object to PLATFORMS

In services/redirect/src/platforms.ts, append a Platform:

type Platform = {
  key: string; // stable id, also the `deeplink` value in API responses
  scheme: string; // the app's custom URL scheme, e.g. "spotify"
  androidPackage: string; // Play Store package id, e.g. "com.spotify.music"
  hosts: string[]; // lowercased hostnames it owns, no leading "www."
  path: (url: URL) => string; // scheme-specific suffix after "scheme://", or "" for app home
};

Example:

{
  key: "spotify",
  scheme: "spotify",
  androidPackage: "com.spotify.music",
  hosts: ["open.spotify.com"],
  path: (url) => {
    const s = url.pathname.split("/").filter(Boolean);
    // /track/<id> → spotify:track:<id>-style suffix the app understands, else app home
    if ((s[0] === "track" || s[0] === "album" || s[0] === "playlist") && s[1]) {
      return `${s[0]}/${s[1]}`;
    }
    return "";
  },
}

Zippy derives the iOS (scheme://path), Android (intent://…), and web-fallback forms from these fields — nothing else in the Worker changes.

2. Add test rows to test/platforms.test.ts

Cover each URL shape your path handles (profile, content, and the app-home fallback), and run the suite:

bun --filter @zippy/redirect test

Tips

  • Verify the scheme on a real device if you can — schemes are undocumented and drift. If you're unsure, leave a // ponytail:-style note; the web fallback keeps a wrong scheme safe.
  • Return "" rather than guessing when a content type has no dependable scheme. An app-home open plus the web fallback beats a broken deep link.
  • Keep hosts lowercase and without www. — matching normalizes the request host the same way.

On this page