Skip to content

Commit 5c1511f

Browse files
authored
Support loading analytics into a custom global variable when using snippet version 5.2.1+ (#1032)
1 parent c302fea commit 5c1511f

File tree

4 files changed

+164
-0
lines changed

4 files changed

+164
-0
lines changed

.changeset/kind-crabs-report.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@segment/analytics-next': minor
3+
---
4+
5+
Support loading analytics into a custom global variable when using snippet version 5.2.1 or later
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { test, expect } from '@playwright/test'
2+
import { standaloneMock } from './helpers/standalone-mock'
3+
import { extractWriteKeyFromUrl } from './helpers/extract-writekey'
4+
import { CDNSettingsBuilder } from '@internal/test-helpers'
5+
6+
test.describe('Segment with custom global key', () => {
7+
test.beforeEach(standaloneMock)
8+
test.beforeEach(async ({ context }) => {
9+
await context.route(
10+
'https://cdn.segment.com/v1/projects/*/settings',
11+
(route, request) => {
12+
if (request.method().toLowerCase() !== 'get') {
13+
return route.continue()
14+
}
15+
16+
const writeKey = extractWriteKeyFromUrl(request.url()) || 'writeKey'
17+
return route.fulfill({
18+
status: 200,
19+
headers: {
20+
'Content-Type': 'application/json',
21+
},
22+
body: JSON.stringify(new CDNSettingsBuilder({ writeKey }).build()),
23+
})
24+
}
25+
)
26+
})
27+
28+
test('supports using a custom global key', async ({ page }) => {
29+
// Load analytics.js
30+
await page.goto('/standalone-custom-key.html')
31+
await page.evaluate(() => {
32+
;(window as any).segment_analytics.track('track before load')
33+
;(window as any).segment_analytics.load('fake-key')
34+
})
35+
36+
const req = await page.waitForRequest('https://api.segment.io/v1/t')
37+
38+
// confirm that any events triggered before load have been sent
39+
expect(req.postDataJSON().event).toBe('track before load')
40+
41+
const contextObj = await page.evaluate(() =>
42+
(window as any).segment_analytics.track('track after load')
43+
)
44+
45+
// confirm that any events triggered after load return a regular context object
46+
expect(contextObj).toMatchObject(
47+
expect.objectContaining({
48+
attempts: expect.anything(),
49+
event: expect.objectContaining({ event: 'track after load' }),
50+
stats: expect.objectContaining({ metrics: expect.anything() }),
51+
})
52+
)
53+
})
54+
})
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script>
5+
!(function () {
6+
var i = 'segment_analytics',
7+
analytics = (window[i] = window[i] || [])
8+
if (!analytics.initialize)
9+
if (analytics.invoked)
10+
window.console &&
11+
console.error &&
12+
console.error('Segment snippet included twice.')
13+
else {
14+
analytics.invoked = !0
15+
analytics.methods = [
16+
'trackSubmit',
17+
'trackClick',
18+
'trackLink',
19+
'trackForm',
20+
'pageview',
21+
'identify',
22+
'reset',
23+
'group',
24+
'track',
25+
'ready',
26+
'alias',
27+
'debug',
28+
'page',
29+
'screen',
30+
'once',
31+
'off',
32+
'on',
33+
'addSourceMiddleware',
34+
'addIntegrationMiddleware',
35+
'setAnonymousId',
36+
'addDestinationMiddleware',
37+
'register',
38+
]
39+
analytics.factory = function (e) {
40+
return function () {
41+
if (window[i].initialized)
42+
return window[i][e].apply(window[i], arguments)
43+
var n = Array.prototype.slice.call(arguments)
44+
if (
45+
[
46+
'track',
47+
'screen',
48+
'alias',
49+
'group',
50+
'page',
51+
'identify',
52+
].indexOf(e) > -1
53+
) {
54+
var c = document.querySelector("link[rel='canonical']")
55+
n.push({
56+
__t: 'bpc',
57+
c: (c && c.getAttribute('href')) || void 0,
58+
p: location.pathname,
59+
u: location.href,
60+
s: location.search,
61+
t: document.title,
62+
r: document.referrer,
63+
})
64+
}
65+
n.unshift(e)
66+
analytics.push(n)
67+
return analytics
68+
}
69+
}
70+
for (var n = 0; n < analytics.methods.length; n++) {
71+
var key = analytics.methods[n]
72+
analytics[key] = analytics.factory(key)
73+
}
74+
analytics.load = function (key, n) {
75+
var t = document.createElement('script')
76+
t.type = 'text/javascript'
77+
t.async = !0
78+
t.setAttribute('data-global-segment-analytics-key', i)
79+
t.src =
80+
'https://cdn.segment.com/analytics.js/v1/' +
81+
key +
82+
'/analytics.min.js'
83+
var r = document.getElementsByTagName('script')[0]
84+
r.parentNode.insertBefore(t, r)
85+
analytics._loadOptions = n
86+
analytics._writeKey = key
87+
}
88+
analytics.SNIPPET_VERSION = '5.2.0'
89+
}
90+
})()
91+
</script>
92+
</head>
93+
<body></body>
94+
</html>

packages/browser/src/browser/standalone.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
loadAjsClassicFallback,
2929
isAnalyticsCSPError,
3030
} from '../lib/csp-detection'
31+
import { setGlobalAnalyticsKey } from '../lib/global-analytics-helper'
3132

3233
let ajsIdentifiedCSP = false
3334

@@ -71,6 +72,16 @@ async function attempt<T>(promise: () => Promise<T>) {
7172
}
7273
}
7374

75+
const globalAnalyticsKey = (
76+
document.querySelector(
77+
'script[data-global-segment-analytics-key]'
78+
) as HTMLScriptElement
79+
)?.dataset.globalSegmentAnalyticsKey
80+
81+
if (globalAnalyticsKey) {
82+
setGlobalAnalyticsKey(globalAnalyticsKey)
83+
}
84+
7485
if (shouldPolyfill()) {
7586
// load polyfills in order to get AJS to work with old browsers
7687
const script = document.createElement('script')

0 commit comments

Comments
 (0)