
PSA: Instagram/TikTok in-app browsers block every client-side path to the App Store. Here's the server-side fix that actually works.
If you put a "link in bio" that's supposed to send people to the App Store or Play Store, and you've noticed it just… doesn't work from Instagram or TikTok — you're not crazy. I burned a couple days on this so here's the writeup.
The problem
Instagram, TikTok, and Facebook open links in their own in-app webview, not Safari/Chrome. That webview sandboxes a bunch of navigation. On iOS specifically, I tested every client-side route to the App Store and they all dead-end (blank screen, nothing happens):
window.location/ JS redirect toapps.apple.com- a plain
<a href>tap - universal links
itms-apps:///itms-appss://schemes
What actually works: a server-side 302
The one thing the in-app webview will honor is the initial navigation being a redirect. If the very first response from your URL is a 302 whose Location is the store URL, the webview hands that off to the native store app. This is the same mechanism Linktree/Branch use under the hood.
So instead of an HTML page with redirect JS, your /get link needs to be a tiny endpoint that returns a 302 based on User-Agent. A Cloudflare Worker (free tier) does it:
const PLAY = "https://play.google.com/store/apps/details?id=YOUR.PACKAGE";
const APPSTORE = "https://apps.apple.com/app/idYOURID";
export default {
async fetch(request) {
const ua = request.headers.get("user-agent") || "";
const store = /android/i.test(ua) ? PLAY
: /iPhone|iPad|iPod/i.test(ua) ? APPSTORE
: PLAY; // desktop fallback
return new Response(null, {
status: 302,
headers: { Location: store, "Cache-Control": "no-store" },
});
},
};
Two gotchas that cost me time:
- iOS + Instagram/TikTok is still special. Even the server 302 (both
httpsanditms-appss) dead-ends inside Instagram's iOS webview specifically. The only reliable route there is the user's own "Open in external browser" menu. So for that one case I don't 302 — I serve a tiny interstitial that shows one instruction: tap ⋮ → Open in external browser. Android in-app browsers and iOS Safari all take the 302 fine; it's just IG/TikTok-on-iOS that needs the manual hop. - Don't let the edge cache your 302. Cloudflare will happily cache a bare 302 (~20 min). If you ever change the redirect logic, stale routing bites you.
Cache-Control: no-storeon the redirect fixes it.
Bonus: since the redirect is server-side, you can read utm_source off the query string and fold it into Play's &referrer= for install attribution — something you can't reliably do client-side.
Hope this saves someone the debugging. Curious if anyone's found a way around the iOS-in-app-webview limitation that doesn't need the "open in browser" step — that's the one part I couldn't fully automate.