From cd4bdd6bdf82a6444f10528291577d05e322f1bc Mon Sep 17 00:00:00 2001 From: Anton Demydov Date: Mon, 8 Jun 2026 17:04:46 +0300 Subject: [PATCH 1/4] feat: add stackup RTD module documentation --- dev-docs/modules/stackupRtdProvider.md | 184 +++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 dev-docs/modules/stackupRtdProvider.md diff --git a/dev-docs/modules/stackupRtdProvider.md b/dev-docs/modules/stackupRtdProvider.md new file mode 100644 index 0000000000..096c4f2820 --- /dev/null +++ b/dev-docs/modules/stackupRtdProvider.md @@ -0,0 +1,184 @@ +--- +layout: page_v2 +title: Stack Up RTD Provider +display_name: Stack Up RTD Provider +description: Enriches Prebid.js bid requests with IAB contextual and audience segments derived from page content — no cookies or user identifiers required. +page_type: module +module_type: rtd +module_code: stackupRtdProvider +enable_download: true +vendor_specific: true +sidebarType: 1 +--- + +# Stack Up RTD Provider + +{:.no_toc} + +- TOC + {:toc} + +## Overview + +The Stack Up RTD module enriches Prebid.js bid requests with contextual and audience segments derived from the content of the current page. Before the auction fires, the module calls the Stack Up enrichment API (or reads from a `sessionStorage` cache on revisit) and merges the response into the global `ortb2` fragments: + +- **`site.content.data`** — Stack Up Content Taxonomy 1.0 segments (segtax 502): topics, brand-safety signals, and emotion signals attached to the article. +- **`user.data`** — Stack Up Audience Taxonomy 1.0 segments (segtax 501) inferred from contextual signals. + +Every bidder that participates in the auction receives these segments in its `ortb2` object. No cookies, fingerprints, or user identifiers are transmitted to the Stack Up API — only a URL path and publisher domain. + +Become a member of Stack Up in order to receive your `pubId`. Contact [support@stackup-ai.com](mailto:support@stackup-ai.com) for more details. + +## Build + +Include the Stack Up RTD module and the core RTD module when building Prebid.js: + +```bash +gulp build --modules=rtdModule,stackupRtdProvider +``` + +Add any bid adapters you use to the same build command: + +```bash +gulp build --modules=rtdModule,stackupRtdProvider,appnexusBidAdapter +``` + +> `rtdModule` is required to use the Stack Up RTD module. + +## Configuration + +Configure the module inside `realTimeData.dataProviders` via `pbjs.setConfig`. + +```javascript +pbjs.setConfig({ + realTimeData: { + auctionDelay: 1000, + dataProviders: [ + { + name: "stackupRtd", + waitForIt: true, + params: { + pubId: "YOUR-PUB-ID", // required — issued by Stack Up + timeout: 300, // optional — enrichment budget in ms + articleIdMode: "path", // optional — 'path' (default) or 'explicit' + articleId: "", // required when articleIdMode is 'explicit' + apiUrl: "https://api.stackup-ai.com/v1/enrich-ortb-rtd", // optional + cache: { + ttlSeconds: 3600, // optional + }, + }, + }, + ], + }, +}); +``` + +### Parameters + +{: .table .table-bordered .table-striped } +| Name | Scope | Type | Description | Default | +| :--- | :---: | :---: | :--- | :---: | +| `name` | required | String | Must be `'stackupRtd'` | — | +| `waitForIt` | recommended | Boolean | Set `true` when an `auctionDelay` is defined | `false` | +| `params` | required | Object | Module configuration object | — | +| `params.pubId` | required | String | Publisher ID issued by Stack Up | — | +| `params.timeout` | optional | Integer | Max ms to wait for the enrichment API before releasing the auction | `300` | +| `params.articleIdMode` | optional | String | How the article ID is determined. `'path'` derives it from the page URL; `'explicit'` uses `params.articleId` directly | `'path'` | +| `params.articleId` | optional\* | String | Article identifier — required when `articleIdMode` is `'explicit'`. Max 512 characters | — | +| `params.apiUrl` | optional | String | Override the Stack Up enrichment endpoint | `'https://api.stackup-ai.com/v1/enrich-ortb-rtd'` | +| `params.cache.ttlSeconds` | optional | Integer | How long a cached result is considered fresh (sessionStorage TTL) | `3600` | +| `params.debug` | optional | Boolean | Enable verbose `[stackupRtd]` console logging | `false` | +| `params.debugDomain` | optional | String | Override the domain sent to the API when `debug: true` | page domain | + +## Article ID Resolution + +### `articleIdMode: 'path'` (default) + +The module normalises the current page URL path using Prebid's built-in referer detection (works inside iframes and AMP frames). The normalisation strips trailing slashes, AMP path variants (`/amp/`, `/_amp/`, `/amp` suffix), and double slashes. The resulting path is sent to the API and is also used as the `sessionStorage` cache key so cache hits are consistent across AMP and canonical URLs for the same article. + +### `articleIdMode: 'explicit'` + +Pass a stable, opaque article identifier directly in `params.articleId`. Use this when you have a CMS-issued slug or numeric ID that is more stable than the URL. + +## Caching + +On the first visit to a page the module fetches from the API and writes the result to `sessionStorage` under the key: + +```text +stackup:enrich:v1:path_ +``` + +On subsequent page views within the same session the cache is read instead of calling the API, keeping enrichment latency at ~0 ms. Cache entries expire after `params.cache.ttlSeconds` (default 1 hour). + +## Consent + +The module respects user consent before making any network requests: + +- **COPPA**: if `coppa: true` is set, the module is inert. +- **GDPR**: when GDPR applies, the module requires consent (or legitimate interest) for **Purpose 1** (Store/access information on a device) and **Purpose 4** (Select personalised content). If either purpose is missing, or if `vendorData` is absent (e.g. CMP timeout), the module does nothing. +- **USP / CCPA / GPP**: not enforced — the Stack Up API receives only a URL path and domain, no user identifiers, so US sale-of-data frameworks do not apply. + +## ortb2 Output Shape + +After a successful enrichment the following fields are merged into the global `ortb2` object (non-destructively — existing publisher values are preserved): + +```json +{ + "site": { + "content": { + "id": "", + "title": "
", + "data": [ + { + "name": "stackup-ai.com", + "ext": { "segtax": 502 }, + "segment": [ + { + "id": "IAB-123", + "name": "Technology", + "ext": { "confidence": 0.95 } + } + ] + } + ], + "ext": { + "brand_safety": {}, + "emotion": {} + } + } + }, + "user": { + "data": [ + { + "name": "stackup-ai.com", + "ext": { "segtax": 501 }, + "segment": [ + { + "id": "AUD-456", + "name": "Tech Enthusiasts", + "ext": { "confidence": 0.87 } + } + ] + } + ] + } +} +``` + +`site.content.ext.brand_safety` and `site.content.ext.emotion` are optional fields populated when the API returns them. Existing publisher values in `ext` are preserved — the module only fills fields that are absent. + +## Integration Example + +Build Prebid.js with the module: + +```bash +gulp build --modules=rtdModule,stackupRtdProvider,appnexusBidAdapter +``` + +Then open the live integration example with `debug: true`: + +```text +http://localhost:9999/integrationExamples/gpt/stackupRtdProvider_example.html +``` + +The page shows the fetch URL, the `sessionStorage` cache entry, per-bidder `ortb2` payloads, and the page-level `ortb2` config after the auction completes. From a6a63f1c334d7ffbb2e5edeff7d061cbdb2f1dd2 Mon Sep 17 00:00:00 2001 From: Anton Demydov Date: Mon, 8 Jun 2026 17:26:34 +0300 Subject: [PATCH 2/4] feat: added prebid_member to sStack Up md file --- dev-docs/modules/stackupRtdProvider.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-docs/modules/stackupRtdProvider.md b/dev-docs/modules/stackupRtdProvider.md index 096c4f2820..3223be45ba 100644 --- a/dev-docs/modules/stackupRtdProvider.md +++ b/dev-docs/modules/stackupRtdProvider.md @@ -8,6 +8,7 @@ module_type: rtd module_code: stackupRtdProvider enable_download: true vendor_specific: true +prebid_member: false sidebarType: 1 --- From 3665831020f83c8951a64005136e866b979267cb Mon Sep 17 00:00:00 2001 From: Anton Demydov Date: Mon, 8 Jun 2026 20:02:17 +0300 Subject: [PATCH 3/4] docs: update stackupRtdProvider documentation to reflect new module features - Add missing cache configuration options (enabled, storage) to parameters table - Expand Configuration example with complete cache and debug parameters - Enhance Caching section with memory storage and disabling details - Fix provider name in ortb2 output example to use 'data.stackup-ai.com' - Clarify integration example and debug console behavior --- dev-docs/modules/stackupRtdProvider.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/dev-docs/modules/stackupRtdProvider.md b/dev-docs/modules/stackupRtdProvider.md index 3223be45ba..4502196c34 100644 --- a/dev-docs/modules/stackupRtdProvider.md +++ b/dev-docs/modules/stackupRtdProvider.md @@ -65,8 +65,11 @@ pbjs.setConfig({ articleId: "", // required when articleIdMode is 'explicit' apiUrl: "https://api.stackup-ai.com/v1/enrich-ortb-rtd", // optional cache: { + enabled: true, // optional — disable all cache read/write when false ttlSeconds: 3600, // optional + storage: "session", // optional — 'session' (default) or 'memory' }, + debug: false, // optional }, }, ], @@ -87,7 +90,9 @@ pbjs.setConfig({ | `params.articleIdMode` | optional | String | How the article ID is determined. `'path'` derives it from the page URL; `'explicit'` uses `params.articleId` directly | `'path'` | | `params.articleId` | optional\* | String | Article identifier — required when `articleIdMode` is `'explicit'`. Max 512 characters | — | | `params.apiUrl` | optional | String | Override the Stack Up enrichment endpoint | `'https://api.stackup-ai.com/v1/enrich-ortb-rtd'` | +| `params.cache.enabled` | optional | Boolean | Enable/disable cache usage entirely | `true` | | `params.cache.ttlSeconds` | optional | Integer | How long a cached result is considered fresh (sessionStorage TTL) | `3600` | +| `params.cache.storage` | optional | String | Cache backend: `'session'` for browser sessionStorage or `'memory'` for in-process cache | `'session'` | | `params.debug` | optional | Boolean | Enable verbose `[stackupRtd]` console logging | `false` | | `params.debugDomain` | optional | String | Override the domain sent to the API when `debug: true` | page domain | @@ -103,13 +108,17 @@ Pass a stable, opaque article identifier directly in `params.articleId`. Use thi ## Caching -On the first visit to a page the module fetches from the API and writes the result to `sessionStorage` under the key: +When `params.cache.enabled` is `true` (default), the module checks cache before making a network call. + +With `params.cache.storage: 'session'` (default), the result is written to `sessionStorage` under the key: ```text stackup:enrich:v1:path_ ``` -On subsequent page views within the same session the cache is read instead of calling the API, keeping enrichment latency at ~0 ms. Cache entries expire after `params.cache.ttlSeconds` (default 1 hour). +With `params.cache.storage: 'memory'`, entries are kept in runtime memory only and are cleared on full page reload. + +On subsequent page views within the same session the cache is read instead of calling the API, keeping enrichment latency at ~0 ms. Cache entries expire after `params.cache.ttlSeconds` (default 1 hour). Setting `params.cache.enabled: false` disables both reads and writes. ## Consent @@ -131,7 +140,7 @@ After a successful enrichment the following fields are merged into the global `o "title": "
", "data": [ { - "name": "stackup-ai.com", + "name": "data.stackup-ai.com", "ext": { "segtax": 502 }, "segment": [ { @@ -151,7 +160,7 @@ After a successful enrichment the following fields are merged into the global `o "user": { "data": [ { - "name": "stackup-ai.com", + "name": "data.stackup-ai.com", "ext": { "segtax": 501 }, "segment": [ { @@ -176,10 +185,10 @@ Build Prebid.js with the module: gulp build --modules=rtdModule,stackupRtdProvider,appnexusBidAdapter ``` -Then open the live integration example with `debug: true`: +Start a static file server at the repo root on port 9999, then open: ```text http://localhost:9999/integrationExamples/gpt/stackupRtdProvider_example.html ``` -The page shows the fetch URL, the `sessionStorage` cache entry, per-bidder `ortb2` payloads, and the page-level `ortb2` config after the auction completes. +The page runs a real GAM/GPT auction. With `debug: true` in `pbjs.setConfig` the Prebid.js debug console shows the enriched `ortb2` fragments (`site.content.data` and `user.data`) merged into each bid request. From 3fff8999175587299fc8e41ba0842222ee3cf915 Mon Sep 17 00:00:00 2001 From: Anton Demydov Date: Tue, 9 Jun 2026 08:59:04 +0300 Subject: [PATCH 4/4] docs: added repo root link --- dev-docs/modules/stackupRtdProvider.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-docs/modules/stackupRtdProvider.md b/dev-docs/modules/stackupRtdProvider.md index 4502196c34..36c1408097 100644 --- a/dev-docs/modules/stackupRtdProvider.md +++ b/dev-docs/modules/stackupRtdProvider.md @@ -185,7 +185,7 @@ Build Prebid.js with the module: gulp build --modules=rtdModule,stackupRtdProvider,appnexusBidAdapter ``` -Start a static file server at the repo root on port 9999, then open: +Start a static file server at the [Prebid.js repo root](https://github.com/prebid/Prebid.js) on port 9999, then open: ```text http://localhost:9999/integrationExamples/gpt/stackupRtdProvider_example.html