Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions packages/browser/src/__tests__/utils/user-agent-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => {
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/utils/user-agent-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -150,6 +158,7 @@ const versionRegexes: Record<string, RegExp[]> = {
[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)],
}
Expand Down