You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: add ctxSegments() and ctxTargetingKeyValues() for contextual targeting (#292)
## Summary
Adds a contextual-classification path to the SDK: fetch the DCN's
taxonomy/category classifications for a page URL, cache them on the SDK
instance, and turn the cached response into GAM-ready targeting key-values.
## What's new
### SDK methods (`lib/sdk.ts`, `lib/edge/contextual_segments.ts`)
- **`OptableSDK.ctxSegments(url?)`** — POSTs to `/v1beta1/contextual`
and returns `ContextualSegmentsResponse` with shape
`{ classifications: { categories: [{ taxonomy, id, score, ... }] } }`.
`url` defaults to `window.location.href`. The response is cached on
the instance; calling again refreshes the cache. Pass-through
behavior (no validation / normalization), matching `Targeting()` at
the edge layer.
- **`OptableSDK.ctxTargetingKeyValues(taxonomyKeys?)`** — reads the
cached response and returns `Record<string, string[]>` of category
ids grouped by taxonomy, ready for
`googletag.pubads().setTargeting()`. Without a map, keys are the raw
taxonomy values; with a map, keys are renamed and only the listed
taxonomies are emitted (filter + rename). Ids are deduped, order
preserved.
- **`initContextual`** is widened from `boolean` to
`boolean | ((response: ContextualSegmentsResponse) => void)`. When
truthy, the SDK fires a pageview witness and `ctxSegments()` at init
time (fire-and-forget), so the cache is populated automatically
before any consumer reads it. When set to a callback function, the
SDK additionally invokes the callback with the response once
`ctxSegments()` resolves — useful for chaining an ad-server load
(e.g. GAM) on the contextual response without making a second
`ctxSegments()` call. The callback is not invoked if the request
fails.
### Tests (`lib/sdk.test.ts`, `lib/test/handlers.ts`)
- MSW handler for `/v1beta1/contextual`.
- Breaking-change tests for both new methods.
- Behavioral coverage: happy path, `window.location.href` default,
empty / missing / malformed responses, categories spanning multiple
taxonomies, cache population, default keying, rename, filter of
unmapped taxonomies, that `initContextual: true` triggers a
contextual request, and that `initContextual` as a function triggers
the request and invokes the callback with the response.
### Docs & demos
- **README** — documents the Contextual Segments API: `ctxSegments()`
caching semantics, the `initContextual` precondition for
`ctxTargetingKeyValues()`, the `boolean | callback` union type, the
callback-driven `loadGAM` pattern, the explicit
`ctxSegments().then(loadGAM)` alternative, key rename/allow-list,
and the requirement that the URL already be classified by the DCN.
- **Two new vanilla demo pages** —
`demos/vanilla/targeting/ctx_segments.html.tpl` and
`demos/vanilla/nocookies/targeting/ctx_segments.html.tpl` — call
`ctxSegments()`, render categories grouped by taxonomy with score
bars, show the derived GAM key-values, and display the raw JSON
response. Both pages document the `initContextual` callback pattern
in the intro section and in the GAM activation section.
- Both templates registered in the Makefile `demo-html` target and
linked from the Audience Targeting section of `demos/index.html` and
`demos/index-nocookies.html`.
Co-authored-by: Bosko Milekic <bmilekic@MBP-0041.local>
When set, enables page context extraction for contextual intelligence. Set to `true` to use defaults, or pass a `PageContextConfig` object to customize what is extracted (HTML content, content selector, max lengths). Extracted context is automatically attached to the first `witness()` call that uses `{ includeContext: true }`.
149
151
150
-
-**`initContextual` (boolean, default: `false`)**
151
-
If `true`, the SDK will automatically fire a `pageview` witness event with full page context during initialization. This is the recommended way to enable contextual pageview tracking without writing custom code. Implies `pageContext: true` when no `pageContext` is explicitly configured.
If `true`, the SDK will automatically fire a `pageview` witness event with full page context during initialization, and also call `ctxSegments()` to fetch contextual segments for the current page, caching the result on the instance for later use via `ctxTargetingKeyValues()`. This is the recommended way to enable contextual pageview tracking and contextual targeting without writing custom code. Implies `pageContext: true` when no `pageContext` is explicitly configured.
154
+
When set to a callback function, the SDK does everything `true` does **and** invokes the callback with the `ContextualSegmentsResponse` once it resolves — useful for chaining an ad-server load (e.g. GAM) on the contextual response without making a second `ctxSegments()` call. The callback is not invoked if the request fails.
152
155
153
156
-**`consent` (`InitConsent`)**
154
157
Defines the consent settings for data collection and processing.
To reset the context (e.g. on SPA navigation), call `sdk.resetContext()` before the next `witness()` call.
406
409
410
+
### Contextual Segments API
411
+
412
+
In addition to pageview tracking, the SDK can classify a page URL against one or more contextual taxonomies (such as the [IAB Content Taxonomy](https://iabtechlab.com/standards/content-taxonomy/)) and use the result for ad targeting. Call `ctxSegments()` to fetch the contextual classifications for a URL:
413
+
414
+
```javascript
415
+
// Classify the current page (defaults to window.location.href):
Each call to `ctxSegments()` caches its response on the SDK instance (calling it again refreshes the cache). When `initContextual: true`, the SDK calls `ctxSegments()` for you during initialization, so the cache is populated automatically.
433
+
434
+
> **Note:** The requested URL must already have been classified by the DCN. If the DCN has no classification for the URL, the response will contain an empty `categories` array.
435
+
436
+
#### Contextual targeting key-values
437
+
438
+
`ctxTargetingKeyValues(taxonomyKeys?)` reads the cached `ctxSegments()` response and builds a `Record<string, string[]>` of category ids grouped by taxonomy, ready to pass to an ad server such as Google Ad Manager via `googletag.pubads().setTargeting()`.
439
+
440
+
Without arguments, each taxonomy value is used as the key:
Pass a `taxonomyKeys` map to rename keys. Only taxonomies present in the map are emitted (filter + rename), which is useful when you only want to set keys you have configured in your ad server:
A typical Google Ad Manager activation uses a `loadGAM()` helper:
455
+
456
+
```javascript
457
+
// Helper to load GAM ads with optional targeting data:
458
+
varloadGAM=function (tdata= {}) {
459
+
window.googletag=window.googletag|| { cmd: [] };
460
+
googletag.cmd.push(function () {
461
+
for (const [key, values] ofObject.entries(tdata)) {
462
+
googletag.pubads().setTargeting(key, values);
463
+
}
464
+
googletag.pubads().refresh();
465
+
});
466
+
};
467
+
```
468
+
469
+
Because `ctxTargetingKeyValues()` reads the cached response, the instance should be initialized with `initContextual: true` so the segments are fetched during initialization and the cache is likely populated by the time `loadGAM()` runs:
If you want `loadGAM()` to run as soon as the contextual segments arrive — without making a second `ctxSegments()` call — pass a callback to `initContextual`. The SDK fires the contextual request automatically during initialization and invokes the callback with the response, populating the cache before `ctxTargetingKeyValues()` reads from it:
476
+
477
+
```javascript
478
+
constsdk=newOptableSDK({
479
+
host:"dcn.customer.com",
480
+
site:"my-site",
481
+
initContextual:function (response) {
482
+
loadGAM(sdk.ctxTargetingKeyValues());
483
+
},
484
+
});
485
+
```
486
+
487
+
If you are not using `initContextual` at all, fetch the segments explicitly and call `loadGAM()` once `ctxSegments()` resolves (falling back to an untargeted load on error):
488
+
489
+
```javascript
490
+
optable.cmd.push(function () {
491
+
optable.instance
492
+
.ctxSegments()
493
+
.then(loadGAM)
494
+
.catch((err) => {
495
+
loadGAM();
496
+
});
497
+
});
498
+
```
499
+
500
+
You can also rename and allow-list the GAM keys by passing a `taxonomyKeys` map to `ctxTargetingKeyValues()` (only the taxonomies present in the map are emitted):
501
+
502
+
```javascript
503
+
// Emit only the "iab_ct_3_1" taxonomy, under the GAM key "ctx_iab":
For each [SDK release](https://github.com/Optable/optable-web-sdk/releases), a webpack-generated browser bundle targeting the browsers list described by `pnpm dlx browserslist "> 0.25%, not dead"` can be loaded on a website via a `script` tag.
0 commit comments