f2etw / detect-inapp

detect browser or in-app information for mobile
https://f2etw.github.io/detect-inapp
251 stars 31 forks source link

Incorrectly detecting chrome on android as an InApp browser #52

Open reqyo opened 1 year ago

reqyo commented 1 year ago

Please look into this, seems like being on android and chrome I'm getting it as an inapp browser. Thank you

aggy-k commented 11 months ago

Same here, it's detecting android's chrome as inApp. Here's the User-Agent: Mozilla/5.0 (Linux: Android10; K) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/119.0.0.0 MobileSafari/537.36

I tested this UA against the isInApp regex rules, and it does return FALSE, so not sure why it's returning TRUE for our users. Thank you!

brunofin commented 10 months ago

That's because isInApp matches the string Android as an in app browser, which is wrong: https://github.com/f2etw/detect-inapp/blob/master/src/inapp.js#L42

https://chat.openai.com/share/98549886-db01-4c4c-8c9c-5c3bce26ea42

I guess what could be done is to use the browser function https://github.com/f2etw/detect-inapp/blob/master/src/inapp.js#L26 and manually compare with the returned value.

brunofin commented 10 months ago

here are some user agent strings I got from my own testing. Notice Facebook in-app browser is the only one that contains FB_IAB and Instagram contains Instagram. Those are simple effective methods to test whether the user is accessig from an in-app browser while avoiding false positives such as the one described in this issue.

chrome on linux
    Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36

firefox on linux
    Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0

edge on linux
    Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0

chrome on android
    Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36

firefox on android
    Mozilla/5.0 (Android 14; Mobile; rv:121.0) Gecko/121.0 Firefox/121.0

facebook in app broswer on android
    Mozilla/5.0 (Linux; Android 14; Pixel 6 Build/UQ1A.240105.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/120.0.6099.193 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/446.0.0.27.352;]

instagram in app browser on android
    Mozilla/5.0 (Linux; Android 14; Pixel 6 Build/UQ1A.240105.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/120.0.6099.193 Mobile Safari/537.36 Instagram 313.0.0.26.328 Android (34/14; 420dpi; 1080x2209; Google/google; Pixel 6; oriole; oriole; en_GB; 554218560)
brunofin commented 10 months ago

one more interesting thing to notice is that on linux browsers even though I am on a Wayland session they still report the string x11.

shalanah commented 9 months ago

Here's what I did: https://github.com/f2etw/detect-inapp/compare/master...shalanah:detect-inapp:shalanah-build

'Android.*(wv|/\\d\\d.0.0.0)',

Feel free to use this in your packages: "detect-inapp": "github:shalanah/detect-inapp#shalanah-build"

I'm also created a debugging page to help test on my devices. https://shalanah.github.io/inapp-debugger/

brunofin commented 9 months ago

I actually ended up removing this package and using a custom solution because none of the other alternative solutions on npm worked properly. Below is the full code. It also works with SSR. This is production tested with a large user base.

/* set of Regex to compare against user agent in order to detect any kind of embedded in app browser */
const IAB = [
  /Instagram/,
  /FB_IAB/,
  /FBAN/,
  /FBIOS/,
  /FBAV/,
  /FBBV/,
  /FBDV/,
  /FBMD/,
  /FBSN/,
  /FBSV/,
  /FBSS/,
  /FBID/,
  /FBLC/,
  /FBOP/,
  /FBRV/,
];

export function isInApp(): boolean {
  if (!isBrowser()) return false;

  const { userAgent } = navigator;
  return IAB.some(value => value.test(userAgent));
}

// nextjs specific implementation of isBrowser
export function isBrowser() {
  if (!process) return false;
  const nextjsProcess = process as NextJSProcess;
  return nextjsProcess.browser === true;
}

This is obviously only checking against Facebook and Instagram at the moment but it works reliably across iOS and Android, old and new versions.

brunofin commented 9 months ago

If you are planning to use this to remove users from in app browsers, the following implementation below works on Android. I am still to find an alternative iOS version for that.

// ...
if (isInApp) {
      // attempt to exit for android;
      const currentLocation = location.origin + location.pathname;
      // @ts-ignore
      window.location = `intent:${currentLocation}#Intent;end`;
// ...

This will open a browser dialog telling users the site is trying to open an app and if they accept. The app is their default browser.

You can aggressively run it on a loop, or first show a full screen modal that cant be closed saying the browser is not supported and make a button with that as a link, either will work and force users out of the in app browsers.

shalanah commented 9 months ago

@brunofin I think a pared down in-app detection is a great idea! Like you noted, I'd need more detection like linkedin, tiktok, etc.

shalanah commented 9 months ago

Also interesting --- would love if Bowser took this on since I'm using it anyway: https://github.com/bowser-js/bowser/pull/452

shalanah commented 9 months ago

@brunofin + all .

I just pushed a fork (with API changes) and created an npm package.

I hope to continue the legacy of detect-inapp and keep it as up-to-date as I can.

To install:

npm install inapp-spy
yarn add inapp-spy

To use (slightly different API)

import InAppSpy from 'inapp-spy';

const {isInApp, appName, appKey} = InAppSpy()

Link to repo: https://github.com/shalanah/inapp-spy

I removed the is mobile, desktop, tablet along with common browsers like "Safari" and "Chrome". I'd recommend bowser to handle that kind of info.