Skip to content

Commit

Permalink
Collect timezone and allow userAgentData to be overridden (#956)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Jackins <djackins@twilio.com>
  • Loading branch information
danieljackins and danieljackins authored Sep 26, 2023
1 parent 03a0a9b commit f5cdb82
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 54 deletions.
5 changes: 5 additions & 0 deletions .changeset/cool-peaches-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@segment/analytics-next': minor
---

Set timezone and allow userAgentData to be overridden
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import { pick } from '../../../lib/pick'
import { SegmentioSettings } from '../../segmentio'
import { version } from '../../../generated/version'
import { CoreExtraContext } from '@segment/analytics-core'
import { UADataValues } from '../../../lib/client-hints/interfaces'
import {
highEntropyTestData,
lowEntropyTestData,
} from '../../../test-helpers/fixtures/client-hints'

let ajs: Analytics

Expand Down Expand Up @@ -262,6 +267,29 @@ describe('pageDefaults', () => {
describe('Other visitor metadata', () => {
let options: SegmentioSettings
let analytics: Analytics
;(window.navigator as any).userAgentData = {
...lowEntropyTestData,
getHighEntropyValues: jest
.fn()
.mockImplementation((hints: string[]): Promise<UADataValues> => {
let result = {}
Object.entries(highEntropyTestData).forEach(([k, v]) => {
if (hints.includes(k)) {
result = {
...result,
[k]: v,
}
}
})
return Promise.resolve({
...lowEntropyTestData,
...result,
})
}),
toJSON: jest.fn(() => {
return lowEntropyTestData
}),
}

const amendSearchParams = (search?: any): CoreExtraContext => ({
page: { search },
Expand All @@ -283,6 +311,11 @@ describe('Other visitor metadata', () => {
}
})

it('should add .timezone', async () => {
const ctx = await analytics.track('test')
assert(typeof ctx.event.context?.timezone === 'string')
})

it('should add .library', async () => {
const ctx = await analytics.track('test')
assert(ctx.event.context?.library)
Expand Down Expand Up @@ -313,6 +346,11 @@ describe('Other visitor metadata', () => {
assert(userAgent1 === userAgent2)
})

it('should add .userAgentData when available', async () => {
const ctx = await analytics.track('event')
expect(ctx.event.context?.userAgentData).toEqual(lowEntropyTestData)
})

it('should add .locale', async () => {
const ctx = await analytics.track('test')
assert(ctx.event.context?.locale === navigator.language)
Expand Down
19 changes: 18 additions & 1 deletion packages/browser/src/plugins/page-enrichment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { tld } from '../../core/user/tld'
import { gracefulDecodeURIComponent } from '../../core/query-string/gracefulDecodeURIComponent'
import { CookieStorage, UniversalStorage } from '../../core/storage'
import { Analytics } from '../../core/analytics'
import { clientHints } from '../../lib/client-hints'
import { UADataValues } from '../../lib/client-hints/interfaces'

interface PageDefault {
[key: string]: unknown
Expand Down Expand Up @@ -174,13 +176,21 @@ function referrerId(

class PageEnrichmentPlugin implements Plugin {
private instance!: Analytics
private userAgentData: UADataValues | undefined

name = 'Page Enrichment'
type: PluginType = 'before'
version = '0.1.0'
isLoaded = () => true
load = (_ctx: Context, instance: Analytics) => {
load = async (_ctx: Context, instance: Analytics) => {
this.instance = instance
try {
this.userAgentData = await clientHints(
this.instance.options.highEntropyValuesClientHints
)
} catch (_) {
// if client hints API doesn't return anything leave undefined
}
return Promise.resolve()
}

Expand Down Expand Up @@ -213,6 +223,7 @@ class PageEnrichmentPlugin implements Plugin {
const query: string = evtCtx.page.search || ''

evtCtx.userAgent = navigator.userAgent
evtCtx.userAgentData = this.userAgentData

// @ts-ignore
const locale = navigator.userLanguage || navigator.language
Expand Down Expand Up @@ -241,6 +252,12 @@ class PageEnrichmentPlugin implements Plugin {
this.instance.options.disableClientPersistence ?? false
)

try {
evtCtx.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
} catch (_) {
// If browser doesn't have support leave timezone undefined
}

return ctx
}

Expand Down
36 changes: 0 additions & 36 deletions packages/browser/src/plugins/segmentio/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ import { Analytics } from '../../../core/analytics'
import { Plugin } from '../../../core/plugin'
import { pageEnrichment } from '../../page-enrichment'
import cookie from 'js-cookie'
import { UADataValues } from '../../../lib/client-hints/interfaces'
import {
highEntropyTestData,
lowEntropyTestData,
} from '../../../test-helpers/fixtures/client-hints'

jest.mock('unfetch', () => {
return jest.fn()
Expand All @@ -24,29 +19,6 @@ describe('Segment.io', () => {
beforeEach(async () => {
jest.resetAllMocks()
jest.restoreAllMocks()
;(window.navigator as any).userAgentData = {
...lowEntropyTestData,
getHighEntropyValues: jest
.fn()
.mockImplementation((hints: string[]): Promise<UADataValues> => {
let result = {}
Object.entries(highEntropyTestData).forEach(([k, v]) => {
if (hints.includes(k)) {
result = {
...result,
[k]: v,
}
}
})
return Promise.resolve({
...lowEntropyTestData,
...result,
})
}),
toJSON: jest.fn(() => {
return lowEntropyTestData
}),
}

options = { apiKey: 'foo' }
analytics = new Analytics({ writeKey: options.apiKey })
Expand Down Expand Up @@ -199,14 +171,6 @@ describe('Segment.io', () => {
assert(body.traits == null)
assert(body.timestamp)
})

it('should add userAgentData when available', async () => {
await analytics.track('event')
const [_, params] = spyMock.mock.calls[0]
const body = JSON.parse(params.body)

expect(body.context?.userAgentData).toEqual(lowEntropyTestData)
})
})

describe('#group', () => {
Expand Down
19 changes: 2 additions & 17 deletions packages/browser/src/plugins/segmentio/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import standard, { StandardDispatcherConfig } from './fetch-dispatcher'
import { normalize } from './normalize'
import { scheduleFlush } from './schedule-flush'
import { SEGMENT_API_HOST } from '../../core/constants'
import { clientHints } from '../../lib/client-hints'
import { UADataValues } from '../../lib/client-hints/interfaces'

type DeliveryStrategy =
| {
Expand Down Expand Up @@ -52,11 +50,11 @@ function onAlias(analytics: Analytics, json: JSON): JSON {
return json
}

export async function segmentio(
export function segmentio(
analytics: Analytics,
settings?: SegmentioSettings,
integrations?: LegacySettings['integrations']
): Promise<Plugin> {
): Plugin {
// Attach `pagehide` before buffer is created so that inflight events are added
// to the buffer before the buffer persists events in its own `pagehide` handler.
window.addEventListener('pagehide', () => {
Expand Down Expand Up @@ -86,15 +84,6 @@ export async function segmentio(
? batch(apiHost, deliveryStrategy.config)
: standard(deliveryStrategy?.config as StandardDispatcherConfig)

let userAgentData: UADataValues | undefined
try {
userAgentData = await clientHints(
analytics.options.highEntropyValuesClientHints
)
} catch {
userAgentData = undefined
}

async function send(ctx: Context): Promise<Context> {
if (isOffline()) {
buffer.push(ctx)
Expand All @@ -107,10 +96,6 @@ export async function segmentio(

const path = ctx.event.type.charAt(0)

if (userAgentData && ctx.event.context) {
ctx.event.context.userAgentData = userAgentData
}

let json = toFacade(ctx.event).json()

if (ctx.event.type === 'track') {
Expand Down

0 comments on commit f5cdb82

Please sign in to comment.