@newrelic/video-core 4.1.5 → 4.1.6
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/CHANGELOG.md +7 -0
- package/README.md +487 -89
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.LICENSE.txt +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.LICENSE.txt +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/umd/nrvideo.min.js +1 -1
- package/dist/umd/nrvideo.min.js.LICENSE.txt +1 -1
- package/package.json +9 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
|
3
3
|
|
|
4
|
+
## [4.1.6] - 2026/04/16
|
|
5
|
+
|
|
6
|
+
### Chore
|
|
7
|
+
|
|
8
|
+
- **README.md overhaul**
|
|
9
|
+
Rewrote `README.md` with comprehensive documentation including table of contents, installation instructions, quick start guide, configuration reference, exposed API details, custom tracker guide, getter methods reference, QoE section, obfuscation rules, build & development instructions, and distribution formats.
|
|
10
|
+
|
|
4
11
|
## [4.1.5] - 2026/04/08
|
|
5
12
|
|
|
6
13
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,159 +1,557 @@
|
|
|
1
|
-
[](https://github.com/newrelic/open-source-office/blob/master/examples/categories/index.md#community-project)
|
|
2
|
-
|
|
3
1
|
# New Relic Video Core - JavaScript
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@newrelic/video-core)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
The **New Relic Video Core** library (`@newrelic/video-core`) is the foundational framework for all browser-based video trackers in the New Relic ecosystem. It provides the core classes, state management, event harvesting, and data transmission pipeline that player-specific trackers extend.
|
|
7
|
+
|
|
8
|
+
Events are categorized into four distinct types:
|
|
9
|
+
|
|
10
|
+
| Event Type | Description |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `VideoAction` | Content playback events (play, pause, seek, buffer, etc.) |
|
|
13
|
+
| `VideoAdAction` | Ad-related events (ad start, end, quartile, break, etc.) |
|
|
14
|
+
| `VideoErrorAction` | Error events (content errors, ad errors, crashes) |
|
|
15
|
+
| `VideoCustomAction` | Custom events defined by the integrator |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Table of Contents
|
|
20
|
+
|
|
21
|
+
- [Installation](#installation)
|
|
22
|
+
- [Quick Start](#quick-start)
|
|
23
|
+
- [Configuration](#configuration)
|
|
24
|
+
- [Info Object (Required)](#info-object-required)
|
|
25
|
+
- [Config Object (Optional)](#config-object-optional)
|
|
26
|
+
- [Exposed API](#exposed-api)
|
|
27
|
+
- [Core](#core)
|
|
28
|
+
- [VideoTracker](#videotracker)
|
|
29
|
+
- [Tracker](#tracker)
|
|
30
|
+
- [Emitter](#emitter)
|
|
31
|
+
- [VideoTrackerState](#videotrackerstate)
|
|
32
|
+
- [Chrono](#chrono)
|
|
33
|
+
- [Log](#log)
|
|
34
|
+
- [Constants](#constants)
|
|
35
|
+
- [Building a Custom Tracker](#building-a-custom-tracker)
|
|
36
|
+
- [Tracker Methods Reference](#tracker-methods-reference)
|
|
37
|
+
- [Getter Methods (Override These)](#getter-methods-override-these)
|
|
38
|
+
- [Quality of Experience (QoE)](#quality-of-experience-qoe)
|
|
39
|
+
- [Obfuscation Rules](#obfuscation-rules)
|
|
40
|
+
- [Build & Development](#build--development)
|
|
41
|
+
- [Distribution Formats](#distribution-formats)
|
|
42
|
+
- [Testing](#testing)
|
|
43
|
+
- [Data Model](#data-model)
|
|
44
|
+
- [License](#license)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @newrelic/video-core
|
|
52
|
+
```
|
|
7
53
|
|
|
8
|
-
|
|
54
|
+
Or include directly via UMD:
|
|
9
55
|
|
|
10
|
-
|
|
56
|
+
```html
|
|
57
|
+
<script src="dist/umd/nrvideo.min.js"></script>
|
|
58
|
+
```
|
|
11
59
|
|
|
12
|
-
|
|
60
|
+
## Quick Start
|
|
13
61
|
|
|
14
62
|
```javascript
|
|
63
|
+
import nrvideo from '@newrelic/video-core';
|
|
64
|
+
|
|
65
|
+
// 1. Define a custom tracker by extending VideoTracker
|
|
66
|
+
class MyPlayerTracker extends nrvideo.VideoTracker {
|
|
67
|
+
getTrackerName() { return 'my-player'; }
|
|
68
|
+
getSrc() { return this.player.currentSrc; }
|
|
69
|
+
getDuration() { return this.player.duration; }
|
|
70
|
+
getPlayhead() { return this.player.currentTime; }
|
|
71
|
+
getRenditionWidth() { return this.player.videoWidth; }
|
|
72
|
+
getRenditionHeight() { return this.player.videoHeight; }
|
|
73
|
+
|
|
74
|
+
registerListeners() {
|
|
75
|
+
this.player.addEventListener('play', () => this.sendRequest());
|
|
76
|
+
this.player.addEventListener('playing', () => this.sendStart());
|
|
77
|
+
this.player.addEventListener('pause', () => this.sendPause());
|
|
78
|
+
this.player.addEventListener('ended', () => this.sendEnd());
|
|
79
|
+
this.player.addEventListener('waiting', () => this.sendBufferStart());
|
|
80
|
+
this.player.addEventListener('seeking', () => this.sendSeekStart());
|
|
81
|
+
this.player.addEventListener('seeked', () => this.sendSeekEnd());
|
|
82
|
+
this.player.addEventListener('error', () => this.sendError({
|
|
83
|
+
errorName: this.player.error?.message,
|
|
84
|
+
errorCode: this.player.error?.code
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
unregisterListeners() {
|
|
89
|
+
// Remove all listeners added in registerListeners
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 2. Configure and register the tracker
|
|
15
94
|
const options = {
|
|
16
95
|
info: {
|
|
17
|
-
licenseKey:
|
|
18
|
-
beacon:
|
|
19
|
-
|
|
96
|
+
licenseKey: 'YOUR_LICENSE_KEY',
|
|
97
|
+
beacon: 'bam.nr-data.net',
|
|
98
|
+
applicationID: 'YOUR_APPLICATION_ID',
|
|
20
99
|
},
|
|
21
100
|
config: {
|
|
22
|
-
qoeAggregate:
|
|
23
|
-
qoeIntervalFactor: 2, // Optional: Include QoE aggregate events once every N harvest cycles; must be a whole number (e.g. 2, not 2.1) (default: 1)
|
|
101
|
+
qoeAggregate: true,
|
|
24
102
|
},
|
|
25
103
|
};
|
|
26
104
|
|
|
27
|
-
|
|
28
|
-
const tracker = new
|
|
105
|
+
const player = document.getElementById('myPlayer');
|
|
106
|
+
const tracker = new MyPlayerTracker(player, options);
|
|
107
|
+
|
|
108
|
+
// 3. Add tracker to Core to begin reporting
|
|
109
|
+
nrvideo.Core.addTracker(tracker, options);
|
|
29
110
|
```
|
|
30
111
|
|
|
31
|
-
|
|
112
|
+
## Configuration
|
|
32
113
|
|
|
33
|
-
|
|
114
|
+
The `options` object passed to `Core.addTracker()` consists of two parts:
|
|
34
115
|
|
|
35
|
-
|
|
116
|
+
### Getting Your Configuration
|
|
36
117
|
|
|
37
|
-
|
|
118
|
+
Before initializing the tracker, obtain your New Relic configuration:
|
|
38
119
|
|
|
120
|
+
1. Log in to [one.newrelic.com](https://one.newrelic.com)
|
|
121
|
+
2. Navigate to the video agent onboarding flow
|
|
122
|
+
3. Copy your credentials: `licenseKey`, `beacon`, and `applicationId`
|
|
39
123
|
|
|
40
|
-
|
|
124
|
+
### Info Object (Required)
|
|
125
|
+
|
|
126
|
+
Obtained through the New Relic onboarding process. Two configuration modes are supported:
|
|
127
|
+
|
|
128
|
+
**Mode 1 — With Application ID and Beacon:**
|
|
41
129
|
|
|
42
|
-
|
|
130
|
+
```javascript
|
|
131
|
+
info: {
|
|
132
|
+
licenseKey: 'YOUR_LICENSE_KEY', // Required
|
|
133
|
+
applicationID: 'YOUR_APPLICATION_ID', // Required
|
|
134
|
+
beacon: 'bam.nr-data.net', // Required when applicationID is provided
|
|
135
|
+
}
|
|
136
|
+
```
|
|
43
137
|
|
|
44
|
-
|
|
138
|
+
**Mode 2 — With App Name and Region:**
|
|
45
139
|
|
|
46
|
-
|
|
140
|
+
```javascript
|
|
141
|
+
info: {
|
|
142
|
+
licenseKey: 'YOUR_LICENSE_KEY', // Required
|
|
143
|
+
appName: 'My Video App', // Required when no applicationID
|
|
144
|
+
region: 'US', // Required when no applicationID
|
|
145
|
+
}
|
|
146
|
+
```
|
|
47
147
|
|
|
48
|
-
|
|
148
|
+
**Valid Beacon Endpoints:**
|
|
49
149
|
|
|
50
|
-
|
|
|
51
|
-
|
|
52
|
-
|
|
|
53
|
-
|
|
|
150
|
+
| Region | Beacon |
|
|
151
|
+
|---|---|
|
|
152
|
+
| US | `bam.nr-data.net`, `bam-cell.nr-data.net` |
|
|
153
|
+
| EU | `bam.eu01.nr-data.net` |
|
|
154
|
+
| Staging | `staging-bam-cell.nr-data.net` |
|
|
155
|
+
| GOV | `gov-bam.nr-data.net` |
|
|
156
|
+
|
|
157
|
+
### Config Object (Optional)
|
|
158
|
+
|
|
159
|
+
| Option | Type | Default | Description |
|
|
160
|
+
|---|---|---|---|
|
|
161
|
+
| `qoeAggregate` | `boolean` | `false` | Enable Quality of Experience event aggregation. |
|
|
162
|
+
| `qoeIntervalFactor` | `number` | `1` | Include QoE aggregate events once every N harvest cycles. Must be a positive integer. QoE events are always sent on the first and final harvest cycles. |
|
|
163
|
+
| `obfuscate` | `array` | `[]` | Regex-based rules to mask sensitive data before transmission. See [Obfuscation Rules](#obfuscation-rules). |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Exposed API
|
|
168
|
+
|
|
169
|
+
All exports are available under the `nrvideo` namespace (UMD) or as named imports:
|
|
54
170
|
|
|
55
171
|
```javascript
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
],
|
|
66
|
-
},
|
|
67
|
-
};
|
|
172
|
+
import nrvideo from '@newrelic/video-core';
|
|
173
|
+
|
|
174
|
+
// Available: nrvideo.Core, nrvideo.VideoTracker, nrvideo.Tracker,
|
|
175
|
+
// nrvideo.Emitter, nrvideo.VideoTrackerState, nrvideo.Chrono,
|
|
176
|
+
// nrvideo.Log, nrvideo.Constants, nrvideo.version,
|
|
177
|
+
// nrvideo.NrVideoEventAggregator, nrvideo.RetryQueueHandler,
|
|
178
|
+
// nrvideo.OptimizedHttpClient, nrvideo.HarvestScheduler,
|
|
179
|
+
// nrvideo.recordEvent
|
|
180
|
+
```
|
|
68
181
|
|
|
69
|
-
|
|
182
|
+
### Core
|
|
183
|
+
|
|
184
|
+
Static class managing tracker registration and event dispatch.
|
|
185
|
+
|
|
186
|
+
| Method | Description |
|
|
187
|
+
|---|---|
|
|
188
|
+
| `Core.addTracker(tracker, options)` | Registers a tracker and initializes video analytics config. Starts event reporting. |
|
|
189
|
+
| `Core.removeTracker(tracker)` | Disposes and removes a tracker. Stops its event reporting. |
|
|
190
|
+
| `Core.getTrackers()` | Returns the array of currently registered trackers. |
|
|
191
|
+
| `Core.send(eventType, actionName, data)` | Sends an event to the collector. Called internally by event handlers. |
|
|
192
|
+
| `Core.sendError(att)` | Sends a `VideoErrorAction` with `actionName: "ERROR"`. For external/app-level errors. |
|
|
193
|
+
| `Core.forceHarvest()` | Forces an immediate harvest of all pending events. Returns a `Promise`. |
|
|
194
|
+
|
|
195
|
+
### VideoTracker
|
|
196
|
+
|
|
197
|
+
Base class for video player trackers. Extends `Tracker`.
|
|
198
|
+
|
|
199
|
+
| Method | Description |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `constructor(player, options)` | Initializes the tracker. Lifecycle: constructor → `setOptions` → `setPlayer` → `registerListeners`. |
|
|
202
|
+
| `setPlayer(player, tag)` | Sets the player and optional DOM element. Calls `registerListeners()`. |
|
|
203
|
+
| `setOptions(options)` | Configures tracker options (heartbeat, customData, adsTracker, isAd, parentTracker). |
|
|
204
|
+
| `setAdsTracker(tracker)` | Sets a child ad tracker. Ad events are funneled through the parent. |
|
|
205
|
+
| `setUserId(userId)` | Sets a user identifier included as `enduser.id` in all events. |
|
|
206
|
+
| `setHarvestInterval(interval)` | Updates the harvest cycle interval in milliseconds. |
|
|
207
|
+
| `dispose()` | Stops heartbeat, disposes ad tracker, unregisters listeners, clears references. |
|
|
208
|
+
| `registerListeners()` | **Override this.** Attach player event listeners and map to `send*()` methods. |
|
|
209
|
+
| `unregisterListeners()` | **Override this.** Detach player event listeners. |
|
|
210
|
+
| `getAttributes(att)` | **Do NOT override.** Collects all video/ad attributes. Use getter methods instead. |
|
|
211
|
+
|
|
212
|
+
**State-changing methods** (call these from `registerListeners`):
|
|
213
|
+
|
|
214
|
+
| Method | Event Emitted (Content / Ad) | Description |
|
|
215
|
+
|---|---|---|
|
|
216
|
+
| `sendPlayerReady(att)` | `PLAYER_READY` | Player is initialized and ready. |
|
|
217
|
+
| `sendRequest(att)` | `CONTENT_REQUEST` / `AD_REQUEST` | Playback has been requested. |
|
|
218
|
+
| `sendStart(att)` | `CONTENT_START` / `AD_START` | First frame rendered. Starts heartbeat. |
|
|
219
|
+
| `sendEnd(att)` | `CONTENT_END` / `AD_END` | Playback ended. Stops heartbeat. |
|
|
220
|
+
| `sendPause(att)` | `CONTENT_PAUSE` / `AD_PAUSE` | Playback paused. |
|
|
221
|
+
| `sendResume(att)` | `CONTENT_RESUME` / `AD_RESUME` | Playback resumed. |
|
|
222
|
+
| `sendBufferStart(att)` | `CONTENT_BUFFER_START` / `AD_BUFFER_START` | Buffering started. |
|
|
223
|
+
| `sendBufferEnd(att)` | `CONTENT_BUFFER_END` / `AD_BUFFER_END` | Buffering ended. |
|
|
224
|
+
| `sendSeekStart(att)` | `CONTENT_SEEK_START` / `AD_SEEK_START` | Seek started. |
|
|
225
|
+
| `sendSeekEnd(att)` | `CONTENT_SEEK_END` / `AD_SEEK_END` | Seek ended. |
|
|
226
|
+
| `sendError(att)` | `CONTENT_ERROR` / `AD_ERROR` | Error occurred during playback. |
|
|
227
|
+
| `sendRenditionChanged(att)` | `CONTENT_RENDITION_CHANGE` / `AD_RENDITION_CHANGE` | Stream quality changed. |
|
|
228
|
+
| `sendDownload(att)` | `DOWNLOAD` | Download event. Requires `att.state`. |
|
|
229
|
+
| `sendHeartbeat(att)` | `CONTENT_HEARTBEAT` / `AD_HEARTBEAT` | Sent automatically every 30s (2s for ads). |
|
|
230
|
+
| `sendAdBreakStart(att)` | `AD_BREAK_START` | Ad break started (ads only). |
|
|
231
|
+
| `sendAdBreakEnd(att)` | `AD_BREAK_END` | Ad break ended (ads only). |
|
|
232
|
+
| `sendAdQuartile(att)` | `AD_QUARTILE` | Ad quartile reached. Requires `att.quartile`. |
|
|
233
|
+
| `sendAdClick(att)` | `AD_CLICK` | Ad clicked. Requires `att.url`. |
|
|
234
|
+
| `sendCustom(actionName, timeSinceAttName, att)` | Custom `VideoCustomAction` | Sends a custom event with a `timeSince` attribute. |
|
|
235
|
+
|
|
236
|
+
### Tracker
|
|
237
|
+
|
|
238
|
+
Base class providing heartbeat, custom data, and attribute management. Extends `Emitter`.
|
|
239
|
+
|
|
240
|
+
| Method | Description |
|
|
241
|
+
|---|---|
|
|
242
|
+
| `setOptions(options)` | Set heartbeat interval, customData, and parentTracker. |
|
|
243
|
+
| `getHeartbeat()` | Returns heartbeat interval in ms. Default: 30000 (content), 2000 (ads). |
|
|
244
|
+
| `startHeartbeat()` | Starts the heartbeat interval. Called automatically on `sendStart`. |
|
|
245
|
+
| `stopHeartbeat()` | Stops the heartbeat interval. Called automatically on `sendEnd`. |
|
|
246
|
+
| `getAttributes(att)` | Returns base attributes (trackerName, coreVersion, isBackgroundEvent, etc.). |
|
|
247
|
+
| `sendVideoAction(event, att)` | Emits a `VideoAction` event. |
|
|
248
|
+
| `sendVideoAdAction(event, att)` | Emits a `VideoAdAction` event. |
|
|
249
|
+
| `sendVideoErrorAction(event, att)` | Emits a `VideoErrorAction` event. |
|
|
250
|
+
| `sendVideoCustomAction(event, att)` | Emits a `VideoCustomAction` event. |
|
|
251
|
+
|
|
252
|
+
### Emitter
|
|
253
|
+
|
|
254
|
+
Event system base class.
|
|
255
|
+
|
|
256
|
+
| Method | Description |
|
|
257
|
+
|---|---|
|
|
258
|
+
| `on(event, callback)` | Subscribe to an event. Use `'*'` to listen to all events. |
|
|
259
|
+
| `off(event, callback)` | Unsubscribe from an event. |
|
|
260
|
+
| `emit(eventType, event, data)` | Emit an event to all subscribers. |
|
|
261
|
+
|
|
262
|
+
### VideoTrackerState
|
|
263
|
+
|
|
264
|
+
Internal state machine managing view lifecycle, QoE KPIs, and timing.
|
|
265
|
+
|
|
266
|
+
| Property | Description |
|
|
267
|
+
|---|---|
|
|
268
|
+
| `numberOfErrors` | Error count for current view. |
|
|
269
|
+
| `numberOfAds` | Total ads shown. |
|
|
270
|
+
| `numberOfVideos` | Total videos played. |
|
|
271
|
+
| `totalPlaytime` | Content viewing time in ms (excludes pausing, buffering, ads). |
|
|
272
|
+
| `totalAdPlaytime` | Ad viewing time in ms. |
|
|
273
|
+
| `startupTime` | Time from `CONTENT_REQUEST` to `CONTENT_START` in ms. |
|
|
274
|
+
| `peakBitrate` | Maximum bitrate observed during playback. |
|
|
275
|
+
|
|
276
|
+
### Chrono
|
|
277
|
+
|
|
278
|
+
Utility class for measuring time lapses.
|
|
279
|
+
|
|
280
|
+
| Method | Description |
|
|
281
|
+
|---|---|
|
|
282
|
+
| `start()` | Start the timer. |
|
|
283
|
+
| `stop()` | Stop the timer and return delta. |
|
|
284
|
+
| `getDeltaTime()` | Get elapsed time since `start()` in ms. |
|
|
285
|
+
| `getDuration()` | Get accumulated duration across multiple start/stop cycles. |
|
|
286
|
+
| `reset()` | Reset all values. |
|
|
287
|
+
| `clone()` | Create a copy of the chrono. |
|
|
288
|
+
|
|
289
|
+
### Log
|
|
290
|
+
|
|
291
|
+
Static logging utility with configurable levels.
|
|
292
|
+
|
|
293
|
+
| Method | Description |
|
|
294
|
+
|---|---|
|
|
295
|
+
| `Log.error(...msg)` | Log an error. |
|
|
296
|
+
| `Log.warn(...msg)` | Log a warning. |
|
|
297
|
+
| `Log.notice(...msg)` | Log a notice. |
|
|
298
|
+
| `Log.debug(...msg)` | Log a debug message. |
|
|
299
|
+
| `Log.debugCommonVideoEvents(player, extraEvents, report)` | Attach debug listeners for common HTML5 video events. |
|
|
300
|
+
|
|
301
|
+
**Log Levels** (set via `Log.level`):
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
nrvideo.Log.level = nrvideo.Log.Levels.DEBUG; // ALL, DEBUG, NOTICE, WARNING, ERROR, SILENT
|
|
70
305
|
```
|
|
71
306
|
|
|
72
|
-
###
|
|
307
|
+
### Constants
|
|
308
|
+
|
|
309
|
+
| Constant | Value | Description |
|
|
310
|
+
|---|---|---|
|
|
311
|
+
| `Constants.AdPositions` | `{ PRE, MID, POST }` | Ad position enum. |
|
|
312
|
+
| `Constants.COLLECTOR` | Object | Beacon endpoint URLs by region. |
|
|
313
|
+
| `Constants.VALID_EVENT_TYPES` | Array | `['VideoAction', 'VideoAdAction', 'VideoErrorAction', 'VideoCustomAction']` |
|
|
314
|
+
| `Constants.MAX_PAYLOAD_SIZE` | `1048576` | Maximum payload size (1 MB). |
|
|
315
|
+
| `Constants.MAX_BEACON_SIZE` | `61440` | Maximum beacon size (60 KB). |
|
|
316
|
+
| `Constants.MAX_EVENTS_PER_BATCH` | `1000` | Maximum events per batch. |
|
|
317
|
+
| `Constants.INTERVAL` | `10000` | Default harvest interval (10s). |
|
|
73
318
|
|
|
74
|
-
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Building a Custom Tracker
|
|
322
|
+
|
|
323
|
+
Extend `VideoTracker` and override getter methods and listener registration:
|
|
75
324
|
|
|
76
325
|
```javascript
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
326
|
+
class MyPlayerTracker extends nrvideo.VideoTracker {
|
|
327
|
+
// Required: identify your tracker
|
|
328
|
+
getTrackerName() { return 'my-custom-player'; }
|
|
329
|
+
getTrackerVersion() { return '1.0.0'; }
|
|
330
|
+
|
|
331
|
+
// Override getters to return player metadata
|
|
332
|
+
getVideoId() { return this.player.getContentId(); }
|
|
333
|
+
getTitle() { return this.player.getTitle(); }
|
|
334
|
+
getSrc() { return this.player.getSrc(); }
|
|
335
|
+
getDuration() { return this.player.getDuration() * 1000; } // in ms
|
|
336
|
+
getPlayhead() { return this.player.getCurrentTime() * 1000; }
|
|
337
|
+
getBitrate() { return this.player.getCurrentBitrate(); }
|
|
338
|
+
getRenditionName() { return this.player.getQualityLabel(); }
|
|
339
|
+
getRenditionHeight() { return this.player.getVideoHeight(); }
|
|
340
|
+
getRenditionWidth() { return this.player.getVideoWidth(); }
|
|
341
|
+
isLive() { return this.player.isLive(); }
|
|
342
|
+
isMuted() { return this.player.isMuted(); }
|
|
343
|
+
isFullscreen() { return this.player.isFullscreen(); }
|
|
344
|
+
getPlayrate() { return this.player.getPlaybackRate(); }
|
|
345
|
+
getPlayerName() { return 'My Player'; }
|
|
346
|
+
getPlayerVersion() { return this.player.version; }
|
|
347
|
+
|
|
348
|
+
// Map player events to tracker methods
|
|
349
|
+
registerListeners() {
|
|
350
|
+
this.player.on('play', () => this.sendRequest());
|
|
351
|
+
this.player.on('playing', () => this.sendStart());
|
|
352
|
+
this.player.on('pause', () => this.sendPause());
|
|
353
|
+
this.player.on('ended', () => this.sendEnd());
|
|
354
|
+
this.player.on('waiting', () => this.sendBufferStart());
|
|
355
|
+
this.player.on('canplay', () => this.sendBufferEnd());
|
|
356
|
+
this.player.on('seeking', () => this.sendSeekStart());
|
|
357
|
+
this.player.on('seeked', () => this.sendSeekEnd());
|
|
358
|
+
this.player.on('error', (e) => this.sendError({
|
|
359
|
+
errorName: e.message,
|
|
360
|
+
errorCode: e.code
|
|
361
|
+
}));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
unregisterListeners() {
|
|
365
|
+
this.player.off('play');
|
|
366
|
+
this.player.off('playing');
|
|
367
|
+
// ... remove all listeners
|
|
368
|
+
}
|
|
369
|
+
}
|
|
82
370
|
```
|
|
83
371
|
|
|
84
|
-
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## Getter Methods (Override These)
|
|
375
|
+
|
|
376
|
+
These methods return `null` by default. Override them in your tracker to provide player-specific data:
|
|
377
|
+
|
|
378
|
+
| Getter | Attribute Set | Description |
|
|
379
|
+
|---|---|---|
|
|
380
|
+
| `getVideoId()` | `contentId` / `adId` | Content or ad identifier. |
|
|
381
|
+
| `getTitle()` | `contentTitle` / `adTitle` | Content or ad title. |
|
|
382
|
+
| `getSrc()` | `contentSrc` / `adSrc` | Media source URL. |
|
|
383
|
+
| `getDuration()` | `contentDuration` / `adDuration` | Duration in ms. |
|
|
384
|
+
| `getPlayhead()` | `contentPlayhead` / `adPlayhead` | Current playback position in ms. |
|
|
385
|
+
| `getBitrate()` | `contentBitrate` / `adBitrate` | Current bitrate in bits/s. |
|
|
386
|
+
| `getManifestBitrate()` | `contentManifestBitrate` | Manifest/playlist declared bitrate in bps. |
|
|
387
|
+
| `getSegmentDownloadBitrate()` | `contentSegmentDownloadBitrate` | Measured bitrate from segment download in bps. |
|
|
388
|
+
| `getNetworkDownloadBitrate()` | `contentNetworkDownloadBitrate` | Network download throughput in bps. |
|
|
389
|
+
| `getRenditionName()` | `contentRenditionName` / `adRenditionName` | Quality label (e.g., "1080p"). |
|
|
390
|
+
| `getRenditionHeight()` | `contentRenditionHeight` / `adRenditionHeight` | Rendition height in px. |
|
|
391
|
+
| `getRenditionWidth()` | `contentRenditionWidth` / `adRenditionWidth` | Rendition width in px. |
|
|
392
|
+
| `isLive()` | `contentIsLive` | `true` if live stream. |
|
|
393
|
+
| `isMuted()` | `contentIsMuted` / `adIsMuted` | `true` if muted. |
|
|
394
|
+
| `isFullscreen()` | `contentIsFullscreen` | `true` if fullscreen. |
|
|
395
|
+
| `getPlayrate()` | `contentPlayrate` | Playback speed (1.0 = normal). |
|
|
396
|
+
| `getLanguage()` | `contentLanguage` / `adLanguage` | Language in locale notation (e.g., `en_US`). |
|
|
397
|
+
| `getCdn()` | `contentCdn` / `adCdn` | CDN serving the content. |
|
|
398
|
+
| `getFps()` | `contentFps` / `adFps` | Current frames per second. |
|
|
399
|
+
| `isAutoplayed()` | `contentIsAutoplayed` | `true` if autoplayed. |
|
|
400
|
+
| `getPreload()` | `contentPreload` | Preload attribute value. |
|
|
401
|
+
| `getPlayerName()` | `playerName` | Player name. |
|
|
402
|
+
| `getPlayerVersion()` | `playerVersion` | Player version. |
|
|
403
|
+
| `getAdQuartile()` | `adQuartile` | Ad quartile (0–4). |
|
|
404
|
+
| `getAdPosition()` | `adPosition` | Ad position (`pre`, `mid`, `post`). |
|
|
405
|
+
| `getAdPartner()` | `adPartner` | Ad partner (e.g., `ima`, `freewheel`). |
|
|
406
|
+
| `getAdCreativeId()` | `adCreativeId` | Ad creative identifier. |
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## Quality of Experience (QoE)
|
|
411
|
+
|
|
412
|
+
When `qoeAggregate` is enabled, the library tracks and reports QoE KPI metrics as `QOE_AGGREGATE` events:
|
|
413
|
+
|
|
414
|
+
| KPI | Description |
|
|
415
|
+
|---|---|
|
|
416
|
+
| `startupTime` | Time from `CONTENT_REQUEST` to `CONTENT_START` in ms. |
|
|
417
|
+
| `peakBitrate` | Maximum bitrate observed during playback. |
|
|
418
|
+
| `averageBitrate` | Playtime-weighted average bitrate in bps. |
|
|
419
|
+
| `totalPlaytime` | Total content viewing time in ms (excludes pausing, buffering, ads). |
|
|
420
|
+
| `totalRebufferingTime` | Total ms spent rebuffering (excludes initial buffering). |
|
|
421
|
+
| `rebufferingRatio` | `(totalRebufferingTime / totalPlaytime) × 100`. |
|
|
422
|
+
| `hadStartupError` | `true` if error occurred before `CONTENT_START`. |
|
|
423
|
+
| `hadPlaybackError` | `true` if error occurred at any time during playback. |
|
|
424
|
+
|
|
425
|
+
QoE KPIs are refreshed before each harvest drain and always included in the final harvest at `CONTENT_END`.
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## Obfuscation Rules
|
|
430
|
+
|
|
431
|
+
Mask sensitive data in event payloads before transmission using regex-based rules:
|
|
85
432
|
|
|
86
433
|
```javascript
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
]
|
|
90
|
-
|
|
91
|
-
|
|
434
|
+
config: {
|
|
435
|
+
obfuscate: [
|
|
436
|
+
{ regex: /\/user\/[^\/?"]+/, replacement: '/user/[REDACTED]' },
|
|
437
|
+
{ regex: /token=[^&"]+/, replacement: 'token=[MASKED]' },
|
|
438
|
+
]
|
|
439
|
+
}
|
|
92
440
|
```
|
|
93
441
|
|
|
94
|
-
|
|
442
|
+
| Field | Type | Description |
|
|
443
|
+
|---|---|---|
|
|
444
|
+
| `regex` | `string` \| `RegExp` | Pattern to match in the serialized JSON payload. |
|
|
445
|
+
| `replacement` | `string` | Replacement string for each match. |
|
|
95
446
|
|
|
96
|
-
Rules are applied
|
|
447
|
+
Rules are applied sequentially — the output of one rule feeds into the next. Invalid regex patterns are skipped with a warning logged via `Log.warn`.
|
|
97
448
|
|
|
98
|
-
|
|
449
|
+
---
|
|
99
450
|
|
|
100
|
-
|
|
101
|
-
- **Empty replacement**: Setting `replacement: ""` deletes the matched content entirely.
|
|
102
|
-
- **RegExp flags**: The global flag (`g`) is always applied so all occurrences in the payload are replaced. Other flags (`i`, `m`, etc.) on `RegExp` objects are preserved.
|
|
451
|
+
## Build & Development
|
|
103
452
|
|
|
453
|
+
```bash
|
|
454
|
+
# Install dependencies
|
|
455
|
+
npm install
|
|
104
456
|
|
|
105
|
-
|
|
457
|
+
# Production build
|
|
458
|
+
npm run build
|
|
106
459
|
|
|
107
|
-
|
|
460
|
+
# Development build (unminified)
|
|
461
|
+
npm run build:dev
|
|
108
462
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- `tracker.setOptions({ customData: { key: value } })` — Set custom options or data.
|
|
112
|
-
- `tracker.sendCustom("CustomEvent", { data: "custom-test" })` — Send a custom event.
|
|
463
|
+
# Watch mode (production)
|
|
464
|
+
npm run watch
|
|
113
465
|
|
|
114
|
-
|
|
466
|
+
# Watch mode (development)
|
|
467
|
+
npm run watch:dev
|
|
115
468
|
|
|
116
|
-
|
|
469
|
+
# Clean build artifacts
|
|
470
|
+
npm run clean
|
|
471
|
+
```
|
|
117
472
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
473
|
+
## Distribution Formats
|
|
474
|
+
|
|
475
|
+
The build produces three output formats:
|
|
476
|
+
|
|
477
|
+
| Format | Path | Usage |
|
|
478
|
+
|---|---|---|
|
|
479
|
+
| **UMD** | `dist/umd/nrvideo.min.js` | `<script>` tag → `window.nrvideo` |
|
|
480
|
+
| **CommonJS** | `dist/cjs/index.js` | `require('@newrelic/video-core')` |
|
|
481
|
+
| **ES Module** | `dist/esm/index.js` | `import nrvideo from '@newrelic/video-core'` |
|
|
482
|
+
|
|
483
|
+
## Testing
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
# Run tests with coverage
|
|
487
|
+
npm test
|
|
123
488
|
```
|
|
124
489
|
|
|
490
|
+
Tests are written using [Jest](https://jestjs.io/) and located in the `test/` directory.
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
125
494
|
## Data Model
|
|
126
495
|
|
|
127
|
-
|
|
496
|
+
For a comprehensive reference of all event types, attributes, and action names, see [DATAMODEL.md](DATAMODEL.md).
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## License
|
|
501
|
+
|
|
502
|
+
This project is licensed under the [Apache 2.0 License](LICENSE).
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## Support
|
|
507
|
+
|
|
508
|
+
Should you need assistance with New Relic products, you are in good hands with several support channels.
|
|
509
|
+
|
|
510
|
+
If the issue has been confirmed as a bug or is a feature request, please file a [GitHub issue](../../issues).
|
|
511
|
+
|
|
512
|
+
**Support Channels:**
|
|
513
|
+
|
|
514
|
+
- [New Relic Documentation](https://docs.newrelic.com): Comprehensive guidance for using our platform
|
|
515
|
+
- [New Relic Community](https://discuss.newrelic.com): The best place to engage in troubleshooting questions
|
|
516
|
+
- [New Relic University](https://learn.newrelic.com): A range of online training for New Relic users of every level
|
|
517
|
+
- [New Relic Technical Support](https://support.newrelic.com): 24/7/365 ticketed support. Read more about our Technical Support Offerings
|
|
518
|
+
|
|
519
|
+
**Additional Resources:**
|
|
520
|
+
|
|
521
|
+
- [DATAMODEL.md](DATAMODEL.md) — Complete event and attribute reference
|
|
522
|
+
- [DEVELOPING.md](DEVELOPING.md) — Building and testing instructions
|
|
523
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) — Contribution guidelines
|
|
524
|
+
|
|
525
|
+
---
|
|
128
526
|
|
|
129
|
-
##
|
|
527
|
+
## Contributing
|
|
130
528
|
|
|
131
|
-
|
|
529
|
+
We encourage your contributions to improve the Video Core JS library! Keep in mind that when you submit your pull request, you'll need to sign the CLA via the click-through using CLA-Assistant. You only have to sign the CLA one time per project.
|
|
132
530
|
|
|
133
|
-
|
|
531
|
+
If you have any questions, or to execute our corporate CLA (which is required if your contribution is on behalf of a company), drop us an email at opensource@newrelic.com.
|
|
134
532
|
|
|
135
|
-
|
|
533
|
+
For more details on how best to contribute, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
136
534
|
|
|
137
|
-
|
|
535
|
+
---
|
|
138
536
|
|
|
139
|
-
##
|
|
537
|
+
## A Note About Vulnerabilities
|
|
140
538
|
|
|
141
|
-
|
|
539
|
+
As noted in our [security policy](../../security/policy), New Relic is committed to the privacy and security of our customers and their data. We believe that providing coordinated disclosure by security researchers and engaging with the security community are important means to achieve our security goals.
|
|
142
540
|
|
|
143
|
-
https://
|
|
541
|
+
If you believe you have found a security vulnerability in this project or any of New Relic's products or websites, we welcome and greatly appreciate you reporting it to New Relic through our [bug bounty program](https://docs.newrelic.com/docs/security/security-privacy/information-security/report-security-vulnerabilities/).
|
|
144
542
|
|
|
145
|
-
|
|
543
|
+
---
|
|
146
544
|
|
|
147
|
-
|
|
545
|
+
## Acknowledgments
|
|
148
546
|
|
|
149
|
-
|
|
547
|
+
If you would like to contribute to this project, review [these guidelines](CONTRIBUTING.md).
|
|
150
548
|
|
|
151
|
-
|
|
549
|
+
To all contributors, we thank you! Without your contribution, this project would not be what it is today.
|
|
152
550
|
|
|
153
|
-
|
|
551
|
+
---
|
|
154
552
|
|
|
155
|
-
|
|
553
|
+
## License
|
|
156
554
|
|
|
157
|
-
|
|
555
|
+
The Video Core JS library is licensed under the [Apache 2.0 License](LICENSE).
|
|
158
556
|
|
|
159
|
-
The
|
|
557
|
+
The Video Core JS library also uses source code from third-party libraries. Full details on which libraries are used and the terms under which they are licensed can be found in the [third-party notices document](THIRD_PARTY_NOTICES.md).
|