diff --git a/packages/browser/src/__tests__/utils/user-agent-utils.test.ts b/packages/browser/src/__tests__/utils/user-agent-utils.test.ts index 6b37f60497..2d4eb67850 100644 --- a/packages/browser/src/__tests__/utils/user-agent-utils.test.ts +++ b/packages/browser/src/__tests__/utils/user-agent-utils.test.ts @@ -205,6 +205,25 @@ describe('user-agent-utils', () => { expectedVersion: 28.0, expectedBrowser: 'Chrome', }, + { + // see https://github.com/PostHog/posthog-js/issues/3574 + // Oculus Browser is Chromium-based, so its UA includes both + // `OculusBrowser` and `Chrome` (and on newer headsets also `SamsungBrowser`). + name: 'Oculus Browser on Quest 2', + userAgent: + 'Mozilla/5.0 (X11; Linux x86_64; Quest 2) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/27.0.0.4.7.391926553 SamsungBrowser/4.0 Chrome/100.0.4896.58 VR Safari/537.36', + vendor: '', + expectedVersion: 27.0, + expectedBrowser: 'Oculus Browser', + }, + { + name: 'Oculus Browser on Quest 3 (no SamsungBrowser segment)', + userAgent: + 'Mozilla/5.0 (Linux; Android 12; Quest 3) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/30.0.0.5.10 Chrome/119.0.6045.193 VR Safari/537.36', + vendor: '', + expectedVersion: 30.0, + expectedBrowser: 'Oculus Browser', + }, ] test.each(browserTestcases)('browser version %s', ({ userAgent, vendor, expectedVersion }) => { diff --git a/packages/core/src/utils/user-agent-utils.ts b/packages/core/src/utils/user-agent-utils.ts index 4c96530d4a..28ef3ba561 100644 --- a/packages/core/src/utils/user-agent-utils.ts +++ b/packages/core/src/utils/user-agent-utils.ts @@ -49,6 +49,7 @@ const GENERIC = 'Generic' const GENERIC_MOBILE = GENERIC + ' ' + MOBILE.toLowerCase() const GENERIC_TABLET = GENERIC + ' ' + TABLET.toLowerCase() const KONQUEROR = 'Konqueror' +const OCULUS_BROWSER = 'Oculus Browser' const BROWSER_VERSION_REGEX_SUFFIX = '(\\d+(\\.\\d+)?)' const DEFAULT_BROWSER_VERSION_REGEX = new RegExp('Version/' + BROWSER_VERSION_REGEX_SUFFIX) @@ -100,6 +101,13 @@ export const detectBrowser = function (user_agent: string, vendor: string | unde } else if (includes(user_agent, 'IE' + MOBILE) || includes(user_agent, 'WPDesktop')) { return INTERNET_EXPLORER_MOBILE } + // Oculus Browser (Meta Quest) is Chromium-based, so its UA includes + // `OculusBrowser` alongside `Chrome` (and sometimes `SamsungBrowser`). + // We must check for it before those, otherwise it would be misdetected. + // See https://github.com/PostHog/posthog-js/issues/3574 + else if (includes(user_agent, 'OculusBrowser')) { + return OCULUS_BROWSER + } // https://developer.samsung.com/internet/user-agent-string-format else if (includes(user_agent, SAMSUNG_BROWSER)) { return SAMSUNG_INTERNET @@ -150,6 +158,7 @@ const versionRegexes: Record = { [BLACKBERRY]: [new RegExp(BLACKBERRY + ' ' + BROWSER_VERSION_REGEX_SUFFIX), DEFAULT_BROWSER_VERSION_REGEX], [ANDROID_MOBILE]: [new RegExp('android\\s' + BROWSER_VERSION_REGEX_SUFFIX, 'i')], [SAMSUNG_INTERNET]: [new RegExp(SAMSUNG_BROWSER + '\\/' + BROWSER_VERSION_REGEX_SUFFIX)], + [OCULUS_BROWSER]: [new RegExp('OculusBrowser\\/' + BROWSER_VERSION_REGEX_SUFFIX)], [INTERNET_EXPLORER]: [new RegExp('(rv:|MSIE )' + BROWSER_VERSION_REGEX_SUFFIX)], Mozilla: [new RegExp('rv:' + BROWSER_VERSION_REGEX_SUFFIX)], }