@guardian/ophan-tracker-js 4.0.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NPM-dist/adblock-detection.js +17 -11
- package/NPM-dist/adblock-detection.js.map +1 -0
- package/NPM-dist/attention.js +32 -19
- package/NPM-dist/attention.js.map +1 -0
- package/NPM-dist/campaign.js +6 -2
- package/NPM-dist/campaign.js.map +1 -0
- package/NPM-dist/click-path-capture.js +5 -2
- package/NPM-dist/click-path-capture.js.map +1 -0
- package/NPM-dist/components.js +1 -0
- package/NPM-dist/components.js.map +1 -0
- package/NPM-dist/contribution.js +1 -0
- package/NPM-dist/contribution.js.map +1 -0
- package/NPM-dist/core.js +40 -10
- package/NPM-dist/core.js.map +1 -0
- package/NPM-dist/embed.js +1 -0
- package/NPM-dist/embed.js.map +1 -0
- package/NPM-dist/fb-instant.js +1 -0
- package/NPM-dist/fb-instant.js.map +1 -0
- package/NPM-dist/heatmap.js +4 -0
- package/NPM-dist/heatmap.js.map +1 -0
- package/NPM-dist/holidays.js +1 -0
- package/NPM-dist/holidays.js.map +1 -0
- package/NPM-dist/http-status.js +1 -0
- package/NPM-dist/http-status.js.map +1 -0
- package/NPM-dist/iframe-tracking.js +16 -3
- package/NPM-dist/iframe-tracking.js.map +1 -0
- package/NPM-dist/index.js +285 -0
- package/NPM-dist/index.js.map +1 -0
- package/NPM-dist/interactive.js +1 -0
- package/NPM-dist/interactive.js.map +1 -0
- package/NPM-dist/jobs-courses.js +1 -0
- package/NPM-dist/jobs-courses.js.map +1 -0
- package/NPM-dist/jobs.js +1 -0
- package/NPM-dist/jobs.js.map +1 -0
- package/NPM-dist/membership.js +1 -0
- package/NPM-dist/membership.js.map +1 -0
- package/NPM-dist/ng.js +10 -33
- package/NPM-dist/ng.js.map +1 -0
- package/NPM-dist/perf.js +3 -2
- package/NPM-dist/perf.js.map +1 -0
- package/NPM-dist/privatebrowsing.js +1 -0
- package/NPM-dist/privatebrowsing.js.map +1 -0
- package/NPM-dist/r2.js +8 -4
- package/NPM-dist/r2.js.map +1 -0
- package/NPM-dist/smart-news.js +10 -3
- package/NPM-dist/smart-news.js.map +1 -0
- package/NPM-dist/tests/attention.test.js +1 -0
- package/NPM-dist/tests/attention.test.js.map +1 -0
- package/NPM-dist/tests/click-path-capture.test.js +1 -0
- package/NPM-dist/tests/click-path-capture.test.js.map +1 -0
- package/NPM-dist/tests/components.test.js +1 -0
- package/NPM-dist/tests/components.test.js.map +1 -0
- package/NPM-dist/tests/core.test.js +1 -0
- package/NPM-dist/tests/core.test.js.map +1 -0
- package/NPM-dist/tests/heatmap.test.js +1 -0
- package/NPM-dist/tests/heatmap.test.js.map +1 -0
- package/NPM-dist/tests/index.test.js +18 -0
- package/NPM-dist/tests/index.test.js.map +1 -0
- package/NPM-dist/tests/transmit.test.js +1 -0
- package/NPM-dist/tests/transmit.test.js.map +1 -0
- package/NPM-dist/transmit.js +23 -5
- package/NPM-dist/transmit.js.map +1 -0
- package/NPM-dist/types/abtest.js +1 -0
- package/NPM-dist/types/abtest.js.map +1 -0
- package/NPM-dist/types/adblock-detection.d.ts +1 -0
- package/NPM-dist/types/adblock-detection.d.ts.map +1 -0
- package/NPM-dist/types/attention.d.ts +1 -0
- package/NPM-dist/types/attention.d.ts.map +1 -0
- package/NPM-dist/types/campaign.d.ts +1 -0
- package/NPM-dist/types/campaign.d.ts.map +1 -0
- package/NPM-dist/types/click-path-capture.d.ts +1 -0
- package/NPM-dist/types/click-path-capture.d.ts.map +1 -0
- package/NPM-dist/types/component-event.js +1 -0
- package/NPM-dist/types/component-event.js.map +1 -0
- package/NPM-dist/types/component-type.js +1 -0
- package/NPM-dist/types/component-type.js.map +1 -0
- package/NPM-dist/types/components.d.ts +1 -0
- package/NPM-dist/types/components.d.ts.map +1 -0
- package/NPM-dist/types/consent.js +1 -0
- package/NPM-dist/types/consent.js.map +1 -0
- package/NPM-dist/types/contribution.d.ts +2 -1
- package/NPM-dist/types/contribution.d.ts.map +1 -0
- package/NPM-dist/types/core.d.ts +1 -0
- package/NPM-dist/types/core.d.ts.map +1 -0
- package/NPM-dist/types/embed.d.ts +2 -1
- package/NPM-dist/types/embed.d.ts.map +1 -0
- package/NPM-dist/types/event.js +1 -0
- package/NPM-dist/types/event.js.map +1 -0
- package/NPM-dist/types/fb-instant.d.ts +1 -0
- package/NPM-dist/types/fb-instant.d.ts.map +1 -0
- package/NPM-dist/types/heatmap.d.ts +1 -0
- package/NPM-dist/types/heatmap.d.ts.map +1 -0
- package/NPM-dist/types/holidays.d.ts +2 -1
- package/NPM-dist/types/holidays.d.ts.map +1 -0
- package/NPM-dist/types/http-status.d.ts +1 -0
- package/NPM-dist/types/http-status.d.ts.map +1 -0
- package/NPM-dist/types/iframe-tracking.d.ts +1 -0
- package/NPM-dist/types/iframe-tracking.d.ts.map +1 -0
- package/NPM-dist/types/index.d.ts +199 -0
- package/NPM-dist/types/index.d.ts.map +1 -0
- package/NPM-dist/types/inpageclick.js +1 -0
- package/NPM-dist/types/inpageclick.js.map +1 -0
- package/NPM-dist/types/interaction.js +1 -0
- package/NPM-dist/types/interaction.js.map +1 -0
- package/NPM-dist/types/interactive.d.ts +1 -0
- package/NPM-dist/types/interactive.d.ts.map +1 -0
- package/NPM-dist/types/jobs-courses.d.ts +2 -1
- package/NPM-dist/types/jobs-courses.d.ts.map +1 -0
- package/NPM-dist/types/jobs.d.ts +2 -1
- package/NPM-dist/types/jobs.d.ts.map +1 -0
- package/NPM-dist/types/link.js +1 -0
- package/NPM-dist/types/link.js.map +1 -0
- package/NPM-dist/types/media.js +1 -0
- package/NPM-dist/types/media.js.map +1 -0
- package/NPM-dist/types/membership.d.ts +2 -1
- package/NPM-dist/types/membership.d.ts.map +1 -0
- package/NPM-dist/types/ng.d.ts +2 -13
- package/NPM-dist/types/ng.d.ts.map +1 -0
- package/NPM-dist/types/perf.d.ts +2 -1
- package/NPM-dist/types/perf.d.ts.map +1 -0
- package/NPM-dist/types/platform.js +1 -0
- package/NPM-dist/types/platform.js.map +1 -0
- package/NPM-dist/types/printproduct.js +1 -0
- package/NPM-dist/types/printproduct.js.map +1 -0
- package/NPM-dist/types/privatebrowsing.d.ts +1 -0
- package/NPM-dist/types/privatebrowsing.d.ts.map +1 -0
- package/NPM-dist/types/product.js +1 -0
- package/NPM-dist/types/product.js.map +1 -0
- package/NPM-dist/types/r2.d.ts +1 -0
- package/NPM-dist/types/r2.d.ts.map +1 -0
- package/NPM-dist/types/smart-news.d.ts +2 -1
- package/NPM-dist/types/smart-news.d.ts.map +1 -0
- package/NPM-dist/types/subscription.js +1 -0
- package/NPM-dist/types/subscription.js.map +1 -0
- package/NPM-dist/types/tests/attention.test.d.ts +1 -0
- package/NPM-dist/types/tests/attention.test.d.ts.map +1 -0
- package/NPM-dist/types/tests/click-path-capture.test.d.ts +1 -0
- package/NPM-dist/types/tests/click-path-capture.test.d.ts.map +1 -0
- package/NPM-dist/types/tests/components.test.d.ts +1 -0
- package/NPM-dist/types/tests/components.test.d.ts.map +1 -0
- package/NPM-dist/types/tests/core.test.d.ts +1 -0
- package/NPM-dist/types/tests/core.test.d.ts.map +1 -0
- package/NPM-dist/types/tests/heatmap.test.d.ts +1 -0
- package/NPM-dist/types/tests/heatmap.test.d.ts.map +1 -0
- package/NPM-dist/types/tests/index.test.d.ts +2 -0
- package/NPM-dist/types/tests/index.test.d.ts.map +1 -0
- package/NPM-dist/types/tests/transmit.test.d.ts +1 -0
- package/NPM-dist/types/tests/transmit.test.d.ts.map +1 -0
- package/NPM-dist/types/transmit.d.ts +1 -0
- package/NPM-dist/types/transmit.d.ts.map +1 -0
- package/NPM-dist/types/types/abtest.d.ts +1 -0
- package/NPM-dist/types/types/abtest.d.ts.map +1 -0
- package/NPM-dist/types/types/component-event.d.ts +15 -0
- package/NPM-dist/types/types/component-event.d.ts.map +1 -0
- package/NPM-dist/types/types/component-type.d.ts +7 -0
- package/NPM-dist/types/types/component-type.d.ts.map +1 -0
- package/NPM-dist/types/types/consent.d.ts +1 -0
- package/NPM-dist/types/types/consent.d.ts.map +1 -0
- package/NPM-dist/types/types/event.d.ts +11 -0
- package/NPM-dist/types/types/event.d.ts.map +1 -0
- package/NPM-dist/types/types/inpageclick.d.ts +1 -0
- package/NPM-dist/types/types/inpageclick.d.ts.map +1 -0
- package/NPM-dist/types/types/interaction.d.ts +1 -0
- package/NPM-dist/types/types/interaction.d.ts.map +1 -0
- package/NPM-dist/types/types/link.d.ts +1 -0
- package/NPM-dist/types/types/link.d.ts.map +1 -0
- package/NPM-dist/types/types/media.d.ts +1 -0
- package/NPM-dist/types/types/media.d.ts.map +1 -0
- package/NPM-dist/types/types/platform.d.ts +1 -0
- package/NPM-dist/types/types/platform.d.ts.map +1 -0
- package/NPM-dist/types/types/printproduct.d.ts +1 -0
- package/NPM-dist/types/types/printproduct.d.ts.map +1 -0
- package/NPM-dist/types/types/product.d.ts +7 -0
- package/NPM-dist/types/types/product.d.ts.map +1 -0
- package/NPM-dist/types/types/subscription.d.ts +1 -0
- package/NPM-dist/types/types/subscription.d.ts.map +1 -0
- package/NPM-dist/types/vendor/adBlockDetectionLib.d.ts +3 -1
- package/NPM-dist/types/vendor/adBlockDetectionLib.d.ts.map +1 -0
- package/NPM-dist/types/visibility.d.ts +2 -1
- package/NPM-dist/types/visibility.d.ts.map +1 -0
- package/NPM-dist/types/witness.d.ts +2 -1
- package/NPM-dist/types/witness.d.ts.map +1 -0
- package/NPM-dist/vendor/adBlockDetectionLib.js +19 -6
- package/NPM-dist/vendor/adBlockDetectionLib.js.map +1 -0
- package/NPM-dist/visibility.js +14 -5
- package/NPM-dist/visibility.js.map +1 -0
- package/NPM-dist/witness.js +1 -0
- package/NPM-dist/witness.js.map +1 -0
- package/package.json +12 -26
- package/readme.md +112 -53
- package/src/index.ts +360 -0
- package/src/ng.ts +33 -0
- package/src/transmit.ts +176 -0
- package/src/types/abtest.ts +45 -0
- package/src/types/component-event.ts +121 -0
- package/src/types/component-type.ts +70 -0
- package/src/types/consent.ts +49 -0
- package/src/types/event.ts +116 -0
- package/src/types/inpageclick.ts +13 -0
- package/src/types/interaction.ts +19 -0
- package/src/types/link.ts +14 -0
- package/src/types/media.ts +184 -0
- package/src/types/platform.ts +32 -0
- package/src/types/printproduct.ts +53 -0
- package/src/types/product.ts +72 -0
- package/src/types/subscription.ts +70 -0
- package/NPM-dist/manage-my-account.js +0 -46
- package/NPM-dist/support.js +0 -45
- package/NPM-dist/types/manage-my-account.d.ts +0 -28
- package/NPM-dist/types/support.d.ts +0 -28
package/readme.md
CHANGED
|
@@ -10,76 +10,128 @@ $ npm install @guardian/ophan-tracker-js
|
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
|
-
Tracker JS
|
|
13
|
+
Tracker JS is available as both an NPM package and a CDN distribution.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
- `manage-my-account.js` for manage.theguardian.com
|
|
17
|
-
- `support.js` for support.theguardian.com
|
|
18
|
-
- `membership.js` for membership-related sections
|
|
15
|
+
### NPM Package
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
The NPM package uses a unified entry point that supports multiple platforms. Import it eagerly and call `init()` once for your platform before calling any other tracker method. The platform defaults to `ng` when omitted or unrecognised at runtime.
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
**NPM Supported Platforms**
|
|
20
|
+
|
|
21
|
+
- `ng` (short for next-gen) for theguardian.com
|
|
22
|
+
- `manage-my-account` for manage.theguardian.com
|
|
23
|
+
- `support` for support.theguardian.com
|
|
24
|
+
|
|
25
|
+
**Default behaviour**
|
|
26
|
+
|
|
27
|
+
The default entry point for the library is `@guardian/ophan-tracker-js`, which resolves to `NPM-dist/index.js`. Calling `init()` starts the tracker for the chosen platform and sends the initial page-view event. Use `record()` for additional events. Use `sendInitialEvent()` only when you intentionally need a new page-view event, for example after a single-page app route change.
|
|
28
|
+
|
|
29
|
+
If a tracker method is called before `init()` in a browser context, the method warns and does not send the event. In server-side rendering or other non-browser contexts, tracker methods return without touching browser globals.
|
|
30
|
+
|
|
31
|
+
### CDN Distribution
|
|
32
|
+
|
|
33
|
+
The CDN version provides individual entry points for specific use cases, available at `https://j.ophan.co.uk/`. These entry points initialise themselves for their historical platform and are kept for existing CDN consumers:
|
|
34
|
+
|
|
35
|
+
- `contribution.js` - Contribution tracking
|
|
36
|
+
- `embed.js` - For embedded content
|
|
37
|
+
- `fb-instant.js` - For Facebook Instant Articles
|
|
38
|
+
- `holidays.js` - Guardian Holidays
|
|
39
|
+
- `http-status.js` - HTTP status page tracking
|
|
40
|
+
- `interactive.js` - For Guardian interactives
|
|
41
|
+
- `jobs.js` - For Guardian Jobs site
|
|
42
|
+
- `jobs-courses.js` - For Guardian Jobs courses site
|
|
43
|
+
- `membership.js` - For Guardian membership (old site)
|
|
44
|
+
- `ng.js` - For theguardian.com
|
|
45
|
+
- `r2.js` - Legacy R2 platform tracking
|
|
46
|
+
- `smart-news.js` - SmartNews platform tracking
|
|
47
|
+
- `witness.js` - GuardianWitness tracking
|
|
24
48
|
|
|
25
49
|
You can see example usage of the library on theguardian.com [here](https://github.com/guardian/dotcom-rendering/blob/main/dotcom-rendering/src/client/ophan/ophan.ts)
|
|
26
50
|
|
|
27
|
-
1. **Import and
|
|
51
|
+
1. **Import and initialise the library:**
|
|
28
52
|
|
|
29
|
-
The library should be imported and
|
|
53
|
+
The library should be imported and initialised eagerly (non-lazily) to ensure proper initialisation. The exact syntax may vary depending on your build tool or environment.
|
|
30
54
|
|
|
31
55
|
```javascript
|
|
32
|
-
import
|
|
56
|
+
import { init, record } from '@guardian/ophan-tracker-js';
|
|
57
|
+
|
|
58
|
+
// Initialise for your platform. This sends the initial page-view event.
|
|
59
|
+
init('ng'); // or 'manage-my-account' or 'support'
|
|
33
60
|
```
|
|
34
61
|
|
|
35
|
-
2. **Send Tracking Events with `
|
|
62
|
+
2. **Send Tracking Events with `record()`:**
|
|
36
63
|
|
|
37
64
|
```javascript
|
|
38
|
-
|
|
39
|
-
|
|
65
|
+
record({
|
|
66
|
+
edition: 'UK',
|
|
40
67
|
});
|
|
41
68
|
```
|
|
42
69
|
|
|
43
|
-
### Usage with
|
|
70
|
+
### Usage with TypeScript
|
|
71
|
+
|
|
72
|
+
The package exports TypeScript declarations, declaration maps, and source files. Editors should let you click through from `record()` to `EventPayload`, `ComponentEvent`, `Product`, and the related union types in [`src/types/event.ts`](/tracker-js/src/types/event.ts) and the neighbouring type files.
|
|
44
73
|
|
|
45
|
-
|
|
74
|
+
When you pass an object literal to `record()`, TypeScript will reject unknown top-level fields and invalid nested values such as unsupported component actions, component types, products, or editions. If you need to add a new event type or property, update the tracker-js types and the downstream Ophan model deliberately.
|
|
46
75
|
|
|
47
76
|
#### Example Usage
|
|
48
77
|
|
|
49
78
|
```typescript
|
|
50
|
-
import
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
79
|
+
import {
|
|
80
|
+
getViewId,
|
|
81
|
+
init,
|
|
82
|
+
record,
|
|
83
|
+
sendInitialEvent,
|
|
84
|
+
} from '@guardian/ophan-tracker-js';
|
|
85
|
+
import type {
|
|
86
|
+
EventPayload,
|
|
87
|
+
Product,
|
|
88
|
+
ComponentEvent,
|
|
89
|
+
AbTest,
|
|
90
|
+
} from '@guardian/ophan-tracker-js';
|
|
91
|
+
|
|
92
|
+
// Initialise the library for your platform. This sends the initial page-view event.
|
|
93
|
+
init('ng'); // or 'manage-my-account' or 'support'
|
|
94
|
+
|
|
95
|
+
const exampleProduct: Product = 'APP_PREMIUM_TIER';
|
|
54
96
|
const exampleAbTest: AbTest = {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
97
|
+
name: 'myAbTest',
|
|
98
|
+
variant: 'variant',
|
|
99
|
+
campaignCodes: ['code1', 'code2'],
|
|
58
100
|
};
|
|
59
101
|
|
|
60
102
|
const componentV2 = {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
103
|
+
componentType: 'ACQUISITIONS_BUTTON',
|
|
104
|
+
id: 'component-id',
|
|
105
|
+
products: [exampleProduct],
|
|
106
|
+
campaignCode: 'campaign-code',
|
|
107
|
+
labels: ['label1', 'label2'],
|
|
66
108
|
};
|
|
67
109
|
|
|
68
110
|
const componentEvent: ComponentEvent = {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
111
|
+
component: componentV2,
|
|
112
|
+
action: 'CLICK',
|
|
113
|
+
value: 'some-value',
|
|
114
|
+
id: 'event-id',
|
|
115
|
+
abTest: exampleAbTest,
|
|
116
|
+
targetingAbTest: exampleAbTest,
|
|
75
117
|
};
|
|
76
118
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
119
|
+
const payload: EventPayload = {
|
|
120
|
+
componentEvent: componentEvent,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
record(payload);
|
|
124
|
+
|
|
125
|
+
const currentViewId = getViewId();
|
|
126
|
+
|
|
127
|
+
// Use sendInitialEvent() only when intentionally creating a new page view,
|
|
128
|
+
// for example after a single-page app route change.
|
|
129
|
+
sendInitialEvent();
|
|
80
130
|
```
|
|
81
131
|
|
|
82
|
-
|
|
132
|
+
`getViewId()` and `getPageViewId()` return the current live page view ID. The default export also exposes `viewId` and `pageViewId` as getters for compatibility with object-style consumers.
|
|
133
|
+
|
|
134
|
+
If you would like to add a new event type or event property which does not exist, please [contact the Ophan team](mailto:Ophan.Dev@guardian.co.uk).
|
|
83
135
|
|
|
84
136
|
### Sending events straight to the backend
|
|
85
137
|
|
|
@@ -91,9 +143,9 @@ The backend of tracker exposes two endpoints, `img/1` which takes in page view e
|
|
|
91
143
|
|
|
92
144
|
The library is implemented using both Javascript and TypeScript, with the source code located in the `src` directory and its subdirectories. The project is set up to include both TypeScript (.ts) and JavaScript (.js) files, allowing for a mix of both languages in the library's implementation.
|
|
93
145
|
|
|
94
|
-
Typescript interfaces and types are developed in the `types` folder.
|
|
146
|
+
Typescript interfaces and types are developed in the `src/types` folder.
|
|
95
147
|
|
|
96
|
-
The TypeScript compiler is configured to generate compiled JavaScript files and corresponding declaration files (
|
|
148
|
+
The TypeScript compiler is configured to generate compiled JavaScript files and corresponding declaration files (`.d.ts`) in the `NPM-dist` directory. The declaration files provide type information for the library's public API, and declaration maps point editors back to the source files.
|
|
97
149
|
|
|
98
150
|
## Compile
|
|
99
151
|
|
|
@@ -101,20 +153,26 @@ The TypeScript compiler is configured to generate compiled JavaScript files and
|
|
|
101
153
|
.../ophan/tracker-js $ npm run build-for-npm
|
|
102
154
|
```
|
|
103
155
|
|
|
156
|
+
## Type checks
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
.../ophan/tracker-js $ npm run test:types
|
|
160
|
+
```
|
|
161
|
+
|
|
104
162
|
#### Proxy tracker-js:
|
|
105
163
|
|
|
106
164
|
1. Install dependencies
|
|
107
165
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
166
|
+
```
|
|
167
|
+
$ brew install lighttpd
|
|
168
|
+
.../ophan/tracker-js $ npm install
|
|
169
|
+
```
|
|
112
170
|
|
|
113
171
|
2. In another terminal window:
|
|
114
172
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
173
|
+
```
|
|
174
|
+
.../ophan/tracker-js $ lighttpd -f lighttpd.conf -D
|
|
175
|
+
```
|
|
118
176
|
|
|
119
177
|
3. Install FoxyProxy (https://getfoxyproxy.org/downloads/) in your browser and create a rule that forces j.ophan.co.uk
|
|
120
178
|
to localhost 8000. (For me FoxyProxy needed a few switches on and off before it decided to start talking to lighttpd.)
|
|
@@ -131,7 +189,7 @@ The TypeScript compiler is configured to generate compiled JavaScript files and
|
|
|
131
189
|
|
|
132
190
|
### Two formats for release
|
|
133
191
|
|
|
134
|
-
When you make a change to Tracker JS, you must release on
|
|
192
|
+
When you make a change to Tracker JS, you must release on _both_ these systems:
|
|
135
193
|
|
|
136
194
|
#### NPM
|
|
137
195
|
|
|
@@ -139,9 +197,9 @@ We use `changesets` for automated publishing of the NPM package:
|
|
|
139
197
|
|
|
140
198
|
1. Add a changeset, run the following command and follow the instructions
|
|
141
199
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
200
|
+
```
|
|
201
|
+
.../ophan/tracker-js $ npx changeset
|
|
202
|
+
```
|
|
145
203
|
|
|
146
204
|
2. When you raise a PR, the changeset bot won’t correctly see that you have included a changeset – it only checks for the .changesets folder in the root of the repository, whereas we have it in a subdirectory. Don’t worry.
|
|
147
205
|
|
|
@@ -149,15 +207,16 @@ We use `changesets` for automated publishing of the NPM package:
|
|
|
149
207
|
|
|
150
208
|
#### S3 Bucket
|
|
151
209
|
|
|
152
|
-
|
|
210
|
+
- [https://j.ophan.co.uk/](https://j.ophan.co.uk/jobs.js) - CDN/S3, [deployed through RiffRaff](https://riffraff.gutools.co.uk/deployment/history?projectName=ophan%3A%3Aophan-tracker-js&page=1) and used by some Guardian sites like https://jobs.theguardian.com/. An advantage of this approach is that sites using it immediately get Tracker JS updates, without developer intervention.
|
|
153
211
|
|
|
154
212
|
#### Rollup
|
|
155
213
|
|
|
156
214
|
The generated files from Rollup (using the `build-for-cdn` script in `package.json`) are only used for publishing to the CDN to use SystemJS / AMD
|
|
157
215
|
|
|
158
216
|
## Post publish
|
|
217
|
+
|
|
159
218
|
Post publish it would be good practice to inform the teams using Tracker-JS about the update.
|
|
160
219
|
|
|
161
220
|
See the [google doc ](https://docs.google.com/document/d/1MndFG-DLDQAMHIi55T4kZkGq4ONcded1-MDd9QS_NZE/edit?tab=t.0) for a list of teams depending on tracker-js.
|
|
162
221
|
|
|
163
|
-
If the change to tracker-js is small, we could raise a quick PR in the relevant repo and ask the team to review it.
|
|
222
|
+
If the change to tracker-js is small, we could raise a quick PR in the relevant repo and ask the team to review it.
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import core from './core.js';
|
|
2
|
+
import transmit from './transmit.js';
|
|
3
|
+
import attention from './attention.js';
|
|
4
|
+
import visibility from './visibility.js';
|
|
5
|
+
import privatebrowsing from './privatebrowsing.js';
|
|
6
|
+
import heatmap from './heatmap.js';
|
|
7
|
+
|
|
8
|
+
import './click-path-capture.js';
|
|
9
|
+
import './perf.js';
|
|
10
|
+
import './iframe-tracking.js';
|
|
11
|
+
import './campaign.js';
|
|
12
|
+
|
|
13
|
+
import { EventPayload } from './types/event.js';
|
|
14
|
+
import clickPathCapture from './click-path-capture.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Product surface that is initialising the tracker.
|
|
18
|
+
*
|
|
19
|
+
* The platform controls the historical Ophan serving-platform value and any
|
|
20
|
+
* platform-specific browser integrations started by `init()`.
|
|
21
|
+
*/
|
|
22
|
+
export type Platform = 'ng' | 'manage-my-account' | 'support';
|
|
23
|
+
|
|
24
|
+
const isBrowser = (): boolean =>
|
|
25
|
+
typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
26
|
+
|
|
27
|
+
let initialized = false;
|
|
28
|
+
let currentPlatform: Platform | null = null;
|
|
29
|
+
|
|
30
|
+
const warnIfUninitialized = (methodName: string): void => {
|
|
31
|
+
console.warn(
|
|
32
|
+
`Ophan tracker ${methodName}() called before init(); ignoring event.`,
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const canUseTracker = (methodName: string): boolean => {
|
|
37
|
+
if (!isBrowser()) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!initialized) {
|
|
42
|
+
warnIfUninitialized(methodName);
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return true;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Initialise the Ophan tracker for a specific platform.
|
|
51
|
+
*
|
|
52
|
+
* Call this once, eagerly, in a browser context before using the other tracker
|
|
53
|
+
* methods. Initialisation sends the first page-view event.
|
|
54
|
+
*
|
|
55
|
+
* @param platform - The platform identifier ('ng' for next-gen Guardian sites, 'manage-my-account', or 'support'). Defaults to 'ng'.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```javascript
|
|
59
|
+
* import { init } from '@guardian/ophan-tracker-js';
|
|
60
|
+
* init('ng');
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export const init = (platform: Platform = 'ng'): void => {
|
|
64
|
+
if (!isBrowser()) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const resolvedPlatform: Platform =
|
|
69
|
+
platform === 'manage-my-account' || platform === 'support' ? platform : 'ng';
|
|
70
|
+
|
|
71
|
+
if (initialized) {
|
|
72
|
+
console.warn(
|
|
73
|
+
`Ophan tracker already initialized with platform: ${currentPlatform}`,
|
|
74
|
+
);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
currentPlatform = resolvedPlatform;
|
|
79
|
+
initialized = true;
|
|
80
|
+
|
|
81
|
+
if (resolvedPlatform === 'ng') {
|
|
82
|
+
core.init('next-gen');
|
|
83
|
+
privatebrowsing.init();
|
|
84
|
+
heatmap.init();
|
|
85
|
+
|
|
86
|
+
if ((window as any).addEventListener) {
|
|
87
|
+
attention.init(visibility);
|
|
88
|
+
}
|
|
89
|
+
} else if (resolvedPlatform === 'manage-my-account') {
|
|
90
|
+
core.init('manage-my-account');
|
|
91
|
+
if ((window as any).addEventListener) {
|
|
92
|
+
attention.init(visibility);
|
|
93
|
+
}
|
|
94
|
+
} else if (resolvedPlatform === 'support') {
|
|
95
|
+
core.init('support');
|
|
96
|
+
if ((window as any).addEventListener) {
|
|
97
|
+
attention.init(visibility);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Send a new page-view event to Ophan.
|
|
104
|
+
*
|
|
105
|
+
* This generates a new view ID and tracks the current page.
|
|
106
|
+
* `init()` already sends the first page-view event, so call this only when
|
|
107
|
+
* intentionally creating another page view, such as after a single-page app
|
|
108
|
+
* route change.
|
|
109
|
+
*
|
|
110
|
+
* @param url - The page URL to track (defaults to current location)
|
|
111
|
+
* @param referrer - The referrer URL (defaults to document.referrer)
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```javascript
|
|
115
|
+
* import { sendInitialEvent } from '@guardian/ophan-tracker-js';
|
|
116
|
+
* sendInitialEvent('https://www.theguardian.com/article', 'https://google.com');
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export const sendInitialEvent = (
|
|
120
|
+
url: string = typeof window !== 'undefined' ? location.href : '',
|
|
121
|
+
referrer: string = typeof window !== 'undefined' &&
|
|
122
|
+
typeof document !== 'undefined'
|
|
123
|
+
? document.referrer
|
|
124
|
+
: '',
|
|
125
|
+
): void => {
|
|
126
|
+
if (!canUseTracker('sendInitialEvent')) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
transmit.bumpViewId();
|
|
132
|
+
core.sendInitialEvent(null, url, referrer);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.log(error);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Record an event against the current page view.
|
|
140
|
+
*
|
|
141
|
+
* Use this for component interactions, purchases, subscriptions, media events,
|
|
142
|
+
* consent events, and other non-page-view payloads. `init()` must have run
|
|
143
|
+
* first so the event is associated with a valid page view and platform.
|
|
144
|
+
*
|
|
145
|
+
* @param event - The event data payload containing metrics and metadata
|
|
146
|
+
* @param callback - Optional callback function executed after the event is sent
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```javascript
|
|
150
|
+
* import { record } from '@guardian/ophan-tracker-js';
|
|
151
|
+
*
|
|
152
|
+
* // Track a component interaction
|
|
153
|
+
* record({
|
|
154
|
+
* componentEvent: {
|
|
155
|
+
* component: {
|
|
156
|
+
* componentType: 'ACQUISITIONS_ENGAGEMENT_BANNER',
|
|
157
|
+
* id: 'end-of-article-banner',
|
|
158
|
+
* campaignCode: '2024-annual-campaign',
|
|
159
|
+
* labels: ['end-of-article']
|
|
160
|
+
* },
|
|
161
|
+
* action: 'CLICK',
|
|
162
|
+
* abTest: {
|
|
163
|
+
* name: 'BannerTest',
|
|
164
|
+
* variant: 'control'
|
|
165
|
+
* }
|
|
166
|
+
* }
|
|
167
|
+
* });
|
|
168
|
+
*
|
|
169
|
+
* // Track a rendered component list
|
|
170
|
+
* record({
|
|
171
|
+
* renderedComponents: ['nav', 'footer']
|
|
172
|
+
* });
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export const record = (event: EventPayload, callback?: () => void): void => {
|
|
176
|
+
if (!isBrowser()) {
|
|
177
|
+
callback?.();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (!initialized) {
|
|
182
|
+
warnIfUninitialized('record');
|
|
183
|
+
callback?.();
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
transmit.sendMore(event, callback);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Track component attention and visibility analytics.
|
|
192
|
+
*
|
|
193
|
+
* Monitors when components enter and leave the viewport.
|
|
194
|
+
*
|
|
195
|
+
* @param name - Unique identifier for the component
|
|
196
|
+
* @param el - The DOM element to track
|
|
197
|
+
* @param visibilityThreshold - Percentage of element that must be visible (0-1)
|
|
198
|
+
* @param isTrackingVideo - Whether this component contains video content
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```javascript
|
|
202
|
+
* import { trackComponentAttention } from '@guardian/ophan-tracker-js';
|
|
203
|
+
*
|
|
204
|
+
* const banner = document.getElementById('promo-banner');
|
|
205
|
+
* trackComponentAttention('promo-banner', banner, 0.5);
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export const trackComponentAttention = (
|
|
209
|
+
name: string,
|
|
210
|
+
el: HTMLElement,
|
|
211
|
+
visibilityThreshold: number,
|
|
212
|
+
isTrackingVideo?: boolean,
|
|
213
|
+
): void => {
|
|
214
|
+
if (!canUseTracker('trackComponentAttention')) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
attention.initComponent(name, el, visibilityThreshold, isTrackingVideo);
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Set a custom event emitter for attention tracking.
|
|
223
|
+
*
|
|
224
|
+
* This is primarily for integrations that need to bridge the tracker's
|
|
225
|
+
* attention events into an existing event system.
|
|
226
|
+
*
|
|
227
|
+
* @param event - Event emitter object with emit/on methods
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```javascript
|
|
231
|
+
* import { setEventEmitter } from '@guardian/ophan-tracker-js';
|
|
232
|
+
*
|
|
233
|
+
* const customEmitter = new EventEmitter();
|
|
234
|
+
* setEventEmitter(customEmitter);
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
export const setEventEmitter = (event: Object): void => {
|
|
238
|
+
attention.setEventEmitter(event);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Manually track a click event on an element with data-link-name or data-component attributes.
|
|
243
|
+
* This captures click path information and component context for analytics.
|
|
244
|
+
* Useful for elements that stop event propagation or need explicit tracking.
|
|
245
|
+
*
|
|
246
|
+
* @param element - The clicked DOM element (should have data-link-name or data-component attributes)
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```javascript
|
|
250
|
+
* import { trackClickComponentEvent } from '@guardian/ophan-tracker-js';
|
|
251
|
+
*
|
|
252
|
+
* // Track a click on an element with tracking attributes
|
|
253
|
+
* const link = document.querySelector('a[data-link-name="subscribe-button"]');
|
|
254
|
+
* trackClickComponentEvent(link);
|
|
255
|
+
*
|
|
256
|
+
* // Or track a button inside a component
|
|
257
|
+
* const button = document.querySelector('[data-component="newsletter-signup"] button');
|
|
258
|
+
* trackClickComponentEvent(button);
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
export const trackClickComponentEvent = (element: Element): void => {
|
|
262
|
+
if (!canUseTracker('trackClickComponentEvent')) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
clickPathCapture.trackClickComponentEvent(element);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Generate a new page view ID for the current browser session.
|
|
271
|
+
*
|
|
272
|
+
* Useful for single-page applications when navigating between pages.
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```javascript
|
|
276
|
+
* import { bumpViewId } from '@guardian/ophan-tracker-js';
|
|
277
|
+
*
|
|
278
|
+
* // Call when navigating to a new page in SPA
|
|
279
|
+
* bumpViewId();
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
export const bumpViewId = (): void => {
|
|
283
|
+
if (!canUseTracker('bumpViewId')) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
transmit.bumpViewId();
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Return the current live Ophan page view ID.
|
|
292
|
+
*
|
|
293
|
+
* Prefer this function over destructuring `viewId` from the default export,
|
|
294
|
+
* because the value changes after `bumpViewId()` or `sendInitialEvent()`.
|
|
295
|
+
*/
|
|
296
|
+
export const getViewId = (): string => transmit.viewId;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Alias for `getViewId()` kept for consumers that use page-view terminology.
|
|
300
|
+
*/
|
|
301
|
+
export const getPageViewId = (): string => transmit.viewId;
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Object-shaped tracker API exposed by the package default export.
|
|
305
|
+
*
|
|
306
|
+
* Named exports are preferred for new code, but the default export keeps the
|
|
307
|
+
* historical object-style API and exposes `viewId`/`pageViewId` as live getters.
|
|
308
|
+
*/
|
|
309
|
+
export interface OphanTracker {
|
|
310
|
+
init: (platform?: Platform) => void;
|
|
311
|
+
sendInitialEvent: (url?: string, referrer?: string) => void;
|
|
312
|
+
record: (event: EventPayload, callback?: () => void) => void;
|
|
313
|
+
trackComponentAttention: (
|
|
314
|
+
name: string,
|
|
315
|
+
el: HTMLElement,
|
|
316
|
+
visibilityThreshold: number,
|
|
317
|
+
isTrackingVideo?: boolean,
|
|
318
|
+
) => void;
|
|
319
|
+
setEventEmitter: (event: Object) => void;
|
|
320
|
+
trackClickComponentEvent: (element: Element) => void;
|
|
321
|
+
bumpViewId: () => void;
|
|
322
|
+
getViewId: () => string;
|
|
323
|
+
getPageViewId: () => string;
|
|
324
|
+
viewId: string;
|
|
325
|
+
pageViewId: string;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const ophanTracker: OphanTracker = {
|
|
329
|
+
init,
|
|
330
|
+
sendInitialEvent,
|
|
331
|
+
record,
|
|
332
|
+
trackComponentAttention,
|
|
333
|
+
setEventEmitter,
|
|
334
|
+
trackClickComponentEvent,
|
|
335
|
+
bumpViewId,
|
|
336
|
+
getViewId,
|
|
337
|
+
getPageViewId,
|
|
338
|
+
get viewId() {
|
|
339
|
+
return getViewId();
|
|
340
|
+
},
|
|
341
|
+
get pageViewId() {
|
|
342
|
+
return getPageViewId();
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
export default ophanTracker;
|
|
347
|
+
|
|
348
|
+
// Type exports
|
|
349
|
+
export * from './types/abtest.js';
|
|
350
|
+
export * from './types/subscription.js';
|
|
351
|
+
export * from './types/interaction.js';
|
|
352
|
+
export * from './types/inpageclick.js';
|
|
353
|
+
export * from './types/printproduct.js';
|
|
354
|
+
export * from './types/product.js';
|
|
355
|
+
export * from './types/platform.js';
|
|
356
|
+
export * from './types/media.js';
|
|
357
|
+
export * from './types/consent.js';
|
|
358
|
+
export * from './types/component-type.js';
|
|
359
|
+
export * from './types/component-event.js';
|
|
360
|
+
export * from './types/event.js';
|
package/src/ng.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import ophan, { init } from './index.js';
|
|
2
|
+
|
|
3
|
+
export * from './types/abtest.js';
|
|
4
|
+
export * from './types/subscription.js';
|
|
5
|
+
export * from './types/interaction.js';
|
|
6
|
+
export * from './types/inpageclick.js';
|
|
7
|
+
export * from './types/printproduct.js';
|
|
8
|
+
export * from './types/product.js';
|
|
9
|
+
export * from './types/platform.js';
|
|
10
|
+
export * from './types/media.js';
|
|
11
|
+
export * from './types/consent.js';
|
|
12
|
+
export * from './types/component-type.js';
|
|
13
|
+
export * from './types/component-event.js';
|
|
14
|
+
export * from './types/event.js';
|
|
15
|
+
|
|
16
|
+
const windowWithGuardian =
|
|
17
|
+
typeof window !== 'undefined'
|
|
18
|
+
? (window as typeof window & {
|
|
19
|
+
guardian?: {
|
|
20
|
+
ophan?: typeof ophan;
|
|
21
|
+
};
|
|
22
|
+
})
|
|
23
|
+
: undefined;
|
|
24
|
+
|
|
25
|
+
const ng = windowWithGuardian?.guardian?.ophan ?? ophan;
|
|
26
|
+
|
|
27
|
+
if (windowWithGuardian && !windowWithGuardian.guardian?.ophan) {
|
|
28
|
+
init('ng');
|
|
29
|
+
windowWithGuardian.guardian = windowWithGuardian.guardian ?? {};
|
|
30
|
+
windowWithGuardian.guardian.ophan = ng;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default ng;
|