@newrelic/video-core 4.1.8-beta → 4.1.8

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