Skip to main content

isInAppBrowser()

true when the page is loaded inside a mobile in-app browser — the embedded WebView that social and messaging apps use when you tap a link in-app.

Signature(options?: DetectOptions) => boolean
SSR safe✅ Pass { userAgent } to pin
Bundle cost~130 B incremental on top of an existing get-browser import. 0 B when tree-shaken out.

Why this matters

In-app browsers look like regular browsers but break in subtle ways that ship-stopping. The most painful:

SurfaceBehaviour
OAuth sign-inGoogle, Apple, and Microsoft explicitly block sign-in inside third-party WebViews. Users see a generic "this browser is not supported" error and bail.
Deep linkstarget="_blank", custom URL schemes, and app-store redirects often open inside the WebView or fail silently.
PaymentsApple Pay, Google Pay, Stripe redirect flows, and PayPal sandbox all expect a top-level browsing context the WebView doesn't provide.
PWA install / pushService workers register but never wake up — the WebView dies when the parent app closes.
AnalyticsWithout this signal, Instagram-traffic and Safari-traffic look identical and conversion rates lie to you.

If you sell a product, run a SaaS sign-up, or care about funnel completion: detecting this is non-optional.

Detected apps

AppUA token(s) matched
FacebookFBAN/, FBAV/, FB_IAB/
InstagramInstagram
X / TwitterTwitter for iPhone / Twitter for iPad, TwitterAndroid
LinkedInLinkedInApp
TikTokTikTok, musical_ly_<v>, Trill_<v> (legacy / regional builds; the trailing _ keeps the matcher from colliding with Triller and other look-alikes)
SnapchatSnapchat
WeChatWeChat, MicroMessenger
LineLine/
TelegramTelegram
PinterestPinterest

The list is curated for the apps that genuinely break the surfaces above. Desktop Electron apps (Slack, Discord, Microsoft Teams) are not caught — they ship a full Chromium without the WebView pitfalls.

Examples

import { isInAppBrowser } from 'get-browser';

// `startOAuth` is your normal SDK / NextAuth / Clerk handler.
declare function startOAuth(): void;

export function SignInButton() {
if (isInAppBrowser()) {
// Render an anchor (not a button) so the in-app browser treats the click
// as a navigation. A server endpoint can issue a 302 to the OAuth URL with
// a special `target=_system`-style header — most WebViews respect that and
// hand the flow off to Safari / Chrome.
return (
<a href="/auth/oauth-bounce" className="cta">
Continue with Google (opens in your browser)
</a>
);
}
return <button onClick={startOAuth}>Sign in with Google</button>;
}

Composes with other predicates

isInAppBrowser is orthogonal to detect(), getOS(), and the browser-family predicates. A Facebook user on Android is all of: an Android OS, an Android system WebView, and an in-app browser — every detector reports its own dimension correctly.

import { detect, getOS, isInAppBrowser, isAndroid, isMobile } from 'get-browser';

// Inside Facebook on a Pixel 8:
detect(); // → 'chrome' (the underlying engine)
getOS(); // → 'android' (the OS)
isAndroid(); // → true (Android system WebView)
isMobile(); // → true (yep)
isInAppBrowser(); // → true (it's Facebook)

Caveats

The token list moves slowly, but it moves

UA tokens for these apps are quite stable — FBAN/FBAV have been around since Facebook for iOS shipped. But new apps appear, and apps occasionally rebrand (TikTok was musical_ly). If you spot a missing app shipping a distinctive UA fragment, an issue / PR with the real UA is welcome.

Desktop in-app contexts

Slack, Discord, Microsoft Teams desktop apps are Electron — full Chromium. They're not caught here because they don't have the OAuth / deep-link pitfalls of the mobile WebViews. If your product treats them as in-app for analytics, layer your own check.

Versions

The matchers anchor on the app tokens, not on version. A Facebook UA from 2019 and a Facebook UA from 2026 both report true — version bumps don't break detection.

See also