# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
This site has an agentic ask interface you may use to query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.hbwrapper.com/index.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

---

# Introduction

This documentation provides a comprehensive guide to the Header Bidding wrapper, designed to help you understand, configure, and customize its powerful features.

The wrapper is a single script that runs the whole header bidding process for a website: it collects bids from many ad buyers at once, runs the competition, talks to Google Ad Manager, and displays the winning ad. It's built on Prebid.js and is designed to manage thousands of sites from one place.

**New to header bidding, or not a developer?** Start with the [Glossary](/glossary) — it explains every term used in these docs in plain language before you dive into the technical p


# Project Description

A high-performance, fully modular, and enterprise-grade Header Bidding Wrapper built on **Prebid.js**, designed to scale effortlessly across **thousands of websites** and optimized for **billions of pageviews monthly**.

> **In plain terms:** this is one script that runs the entire process of selling a website's ad space through open competition. When a page loads, the wrapper asks many ad buyers to bid at the same time, picks the best offer, hands it to Google Ad Manager, and shows the winning ad — all in a fraction of a second. It's designed so that one team can manage the ad setup for thousands of sites from a single place, just by editing settings files. If any term below is unfamiliar, the [Glossary](/glossary) explains them all in everyday language.

***

## 🚀 Key Features

### 🔧 Modular Micro-Script Architecture

* **Only the code you need, per site**\
  Each domain loads a minimal, optimized JavaScript payload tailored to its unique configuration.
* **Automatic builds and deployments**\
  CI/CD system ensures your wrapper is always up to date, with each configuration change triggering a fresh, versioned build.

### 🌍 Designed for Scale

* Manage **thousands of sites** from a centralized, structured configuration.
* JSON-based config makes onboarding and updates fast and reliable.
* Production-tested on **billions of monthly pageviews**.

### ☁️ Delivered via Specialized CDN

* Served from a **CDN optimized for ad tech assets**, ensuring:
  * **Fast initial load**
  * **Caching optimization**
  * **Frequent updates** without cache bloat or versioning issues

### 🧱 Built on Prebid.js

* On top of Prebid.js, supports **hybrid header bidding** (client-side + server-side)
* Supports:
  * **High-impact Rich Media** ad formats
  * **ID modules**
  * **User sync**
  * **GDPR/CCPA compliance**

### 🎯 Manages Google Ad Manager (GAM)

* **No on-page GAM setup required** — the wrapper fully manages all GAM interactions.
* Pushes **precise key-values** to GAM for:
  * Advanced delivery targeting
  * Optimized creative decisioning
  * Vast and detailed key values reporting for GAM to analyze the delivery and results of ads

### 📊 Advanced Ad Tech Capabilities

* **Flexible Safe Frames Signal** — Industry-first impression-level SafeFrame control based on bid characteristics (bidder, CPM, domain, category, or ad unit)
* **Bot detection** to reduce invalid traffic
* **Granular ad refresh controls**
* **Fallback renderer** to display ads when GAM returns no creative
* **Custom JS hooks** for full control at auction, render, or bid-won events

### ⚙️ Easy to Implement

* Built for fast integration
* Suitable for **both simple and complex implementations**
* **Supports complex integrations with a Publisher API**

### 🧑‍💻 Developer-Friendly

* **Implement any custom JavaScript**
* **All configuration handled in JSON** — clean, structured, and scalable

### 🔄 Always Up to Date

* Actively maintained to reflect:
  * The **latest releases from Prebid.org**
  * **IAB Tech Lab standards**
  * **Industry best practices** — implemented by default

***

## 🧰 Use Cases

* Ad tech teams managing thousands of sites
* Publishers seeking flexibility, performance, and complete control
* Networks needing rapid deployment and ad decisioning at scale

***

## 🧭 Key Concepts

* Wrapper: Script coordinating header bidding, auctions, and GAM requests.
* Ad unit: Placement configured in GAM and mapped on-page via `data-aa-...` attributes.
* GAM: Google Ad Manager, the ad server receiving requests from the wrapper.
* Auction: Parallel demand competition (Prebid) before the GAM request.
* Lazy load: Defers ad requests until elements approach the viewport.
* Refresh: Re-requests ads on a timer or when viewable.

See also

* Public API: `Public-API.md`
* Configuration: `Configuration.md`

## 📊 Workflow

```
+-----------------------+       +-----------------------+       +---------------------+       +-------------------------+       +--------------------+
| JSON Config Files     |  -->  |   Build System        |  -->  |     CDN Delivery    |  -->  | Publisher Site Loads    |  -->  |   Ads Displayed    |
| (Structured Settings) |       | (Wrapper Generator)   |       | (Optimized Wrapper) |       | (Script Integration)    |       | (User Sees Ads)    |
+-----------------------+       +-----------------------+       +---------------------+       +-------------------------+       +--------------------+
          |                                |                               |                               |                              |
   Site-specific JSON              Auto versioning &              Cached, fast-loading           Wrapper executes and               Wrapper handle
   for units, bidders,            minified script builds         wrapper scripts via CDN        triggers auction on page           auction & render
   refresh, etc.                                                                                        

```


# Glossary

New to header bidding, or coming from the business side rather than engineering? Start here. This page explains the terms used throughout the documentation in plain language. Each entry says what the thing is and why it matters, without assuming you write code.

If you only read one page before the rest, read this one.

***

## The big picture

**Header bidding** A way of selling ad space on a website. Instead of asking one ad seller at a time, the page asks many ad buyers to bid at the same time, then sends the best price to the ad server. More competition usually means more revenue for the publisher. It's called "header" bidding because the code historically ran early in the page's HTML `<head>`.

**Wrapper** The software this documentation is about. It's a single script that a website loads once. The wrapper runs the whole header bidding process for you: it collects bids, runs the competition, talks to the ad server, and shows the winning ad. Think of it as the conductor of an orchestra — it coordinates all the other pieces so you don't have to wire them together by hand on every site.

**Prebid.js** The open-source, industry-standard library that actually runs the bidding. The wrapper is built on top of Prebid.js and adds automation, scale (thousands of sites from one place), extra features, and management of the Google ad server. When the docs mention a "Prebid" setting, it's a setting that comes from this underlying library.

**Publisher** The owner of the website that shows the ads and earns the revenue. If you manage sites, you're the publisher (or you work for one).

***

## The ad-serving pieces

**GAM (Google Ad Manager)** Google's ad server — the system that ultimately decides which ad to show in each slot and records what was delivered. The wrapper talks to GAM for you, so you don't have to add Google's ad code to the page yourself.

**DFP** The old name for Google Ad Manager (it used to be called "DoubleClick for Publishers"). You'll still see `dfp` used as the name of several settings in the configuration files — for example `dfp.collapseEmptyDivs`. Whenever you see `dfp` in a setting name, read it as "Google Ad Manager." The name stuck around for backwards compatibility even though the product was renamed.

**Ad unit** A single ad placement — one spot on the page where an ad can appear (e.g. the leaderboard at the top, or the box in the sidebar). Each ad unit is set up in GAM and connected to a spot on the page.

**Ad unit code / path** The full identifier of an ad unit in GAM, written like a folder path, e.g. `/22181265/Homepage/Leaderboard`. Important: always use the ad unit **CODE** (the path), not the friendly display **NAME** you see in the GAM interface — they are not the same, and mixing them up is a common cause of ads not showing.

**Slot** Another word for the on-page container where a specific ad is rendered. Loosely interchangeable with "ad unit" in everyday use.

***

## How an ad gets chosen

**Auction** The competition among ad buyers for a single ad slot, run by the wrapper before it asks GAM for an ad. All buyers bid in parallel, and the highest useful bid is passed along. Faster and fairer than asking buyers one at a time.

**Bidder / SSP / demand partner / network** A company that bids to buy the ad space (e.g. Rubicon, PubMatic, AppNexus). These terms are used loosely to mean "a source of ad demand." You configure which bidders compete for each ad unit.

**Bid** An offer from a bidder — a price they'll pay to show their ad in the slot.

**CPM** "Cost per mille" — the price for one thousand ad impressions. Ad prices are quoted this way. A $2.00 CPM means the buyer pays $2.00 for every 1,000 times the ad is shown. Most bid and floor settings are expressed as CPMs.

**Floor / price floor** The minimum price you'll accept for an ad. Bids below the floor are ignored. Floors help protect the value of your inventory.

**Client-side vs. server-side (S2S)** Two places the auction can happen. *Client-side* means the bidding runs in the visitor's browser. *Server-side* (also written **S2S**, "server-to-server") means some of the bidding is handed off to a server, which is faster for the browser and can include more bidders without slowing the page. This wrapper supports a **hybrid** approach — using both at once.

**Amazon / A9 / UAM** Amazon's separate ad-demand system, which runs alongside Prebid. The wrapper can include it in the competition; it's configured on its own because it works a bit differently from other bidders.

***

## What the wrapper tracks and sends

**Key-value (targeting key-value)** A small labelled piece of information the wrapper attaches to each ad request so GAM can make decisions and you can report on them. For example, "the winning bidder was pubmatic" or "this visitor is on mobile." The wrapper sends many of these automatically. The full list is in [Key-Values](/key-values).

**Impression** One instance of an ad being shown to a visitor.

**OpenRTB impression fields (`ortb2Imp`)** Structured data attached to each ad slot in the bid request so buyers know which placement it is and whether HTTPS creatives are required. The wrapper sets these automatically: `secure` (`1`, HTTPS creatives required; a publisher-set value including `0` is honored), GPID, GAM adslot, and an interstitial flag (`instl`) when the placement is an interstitial.

**GPID (Global Placement ID)** A unique identifier for a specific slot on the page, sent as `ortb2Imp.ext.gpid`. When the same GAM path is used more than once (feeds, infinite scroll), the wrapper adds a `#` suffix so buyers can tell the slots apart.

**Viewable / viewability** Whether an ad was actually seen. The industry standard (and what the wrapper measures) is that at least **50%** of the ad was on screen for at least **1 continuous second**. Viewability drives some refresh behaviour and reporting.

**Refresh** Automatically requesting a new ad for a slot after some time or after it's been viewed, so the same visitor can generate more than one impression from the same spot. The wrapper gives you fine control over when and how often this happens.

**Lazy loading** Waiting to request an ad until the visitor is about to scroll it into view, instead of loading every ad up front. This speeds up the page and improves viewability, because ads aren't requested for spots the visitor never reaches.

***

## Privacy, safety, and quality

**GDPR / CCPA / consent** Privacy regulations (Europe and California, respectively) that govern how visitor data can be used for advertising. The wrapper handles the required consent signals so bidders receive the right permissions.

**SafeFrame** A protective wrapper GAM can put around an ad so the ad can't interfere with the rest of your page. It's safer but limits what some bidders can do, which can reduce revenue. This wrapper offers a unique "flexible" mode that turns SafeFrames on only for specific impressions rather than all of them — see `dfp.flexibleSafeFramesSignal` in [Configuration](/configuration).

**Bot / invalid traffic (IVT)** Automated visitors that aren't real people. Showing ads to bots wastes money and can get you penalised, so the wrapper can detect and block them.

**Rich media format** A special, more interactive ad presentation — for example an ad that sticks to the bottom of the screen (adhesion), stays in place as you scroll (sticky), or covers the page (interstitial). See [Rich Media Formats](/rich-media).

***

## Delivery and configuration

**CDN (Content Delivery Network)** A globally distributed network of servers that delivers the wrapper script quickly to visitors anywhere. The wrapper is served from a CDN tuned for ad-tech so it loads fast and updates cleanly.

**JSON config** The settings files that control the wrapper. "JSON" is just a structured text format for settings — a series of names and values inside braces `{ }`. You don't program the wrapper; you configure it by editing these files. The main ones are `config.json` (site-wide settings), `adunits.json` (per-placement settings), `deviceDetection.json` (screen-size rules), and `modules.json` (which bidders are included). All are documented in [Configuration](/configuration).

**Build / CI/CD** The automated process that turns your JSON settings into the finished script on the CDN. Every time you change a config, a fresh, versioned copy is built and deployed automatically. You don't run this by hand.

**`globalVar` / `pbjs`** The name of the wrapper's control object in the browser — the handle your custom code uses to talk to the wrapper (for example to refresh ads). Each site sets its own name via the `globalVar` setting; the examples in these docs use `pbjs`. Wherever you see `pbjs` in a code example, substitute your site's actual value if it's different.

**Command queue (`pbjs.cmd`)** A safe "to-do list" for the wrapper. Because the wrapper loads asynchronously, you don't call it directly — you push your instructions onto `pbjs.cmd` and the wrapper runs them as soon as it's ready. This is why the code examples wrap instructions in `pbjs.cmd.push(function () { ... })`.

**Device detection** How the wrapper decides whether a visitor is on desktop, tablet, or mobile — based on screen or window width. You define the size breakpoints in `deviceDetection.json`, and can add your own labels (for example a `bigDesktop` tier) beyond the default three.

***

Ready for detail? Continue to [Configuration](/configuration) for every setting, or [Public API](/public-api) for the commands your own code can call.


# Configuration

This section provides a detailed overview of the configuration files used in the Header Bidding wrapper.

## How configuration works (read this first)

You don't program the wrapper — you **configure** it by editing settings files written in JSON. JSON is just a structured way of writing settings: names and values inside braces `{ }`. A change to any of these files triggers an automatic rebuild and redeploy of the wrapper (see [Glossary → Build](/glossary)).

There are four files, each with a job:

| File                   | What it controls                                                                                                         |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `config.json`          | Site-wide settings: identity, timeouts, bidding behaviour, privacy, refresh, ad-server (GAM) options. Most of this page. |
| `adunits.json`         | Per-placement settings: one entry per ad unit (sizes, devices, bidders, refresh, formats).                               |
| `deviceDetection.json` | The screen-width rules that decide whether a visitor is desktop, tablet, mobile (or a custom tier).                      |
| `modules.json`         | Which bidder adapters (demand partners) are included in the build.                                                       |

**A naming note that trips people up:** many settings live under a `dfp` group (e.g. `dfp.collapseEmptyDivs`). "DFP" is the old name for **Google Ad Manager (GAM)** — read every `dfp` setting as "Google Ad Manager." The name was kept for backwards compatibility. Likewise, `dfpAccount` means your GAM account ID.

Each setting below is documented with its **Description**, whether it's **Required**, its **Default** where one exists, and an example. Unfamiliar with a term (CPM, bidder, S2S, SafeFrame, floor)? See the [Glossary](/glossary).

Before You Begin

* Confirm GAM ad unit CODES and full paths
* Align device detection names with `deviceDetection.json`
* Decide targeting prefix and understand SafeFrames/S2S implications

Common Pitfalls

* Using GAM ad unit NAME instead of CODE
* Double quotes inside HTML `data-` JSON; prefer single quotes on attributes
* Device labels mismatch between page and config

## config.json

### `id`

**Description:** An identification number used internally within the wrappers, not across different wrapper instances.

**Required:** Yes - Will throw an error if missing.

**Notes:** It must be an integer.

```javascript
{
	"id" : 12345
}
```

### `code`

**Description:** The identification name of the wrapper. It must be unique.

**Required:** Yes - Will throw an error if missing.

```javascript
{
	"code" : "abc"
}
```

### `file`

**Description:** The name of the file as hosted on the CDN. This is used to build, deploy, and purge. It must be unique.

**Required:** Yes - will not build without it

**Notes:** It is best practice for the file name to be lowercase.

```javascript
{
	"file" : "prefix.code.js"
}
```

### `blockAutoBuild`

**Description:** If `true`, it will not allow the wrapper to be automatically built.

**Required:** No - Optional.

```javascript
{
	"blockAutoBuild" : true
}
```

### `globalVar`

**Description:** The variable that Prebid will use. The wrapper uses a custom variable name for Prebid to avoid conflicts with other wrappers on the page.

**Required:** Yes - Will throw an error if missing.

```javascript
{
	"globalVar" : "pbjs"
}
```

### `targetingPrefix`

**Description:** Sets the prefix of targeting key-values used for sending bids to GAM. For example, `[prefix]_bidder`, `[prefix]_hb`, `[prefix]_adid`.

**Required:** No - Optional.

**Important:** If you use a custom prefix (not `hb`), anything related to Prebid Server and Safe Frames will be disabled.

```javascript
{
	"targetingPrefix" : "chp"
}
```

### `url`

**Description:** The URL to the site where the wrapper will be implemented.

**Required:** Yes - Has default value if not set.

**Default:** `"https://example.com"`

```javascript
{
	"url" : "https://example.com"
}
```

### `dfpAccount`

**Description:** The GAM account ID of the main account.

**Required:** Yes - Has default value if not set.

**Default:** `"1234"`

```javascript
{
	"dfpAccount" : "123456789"
}
```

### `dfpChildAccount`

**Description:** The GAM account ID of the child account. If this is set for an MCM network, it will use the GAM tags appropriate for MCM, using both the main and child account. Do not set it if it is not an MCM network.

**Required:** No - Optional.

```javascript
{
	"dfpChildAccount" : "4567890123"
}
```

### `adunitMapping`

**Description:** The method of mapping the div tags implemented in the page with the config built in the wrapper.

**Required:** Yes - Has default value if not set.

**Default:** `"adunit"`

**Possible Values:**

1. `adunit`: Matches based on adunit (`data-aa-adunit` of the div -> with the property `adunit` from `adunits.json`).
2. `targeting`: Matches based on a key targeting (`data-aa-targeting` of the div -> with the property `targeting` from `adunits.json`).

```javascript
{
	"adunitMapping" : "adunit"
}
```

### `adunitMappingKey`

**Description:** The name of the key-value that will be used for mapping. It only works when `adunitMapping` is `targeting`.

**Required:** No - Optional.

```javascript
{
	"adunitMappingKey" : "location"
}
```

### `gist`

**Description:** The URL to the location of tags that the publisher needs to implement on the page.

**Required:** No - Optional.

```javascript
{
	"gist" : "https://gist.github.com/abc/123"
}
```

### `analytics.clarity`

**Description:** To enable Clarity analytics, use the ID provided in the dashboard.

**Required:** No - Optional.

```javascript
{
	"analytics" : {
		"clarity" : "4l37sx2uso"
	}
}
```

### `analytics.gtm`

**Description:** Enables a GTM container.

**Required:** No - Optional.

**Parameters:**

1. `containerId`: The Google Tag Manager Container ID. Required; without this, the GTM container will not be loaded.
2. `dataLayer`: The name of the variable for Data Layer. Default is `dataLayer`; if not set, it will use the default.

```javascript
{
	"analytics" : {
		"gtm" : {
			"containerId" : "GTM-ABCDE123",
			"dataLayer" : "customDataLayerVariable"
		}
	}
}
```

### `analytics.prebid`

**Description:** Enables a Prebid analytics provider. Can take an array for multiple providers or an object for a single one.

**Required:** No - Optional.

```javascript
{
	"analytics" : {
		"prebid" : [
                       {
                        "provider": "provider1Analytics",
                            "options": {
                                        "partnerId": 123
                            }
                       },
                       {
                        "provider": "provider2Analytics",
                            "options": {
                                        "partnerId": 123
                            }
                       }
                   ]
	}
}
```

### `wrapper.timeout`

**Description:** The maximum time in milliseconds that the header bidding auction will wait for bids.

**Required:** Yes - Has default value if not set.

**Default:** `2000`

```javascript
{
	"wrapper" : {
		"timeout" : 2000
	}
}
```

### `wrapper.conditionalTimeout`

**Description:** The maximum time in milliseconds that the header bidding auction will wait for bids for each device type (as defined in `deviceDetection.json`). It will overwrite the default `timeout` if the device is detected.

**Required:** No - Optional.

```javascript
{
	"wrapper" : {
		"conditionalTimeout" : {
            "desktop": 2000,
            "tablet" : 1500,
            "mobile" : 1000
        }
	}
}
```

### `wrapper.timeoutFallback`

**Description:** The maximum time in milliseconds that the wrapper will wait until it makes the GAM ad request.

**Required:** Yes - Has default value if not set.

**Default:** `5000`

```javascript
{
	"wrapper" : {
		"timeoutFallback" : 5000
	}
}
```

### `wrapper.bidRequestWaitTime`

**Description:** The time in milliseconds that the processing of ads will be throttled to ensure all processing occurs simultaneously.

**Required:** Yes - Has default value if not set.

**Default:** `50`

```javascript
{
	"wrapper" : {
		"bidRequestWaitTime" : 50
	}
}
```

### `wrapper.disableBidders`

**Description:** An array of bidder names that will be excluded from all auctions (completely disabled).

**Required:** Yes - Has default value if not set.

**Default:** `[]` (empty array)

```javascript
{
	"wrapper" : {
		"disableBidders" : ["appnexus","pubmatic"]
	}
}
```

### `wrapper.disableBiddersClientSide`

**Description:** An array of bidder names that will be excluded from all client-side auctions (they will still run in S2S).

**Required:** Yes - Has default value if not set.

**Default:** `[]` (empty array)

```javascript
{
	"wrapper" : {
		"disableBiddersClientSide" : ["appnexus","pubmatic"]
	}
}
```

### `wrapper.firstPartyData`

**Description:** When `true`, enables sending first-party data to the bid stream. Geo, IP, carrier, bot score, A/B bucket, and related fields are enriched into the ortb2 config used for bid requests.

**Required:** No - Optional.

**Default:** `false`

```javascript
{
	"wrapper" : {
		"firstPartyData" : true
	}
}
```

### `wrapper.geoFilter`

**Description:** Filters out bidders based on Geo Detection. Geo Detection is asynchronous and might resolve after the auction is initiated, so this functionality is not 100% guaranteed. The value is an object where each key is a bidder name.

**Required:** No - Optional.

**Filter Options (for each bidder):**

* `whitelist`: Enables the bidder only for specified countries.
* `blacklist`: Disables the bidder for specified countries.

Each option takes an array of country codes (ISO).

```javascript
{
	"wrapper" : {
		"geoFilter" : {
			"33across" : {
				"whitelist" : ["US"],
				"blacklist" : []
			}
		}
	}
}
```

### `wrapper.geoFilterUserId`

**Description:** Filters out User IDs based on Geo Detection. Geo Detection is asynchronous and might resolve after the User ID is initiated, so this functionality is not 100% guaranteed. The value is an object where each key is a User ID name.

**Required:** No - Optional.

**Filter Options (for each User ID):**

* `whitelist`: Enables the User ID only for specified countries.
* `blacklist`: Disables the User ID for specified countries.

Each option takes an array of country codes (ISO).

```javascript
{
	"wrapper" : {
		"geoFilterUserId" : {
			"identityLink" : {
				"whitelist" : ["US","CA","AR","BR","MX","BE","FR","DE","IT"],
				"blacklist" : []
			}
		}
	}
}
```

### `wrapper.patternBlocking`

**Description:** A feature to block the wrapper from executing based on URL, user agent, or geo country patterns. When a pattern matches, the wrapper will halt execution immediately. Each rule type (href, userAgent, geo) is enabled if its array exists and has at least one pattern.

**Required:** No - Optional.

**Parameters:**

* `href`:
  * **Description:** An array of patterns to match against the full page URL (`window.location.href`), including scheme, host, path, and query string. If this array exists and has length > 0, href pattern blocking is enabled.
  * **Possible Values:**
    * Wildcard strings (e.g., `*staging*`, `*example.com/admin/*`, `*legal/*`). `*` matches any sequence of characters, `?` matches a single character.
    * Regex strings, prefixed with `regex:` (e.g., `regex:^https?://(dev|staging)\.example\.com/` or `regex:/legal/`).
  * **Common pitfalls (href):**
    * Path-only patterns such as `/legal/terms/`, `/admin/*`, or `legal/*` usually **do not** match, because the value tested is the full URL (e.g. `https://example.com/legal/terms/`), not the pathname alone.
    * To block a path segment inside the URL, include `*` before and/or after the fragment: `*legal/*`, `*/legal/terms*`, or `*example.com/legal/*`.
    * Wildcard patterns are converted to a **full-string** match (the entire `href` must match). Use `regex:` when you need substring matching without wrapping the pattern in `*`.
* `userAgent`:
  * **Description:** An array of patterns to match against the `navigator.userAgent`. If this array exists and has length > 0, user agent pattern blocking is enabled.
  * **Possible Values:**
    * Wildcard strings (e.g., `*bot*`).
    * Regex strings, prefixed with `regex:` (e.g., `regex:Puppeteer|Playwright`).
* `geo`:
  * **Description:** An array of 2-letter country codes (ISO 3166-1 alpha-2) to block. If this array exists and has length > 0, geo pattern blocking is enabled. The wrapper will halt execution if the detected country matches any code in the array.
  * **Possible Values:**
    * 2-letter country codes (e.g., `"US"`, `"CA"`, `"GB"`, `"FR"`, `"DE"`).
  * **Notes:**
    * Geo detection is asynchronous (happens after the wrapper loads).
    * When country is detected, the geo check is performed **before** any event handlers run.
    * If the detected country matches a blocked country, an **error is thrown** and execution stops completely.
    * If the country is not blocked, the wrapper proceeds normally.

**Code Examples:**

```javascript
"wrapper": {
  "patternBlocking": {
    "href": [
      "*staging*",
      "*example.com/admin/*",
      "*legal/*",
      "regex:^https?://(dev|staging)\\.example\\.com/",
      "regex:/legal/(terms|privacy)"
    ],
    "userAgent": [
      "*bot*",
      "*Headless*",
      "regex:Puppeteer|Playwright|HeadlessChrome"
    ],
    "geo": [
      "US",
      "CA",
      "GB"
    ]
  }
}
```

**Notes:**

* The `href` and `userAgent` checks are performed **immediately** at script load before any processing begins (synchronous).
* The `geo` check is performed **after** the country is detected (asynchronous):
  * Geo detection happens in the background after the wrapper loads
  * Once the country is detected, the geo check runs **in the callback** before emitting any events
  * If the country matches a blocked country, an **error is thrown** and execution halts completely
  * If the country is not blocked, the wrapper proceeds normally
* Each rule type is independently enabled based on the presence and length of its array.
* Wildcard matching (for href and userAgent) is case-insensitive. Each wildcard pattern must match the **entire** `href` or `userAgent` string unless you use `*` so the pattern can span the full value (e.g. `*legal/*` on `https://example.com/legal/terms/`).
* `regex:` patterns match as **substrings** (no automatic `^` / `$` anchors). Add anchors in the regex when you need a full-string match.
* For regex patterns, you can control flags within the pattern itself.
* Country code matching is case-insensitive.
* `userAgent` rules typically target bots and automation; normal browser user agents will not match unless you add patterns that match them (e.g. `*google*` matches Chrome on all pages).

### `wrapper.trafficIntegrity`

**Description:** Traffic Integrity Score (TIS) — invalid traffic (IVT) scoring. When enabled, the wrapper asks a scoring endpoint how likely the current visit is to be non-human, and gets back a **score from 0 to 100**, where **100 means almost certainly bot traffic**. A visit scoring at or above the threshold you set stops the wrapper from running any further auctions.

Unlike `patternBlocking`, this check is **asynchronous** — the wrapper does not wait for the answer before starting. See the Notes below for exactly what blocking can and cannot stop.

There is **no endpoint setting**. The URL is derived automatically from the analytics host already in use by the build, with `/tis` appended.

**Required:** No - Optional. The feature is **off unless a `block` threshold is set**, and no scoring request is made until then.

**Parameters:**

* `block`:
  * **Description:** The score at or above which the wrapper stops. This is the switch for the whole feature: with `false` there is nothing to act on, so the wrapper does not contact the endpoint at all.
  * **Possible Values:** `false`, or a number between `0` and `100` (typically `50` or higher).
  * **Default:** `false` (feature off).

`block` is the only setting.

**Code Examples:**

Block traffic scored 70 or above:

```javascript
{
	"wrapper" : {
		"trafficIntegrity" : {
			"block" : 70
		}
	}
}
```

Off — the default. No scoring request is made:

```javascript
{
	"wrapper" : {
		"trafficIntegrity" : {
			"block" : false
		}
	}
}
```

**What gets sent:** the site `id` and `code`, the page URL and referrer, the wrapper's pageview and session identifiers, and a small set of automation signals for the endpoint to score — whether the browser reports itself as automated, whether it claims to be Chrome without behaving like it, whether it has a language list and plugins, whether the window has a real size, and the user agent. No personal data is collected by the wrapper for this call, and no cookies are sent with it.

**What blocking stops:** when the score meets the threshold, the wrapper stops doing any further ad work — no processing, no bid requests, no GAM requests, and no refreshes.

**Notes:**

* No `block` threshold means no request. Nothing is sent to the endpoint until a number is set.
* The request is sent **once per pageview**, as early as possible — immediately after `patternBlocking`.
* Because the check is asynchronous, the answer usually arrives before the first auction, but this is **not guaranteed**. Anything already in flight when the verdict arrives is allowed to finish; ads that have already rendered are left alone rather than being torn down.
* The feature **fails open**. If the request fails or comes back malformed, nothing is blocked and the wrapper continues normally. A bad or unreachable endpoint can never take a site's ads down.
* Be careful with very low thresholds: `"block": 0` matches every possible score and will block **all** traffic.
* Blocking is decided per pageview and is not remembered; nothing is written to cookies or local storage.

### `wrapper.disableInitialProcessAdsOnPage`

**Description:** If `true`, it will disable any automatic processing of ads on page load.

**Required:** No - Optional.

```javascript
{
	"wrapper" : {
		"disableInitialProcessAdsOnPage" : true
	}
}
```

### `wrapper.prebidServer.enabled`

**Description:** Enables Prebid Server for Hybrid bidding (both Client and S2S).

**Required:** No - Optional.

```javascript
{
	"wrapper" : {
		"prebidServer" : {
			"enabled" : true
		}
	}
}
```

### `wrapper.prebidServer.accountId`

**Description:** Prebid Server Account ID, if required by the Prebid Server.

**Required:** No - Optional.

```javascript
{
	"wrapper" : {
		"prebidServer" : {
			"enabled" : true,
			"accountId": "123"
		}
	}
}
```

### `wrapper.prebidServer.endpoint`

**Description:** Updates the Prebid Server Endpoint. This is the URL endpoint for the auction.

**Required:** No - Optional.

```javascript
{
	"wrapper" : {
		"prebidServer" : {
			"enabled" : true,
			"accountId": "123",
            "endpoint": "https://prebid.mydomain.com/pbs/v1/openrtb2/auction"
		}
	}
}
```

### `wrapper.prebidServer.syncEndpoint`

**Description:** Updates the Prebid Server Sync Endpoint. This is the URL endpoint for user synchronization.

**Required:** No - Optional.

```javascript
{
	"wrapper" : {
		"prebidServer" : {
			"enabled" : true,
			"accountId": "123",
            "endpoint": "https://prebid.mydomain.com/pbs/v1/openrtb2/auction",
            "syncEndpoint": "https://prebid.mydomain.com/pbs/v1/cookie_sync"
		}
	}
}
```

### `wrapper.prebidServer.maxTimeout`

**Description:** Updates the Prebid Server Max Timeout. This is the maximum time allowed for the S2S auction to respond.

**Required:** No - Optional.

```javascript
{
	"wrapper" : {
		"prebidServer" : {
			"enabled" : true,
			"accountId": "123",
            "endpoint": "https://prebid.mydomain.com/pbs/v1/openrtb2/auction",
            "syncEndpoint": "https://prebid.mydomain.com/pbs/v1/cookie_sync",
            "maxTimeout": 1700
		}
	}
}
```

### `wrapper.prebidServer.bidders`

**Description:** Updates the Prebid Server Bidders. This is the list of bidders that are allowed to run on S2S.

**Required:** No - Optional.

```javascript
{
	"wrapper" : {
		"prebidServer" : {
			"enabled" : true,
			"accountId": "123",
            "endpoint": "https://prebid.mydomain.com/pbs/v1/openrtb2/auction",
            "syncEndpoint": "https://prebid.mydomain.com/pbs/v1/cookie_sync",
            "maxTimeout": 1700,
            "bidders": ["appnexus","sovrn","pubmatic","triplelift","openx"]
		}
	}
}
```

### `bidAdjustments.pubshare`

**Description:** All header bidding bids will be adjusted with this value.

**Required:** Yes - Has default value if not set.

**Default:** `1`

```javascript
{
	"bidAdjustments" : {
		"pubshare" : 0.8
	}
}
```

### `bidAdjustments.s2s`

**Description:** Header bidding bids received through Server 2 Server will be adjusted to this value.

**Required:** Yes - Has default value if not set.

**Default:** `1`

```javascript
{
	"bidAdjustments" : {
		"s2s" : 0.95
	}
}
```

### `bidAdjustments.networks`

**Description:** Adjusts bids from individual networks. Each bid from the specified network will be multiplied by the adjustment factor.

**Required:** No - Optional.

```javascript
{
	"bidAdjustments" : {
		"networks" : {
			"pubmatic" : 0.97,
			"districtm" : 0.9
		}
	}
}
```

### `lazyLoading.preViewLength`

**Description:** The distance of the ads on the page, in pixels, from the active viewport when ads will be requested.

**Required:** Yes - Has default value if not set.

**Default:** `1000`

```javascript
{
	"lazyLoading" : {
		"preViewLength" : 1500
	}
}
```

### `lazyLoading.preViewPorts`

**Description:** The distance of the ads on the page, in number of viewports, depending on the device, when ads will be requested. If set, this will overwrite `lazyLoading.preViewLength`.

**Required:** No - Optional.

```javascript
{
	"lazyLoading" : {
		"preViewPorts" : 2
	}
}
```

### `lazyLoading.scrollEventDelay`

**Description:** The time in milliseconds that the scroll event is throttled to mitigate latency.

**Required:** Yes - Has default value if not set.

**Default:** `400`

```javascript
{
	"lazyLoading" : {
		"scrollEventDelay" : 400
	}
}
```

### `targeting.refreshIteration`

**Description:** The name of the key-value used to count refreshes.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"refreshIteration" : "refresh_count"
	}
}
```

### `targeting.refreshedInventory`

**Description:** The name of the key-value used to mark if the inventory is refreshed or not.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"refreshedInventory" : "refreshed"
	}
}
```

### `targeting.refreshedAccelerateSeconds`

**Description:** If enabled, it will set a key-value representing the seconds that the refresh was accelerated with.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"refreshedAccelerateSeconds" : true
	}
}
```

### `targeting.speed`

**Description:** If `true`, it sends key-values related to speed.

**Required:** No - Optional.

**Key-Values:**

* `wrap_l`: The load time of the wrapper (relative to page navigation).
* `gpt_l`: The load time of the `googletag` library (relative to wrapper load time).
* `page_r`: The load time of the page (relative to wrapper load time).
* `waai`: The time until the auction initiated (relative to wrapper load time), tracked only for the first auction.
* `waae`: The time until the auction ended (relative to auction init).
* `wabt`: The bidders that timeout (relative to what Prebid detects as timeout).
* `wabtr`: The bidders that timeout by not sending a bid until the GAM ad request is made.
* `cndl`: Connection DownLink.
  * `0`: Unknown.
  * `0.1`: Under 1MB.
  * `1`: 1-9.99 MB.
  * `10`: 10-99.99 MB.
  * `100`: 100-999.99 MB.
  * `1000`: >= 1000 MB.
* `cnrtt`: Connection RTT.
  * `0`: Unknown.
  * `10`: <= 10ms.
  * `100`: <= 100ms.
  * `900`: <= 900ms.
  * `1000`: >= 1000ms.
* `cntp`: Connection Type. Possible values: `na`, `bluetooth`, `cellular`, `ethernet`, `none`, `wifi`, `wimax`, `other`, `unknown`.
* `cnet`: Connection Effective Type. Possible values: `na`, `slow-2g`, `2g`, `3g`, `4g`, `5g`.
* `cnsd`: Connection Save Data. Possible values: `true`, `false`.

**Default:** `true`

### `targeting.pageAdDensity`

**Description:** If `true`, it sends key-values related to Page Ad Density.

**Required:** No - Optional.

**Key-Values:**

* `padpr` (Page Ad Density PreRequest): Represents ad density before requests based on the biggest ad size available.
* `pad` (Page Ad Density): Represents ad density after ads have been rendered.

**Default:** `true`

```javascript
{
	"targeting" : {
		"pageAdDensity" : true
	}
}
```

### `targeting.utmKeyValues`

**Description:** If `true`, it sends key-values related to UTM values.

**Required:** No - Optional.

**Key-Values:**

* `utm_source`
* `utm_medium`
* `utm_campaign`
* `utm_content`

**Default:** `true`

```javascript
{
	"targeting" : {
		"utmKeyValues" : true
	}
}
```

### `targeting.uids`

**Description:** If `true`, it sends key-values related to User Identification Services/Providers.

**Required:** No - Optional.

**Key-Values:**

* `uids`: Sends the value of each User ID Service/Provider that identifies a user.
* `uids_c`: Sends the count of all User ID Services that identified a user.
* Individual key-value for each User ID Service/Provider: Sets a key with the name of the User ID Service/Provider.

**Default:** `false`

```javascript
{
	"targeting" : {
		"uids" : true
	}
}
```

### `targeting.topicsapi`

**Description:** If `true`, it sends key-values with the values from Topics API interests.

**Required:** No - Optional.

**Notes:** The `topicsFpdModule` must be added as it is not included by default anymore.

```javascript
{
	"targeting" : {
		"topicsapi" : true
	}
}
```

### `targeting.gads`

**Description:** If `true`, it sends key-values indicating whether the GAM cookie `gads` is set.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"gads" : true
	}
}
```

### `targeting.cookieEnabled`

**Description:** If `true`, it sends key-values indicating whether the browser allows third-party cookies.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"cookieEnabled" : true
	}
}
```

### `targeting.browserLangCode`

**Description:** If `true`, it sends key-values related to the user's language as set up in the browser.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"browserLangCode" : true
	}
}
```

### `targeting.referrer`

**Description:** If `true`, it sends key-values related to the referrer domain.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"referrer" : true
	}
}
```

### `targeting.domain`

**Description:** If `true`, it sends key-values related to the domain where the wrapper is loaded.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"domain" : true
	}
}
```

### `targeting.code`

**Description:** If `true`, it sends the key-value `wrapCode` related to the wrapper code.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"code" : true
	}
}
```

### `targeting.id`

**Description:** If `true`, it sends the key-value `wrapId` related to the wrapper ID.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"id" : true
	}
}
```

### `targeting.prerendering`

**Description:** If `true`, it sends the key-value `prst` related to the prerendering state of the page.

**Required:** No - Optional.

**Key-Value Definition:**

| Key    | Possible Values | Description                                     |
| ------ | --------------- | ----------------------------------------------- |
| `prst` | `no`            | The page is not prerendered.                    |
|        | `before`        | The page is prerendering but not activated yet. |
|        | `after`         | The page was prerendered and is now activated.  |

**References:**

* [Prerendering Pages in Chrome](https://developer.chrome.com/docs/web-platform/prerender-pages)
* [Document Prerendering API](https://developer.mozilla.org/en-US/docs/Web/API/Document/prerendering)
* [Prebid.js Pull Request #12763](https://github.com/prebid/Prebid.js/pull/12763)

**Default:** `false`

```javascript
{
	"targeting" : {
		"prerendering" : true
	}
}
```

### `targeting.pageNavigationType`

**Description:** If `true`, it sends the key-value `pnType` related to the page navigation type.

**Required:** No - Optional.

**Key-Value Definition:**

| Key      | Possible Values | Description                                              |
| -------- | --------------- | -------------------------------------------------------- |
| `pnType` | `reload`        | Page was reloaded/refreshed.                             |
|          | `push`          | New navigation entry (normal navigation).                |
|          | `replace`       | Current entry was replaced.                              |
|          | `traverse`      | Navigation through history (back/forward).               |
|          | `navigate`      | Normal navigation (clicking a link, typing a URL, etc.). |
|          | `back_forward`  | Navigation via browser back/forward buttons.             |
|          | `prerender`     | Page was prerendered.                                    |
|          | `reserved`      | Reserved value.                                          |
|          | `unknown`       | When navigation type cannot be determined.               |

**Default:** `false`

```javascript
{
	"targeting" : {
		"pageNavigationType" : true
	}
}
```

### `targeting.device`

**Description:** If `true`, it sends key-values related to the device detected from the browser user agent.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"device" : true
	}
}
```

### `targeting.browser`

**Description:** If `true`, it sends key-values related to the browser detected from the browser user agent.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"browser" : true
	}
}
```

### `targeting.os`

**Description:** If `true`, it sends key-values related to the operating system detected from the browser user agent.

**Required:** No - Optional.

```javascript
{
	"targeting" : {
		"os" : true
	}
}
```

### `abtests.uids`

**Description:** Enables A/B testing for User IDs. When a User Identification Service/Provider identifies a user, it splits the traffic 50/50: half the time it sends the User ID to networks, and half the time it does not. The key-values sent to GAM will be `nameOfUserID+test`, with values `true` (User ID sent to network), `false` (User ID not sent to network), or `na` (User ID not identified).

**Required:** No - Optional.

```javascript
{
	"abtests" : {
		"uids" : ["idl_env","lipb","lotamePanoramaId","id5id","33acrossId","teadsId","fabrickId"]
	}
}
```

### `refresh.gamStrategy`

**Description:** Chooses how Google Ad Manager (GAM) loads the next ad when a placement refreshes.

**Status:** Experimental — not tested in production. Prefer the default unless you are deliberately evaluating this option.

**Required:** No - Optional.

**Default:** Classic refresh behaviour (same as `"refresh"`). Omit the setting, or set `"refresh"`, to keep current behaviour.

**Valid Values:**

* `"refresh"` — Ask GAM to refresh the existing ad slot (the usual approach).
* `"redefine"` — Remove the slot and create it again for each refresh, then load a new ad into that new slot.

**In plain terms:** With `"refresh"`, the same GAM slot is reused and told to fetch another ad. With `"redefine"`, the wrapper tears that slot down and builds a fresh one, then fills it. Refresh timers, viewability rules, and refresh limits still work the same way. Refresh counts and related key-values (for example whether the inventory is refreshed, and advertiser history) are preserved across the recreate so reporting stays consistent.

**Notes:**

* Out-of-page (interstitial / overlay) placements always stay on classic refresh, even when `"redefine"` is set.
* If the page element for a slot is missing, that slot also stays on classic refresh so it is not lost.
* When `"redefine"` is on, the creative area is emptied briefly while the new slot is created. If you use `dfp.failedToFetchFallback`, consider a longer wait via `dfp.failedToFetchFallbackRedefine` so a fallback creative does not appear too early while GAM is still loading.

```javascript
{
	"refresh" : {
		"gamStrategy" : "refresh"
	}
}
```

```javascript
{
	"refresh" : {
		"gamStrategy" : "redefine"
	}
}
```

### `refresh.stopAdvertisers`

**Description:** An array of GAM advertiser/company IDs that will stop the refresh after an impression from them is displayed.

**Required:** Yes - Has default value if not set.

**Default:** `[]` (empty array)

**Notes:** Values must be numeric, not strings.

```javascript
{
	"refresh" : {
		"stopAdvertisers" : []
	}
}
```

### `refresh.pauseOutOfFocus`

**Description:** When `true`, it will not refresh until the page is in focus.

**Required:** No - Optional.

```javascript
{
	"refresh" : {
		"pauseOutOfFocus" : false
	}
}
```

### `refresh.pauseOutOfView`

**Description:** Pauses refresh when the adunit is out of view.

**Required:** No - Optional.

**Properties:**

* `threshold`: A float from `0` to `1`. It will refresh only when the ad is in the active viewport. The value represents the threshold; `0` represents one pixel, `1` represents all pixels of the element.
* `adunits`: An array of strings representing adunits that `pauseOutOfView` will apply to. It also accepts the wildcard `*` for all adunits.

```javascript
{
	"refresh" : {
		"pauseOutOfView" : {
			"threshold" : 1,
			"adunits" : ["*"]
		}
	}
}
```

```javascript
{
	"refresh" : {
		"pauseOutOfView" : {
			"threshold" : 0,
			"adunits" : ["/123/AdUnit1","/123/AdUnit2"]
		}
	}
}
```

### `refresh.maxLimit`

**Description:** The maximum number of refreshes allowed for an adunit. The refresh counter starts at `0` for the initial load and increments with each refresh.

**Notes:** Applies to timed refresh and to viewable refresh (GAM or `wrapper` viewability provider).

**Required:** No - Optional.

**Valid Values:**

* `false`: Disables this limit (no maximum refresh limit)
* `0`: No refreshes allowed (ad will not refresh)
* `1` or higher: Number of refreshes allowed before stopping

```javascript
{
	"refresh" : {
		"maxLimit" : 100
	}
}
```

### `refresh.maxEmpty`

**Description:** The maximum number of empty responses from GAM before stopping refreshes. The empty counter starts at `0` and increments each time GAM returns an empty response. Refreshes will stop when the count reaches this limit.

**Notes:** This limit is evaluated when scheduling refreshes for timed refresh (`refreshTimed`) and for viewable refresh when `refresh.viewabilityProvider` is `wrapper`. (Counters are still driven by GAM slot lifecycle events.)

**Required:** No - Optional.

**Valid Values:**

* `false` or `0`: Disables this limit (refreshes continue regardless of empty responses)
* `1` or higher: Number of empty responses tolerated before stopping refreshes
* Setting to `1` means "stop after the first empty response"

```javascript
{
	"refresh" : {
		"maxEmpty" : 100
	}
}
```

### `refresh.maxConsecutiveEmpty`

**Description:** The maximum number of consecutive empty responses from GAM before stopping refreshes. The consecutive empty counter starts at `0` and increments each time GAM returns an empty response, but resets to `0` when a non-empty response is received. Refreshes will stop when consecutive empties reach this limit.

**Notes:** Same scope as `refresh.maxEmpty`: enforced for timed refresh and for viewable refresh when `refresh.viewabilityProvider` is `wrapper`.

**Required:** No - Optional.

**Valid Values:**

* `false` or `0`: Disables this limit (refreshes continue regardless of consecutive empty responses)
* `1` or higher: Number of consecutive empty responses tolerated before stopping refreshes
* Setting to `1` means "stop after the first empty response"

```javascript
{
	"refresh" : {
		"maxConsecutiveEmpty" : 100
	}
}
```

### `refresh.forceRefreshRateForAdvertiser`

**Description:** Changes the refresh rate for a specific GAM advertiser/company. Takes an array of objects with `advertiserId` and `refreshRate` properties.

**Required:** Yes - Has default value if not set.

**Default:** `[]` (empty array)

```javascript
{
	"refresh" : {
		"forceRefreshRateForAdvertiser" : [
			{"advertiserId": 4721606053, "refreshRate":30},
			{"advertiserId": 4607025053, "refreshRate":30},
			{"advertiserId": 4607025017, "refreshRate":30},
			{"advertiserId": 4805864332, "refreshRate":30},
			{"advertiserId": 4805864332, "refreshRate":30}
		]
	}
}
```

### `refresh.accelerate`

**Description:** Accelerates refresh by reducing the refresh time by a specific number of seconds if the estimated CPM is higher than the specified value. Takes an array of objects with `estCPM` and `seconds` properties.

**Required:** No - Optional.

```javascript
{
	"refresh" : {
		"accelerate" : [
		      {"estCPM": 1, "seconds": 3},
		      {"estCPM": 1.5, "seconds": 5},
		      {"estCPM": 2, "seconds": 10},
		      {"estCPM": 2.5, "seconds": 15}
		]
	}
}
```

### `refresh.continueOnEmpty`

**Description:** Applies only to viewable refresh. If GAM returns an empty response, and viewable refresh is enabled, refresh will not stop. A one-time refresh is scheduled with the same refresh rate as the viewable one, effectively transforming the next viewable refresh into a timed refresh.

**Required:** No - Optional.

**Notes:**

* `refresh.maxLimit`, `refresh.maxEmpty`, `refresh.maxConsecutiveEmpty` apply. Refreshes will be counted and will stop if any limit is reached.
* `refresh.accelerate` applies. The refresh is accelerated if there is a bid according to settings.
* `refresh.pauseOutOfFocus` applies; if enabled, it will not refresh while the tab is out of focus.
* `refresh.stopAdvertisers` and `refresh.forceRefreshRateForAdvertiser` do not apply if the response is empty as there is no advertiser.

```javascript
{
	"refresh" : {
		"continueOnEmpty" : true
	}
}
```

### `refresh.viewabilityProvider`

**Description:** Defines the viewability provider for refresh.

**Required:** No - Optional.

**Possible Values:**

* `gam`: Uses the GAM viewability event (`impressionViewable`) to schedule the next viewable refresh.
* `wrapper`: Uses the wrapper’s internal viewability detection (IntersectionObserver: at least 50% of the slot element in view for one second) to schedule the next viewable refresh.

**Notes (wrapper provider):** When `wrapper` is selected, scheduling the next viewable refresh applies the same caps as other refresh paths: `refresh.maxLimit`, `refresh.maxEmpty`, and `refresh.maxConsecutiveEmpty`, plus `refresh.accelerate`, `refresh.stopAdvertisers`, and `refresh.forceRefreshRateForAdvertiser` when response/advertiser information is available from the slot.

```javascript
{
	"refresh" : {
		"viewabilityProvider" : "wrapper"
	}
}
```

### `deviceDetection`

**Description:** The method of detecting the size of the site.

**Required:** Yes - Has default value if not set.

**Default:** `"window"`

**Possible Values:**

1. `window`: Detects the size of the window/tab (if the window is resized or the tag is inside an iframe and cannot access the top window, it will detect that size).
2. `screen`: Detects the screen size, not taking into account the actual window/tab.

```javascript
{
	"deviceDetection" : "window"
}
```

### `dfp.collapseEmptyDivs`

**Description:** If GAM has an empty response, collapses the size of the divs.

**Required:** No - Optional.

```javascript
{
	"dfp" : {
		"collapseEmptyDivs" : false
	}
}
```

### `dfp.appendNetworkCodeToGPTTag`

**Description:** Appends `?network-code=` to the GPT script URL (`gpt.js`) so Funding Choices and related Google privacy messages load via a specific GAM network. Set to `true` to use `dfpAccount`, or pass a string with the network code to use instead. When `false` or omitted, the GPT tag is loaded without a network-code parameter (default GPT behaviour).

**Required:** No - Optional.

**Default:** `undefined` (do not append).

```javascript
{
	"dfp" : {
		"appendNetworkCodeToGPTTag" : true
	}
}
```

```javascript
{
	"dfp" : {
		"appendNetworkCodeToGPTTag" : "23353745321"
	}
}
```

### `dfp.emptyCreativeFallback`

**Description:** If GAM has an empty response but there is a header bidding bid, delivers the ad without GAM.

**Required:** No - Optional.

```javascript
{
	"dfp" : {
		"emptyCreativeFallback" : true
	}
}
```

### `dfp.failedToFetchFallback`

**Description:** After a specific amount of time, adunits are checked if GAM displayed an ad. If not and there are Header Bidding bids available, delivers the ad without GAM.

**Required:** No - Optional.

```javascript
{
	"dfp" : {
		"failedToFetchFallback" : 3000
	}
}
```

### `dfp.failedToFetchFallbackRedefine`

**Description:** Extra wait (in milliseconds) used with `refresh.gamStrategy: "redefine"` when `dfp.failedToFetchFallback` is enabled. Redefine clears the slot sooner than classic refresh, so a longer check helps avoid showing a fallback while GAM is still responding. The effective wait is the larger of this value and `dfp.failedToFetchFallback`.

**Status:** Experimental — intended for use with `refresh.gamStrategy: "redefine"`, which is not tested in production.

**Required:** No - Optional.

**Default:** `5000` (only applied when redefine strategy is active)

```javascript
{
	"dfp" : {
		"failedToFetchFallback" : 3000,
		"failedToFetchFallbackRedefine" : 5000
	}
}
```

### `dfp.houseFallback`

**Description:** Specifies creatives to serve in case there is no demand from GAM or Prebid. Requires `dfp.emptyCreativeFallback` or `dfp.failedToFetchFallback` to be enabled. The value is an object where keys are sizes and values are the HTML creative. It will deliver the creative corresponding to the size of the adunit. If the adunit has multiple sizes and multiple creatives are available, one will be randomly selected.

**Required:** No - Optional.

```javascript
{
	"dfp" : {
		"emptyCreativeFallback": true,
        "failedToFetchFallback": 3000,
		"houseFallback":{
			"300x250" : "<!-- this is a house 300x250 -->",
			"336x280" : "<!-- this is a house 336x280 -->",
			"728x90" : "<!-- this is a house 728x90 -->",
			"468x60" : "<!-- this is a house 468x60 -->",
			"970x90" : "<!-- this is a house 970x90 -->",
			"970x250" : "<!-- this is a house 970x250 -->",
			"300x600" : "<!-- this is a house 300x600 -->",
			"320x50" : "<!-- this is a house 320x50 -->",
			"320x100" : "<!-- this is a house 320x100 -->"
		}
	}
}
```

### `dfp.forceSafeFramesUnderFloor`

**Description:** Enables GAM's SafeFrames if the Header Bidding bid is under the floor.

**Required:** No - Optional.

**Notes:** If enabled, it will disable Amazon and bidders that are not compatible with Safe Frames.

```javascript
{
	"dfp" : {
		"forceSafeFramesUnderFloor" : 2.1
	}
}
```

### `dfp.forceSafeFramesForAdunits`

**Description:** Enables GAM's SafeFrames on specific adunits. The full adunit path must be specified.

**Required:** No - Optional.

**Notes:** If enabled, it will disable Amazon for the adunits it is enabled for. It will also disable bidders that are not compatible with Safe Frames.

```javascript
{
	"dfp" : {
		"forceSafeFramesForAdunits" : ["/123/AdUnit1","/123/AdUnit2"]
	}
}
```

### `dfp.forceSafeFrames`

**Description:** If `true`, it will enable GAM's SafeFrames.

**Required:** No - Optional.

**Notes:** If enabled, it will disable Amazon and bidders that are not compatible with Safe Frames.

```javascript
{
	"dfp" : {
		"forceSafeFrames" : true
	}
}
```

### `dfp.flexibleSafeFramesSignal`

**Description:** **\[NEW INNOVATIVE FEATURE]** An industry-first solution for granular SafeFrame control at the impression level. Instead of forcing SafeFrames on all inventory (which limits bidder participation and monetization), Flexible Safe Frames Signal provides intelligent, bid-level control by setting the `hb_sframe` key-value based on winning bid characteristics. This revolutionary approach allows publishers to:

**Required:** No - Optional.

* **Maximize Revenue**: Only apply SafeFrames when needed, keeping high-performing bidders active on most inventory
* **Surgical Precision**: Target specific bidders, advertiser domains, categories, or ad units
* **Risk Management**: Protect sensitive inventory or high-value pages with granular SafeFrame rules
* **Enhanced Reporting**: Track which impressions are served within SafeFrames via the `hb_sframe` key-value
* **Smart Optimization**: Different SafeFrame strategies for different inventory segments

When enabled, the module sets the `hb_sframe` key-value for every impression. All conditions are evaluated with OR logic - if ANY condition matches, the signal is set to `1`, otherwise `0`. When disabled, no key-value is set.

**Parameters:**

1. **`enabled`** (boolean, required): Set to `true` to activate the module and start setting the `hb_sframe` key-value. When `false` or not set, the module is inactive and no key-value is set.
2. **`bidders`**: Array of bidder codes. Enables SafeFrames for specific bidders (e.g., protect against specific SSPs).
3. **`adomains`**: Array of advertiser domains. Enables SafeFrames for specific advertisers (e.g., competitor exclusion or brand safety).
4. **`acats`**: Array of IAB category codes. Enables SafeFrames for specific ad categories (e.g., sensitive verticals).
5. **`adunits`**: Array of GAM ad unit paths. Enables SafeFrames for specific inventory locations (e.g., homepage only).

**Output:** When enabled, sets the `hb_sframe` key-value to `1` (SafeFrames recommended) or `0` (standard rendering) for every impression. When disabled, no key-value is set.

**Use Cases:**

* **Brand Safety**: "Enable SafeFrames for specific advertiser domains or sensitive categories"
* **Selective Enforcement**: "Enable SafeFrames only on homepage and article pages, not in-feed inventory"
* **Bidder Management**: "Enable SafeFrames for specific bidders with compliance concerns"
* **Category Control**: "Enable SafeFrames for sensitive content categories requiring additional protection"

**Default:** Not configured (feature inactive)

**Code Examples:**

```javascript
// Example 1: Enable SafeFrames for specific bidders
{
	"dfp" : {
		"flexibleSafeFramesSignal" : {
			"enabled": true,
			"bidders": ["rubicon", "appnexus", "pubmatic"]
		}
	}
}
```

```javascript
// Example 2: Enable SafeFrames for specific advertiser domains
{
	"dfp" : {
		"flexibleSafeFramesSignal" : {
			"enabled": true,
			"adomains": ["competitor.com", "sensitive-advertiser.com"]
		}
	}
}
```

```javascript
// Example 3: Enable SafeFrames for sensitive categories
{
	"dfp" : {
		"flexibleSafeFramesSignal" : {
			"enabled": true,
			"acats": ["IAB7-39", "IAB8-18", "IAB23"]
		}
	}
}
```

```javascript
// Example 4: Enable SafeFrames for specific ad units
{
	"dfp" : {
		"flexibleSafeFramesSignal" : {
			"enabled": true,
			"adunits": ["/21833886396/homepage/leaderboard", "/21833886396/article/sidebar"]
		}
	}
}
```

```javascript
// Example 5: Combined conditions (any match triggers SafeFrames)
{
	"dfp" : {
		"flexibleSafeFramesSignal" : {
			"enabled": true,
			"bidders": ["rubicon"],
			"adomains": ["competitor.com"],
			"acats": ["IAB7-39"],
			"adunits": ["/21833886396/homepage/leaderboard"]
		}
	}
}
```

**Notes:**

* Set `enabled: true` to activate the module; when disabled or not set, no key-value is set
* All conditions use OR logic - if ANY condition matches, `hb_sframe` is set to `1`
* The key-value is set at the slot level for each ad impression
* Can be used with GAM creative templates or line item targeting for conditional SafeFrame rendering
* Compatible with all header bidding demand sources and GAM features
* Does not automatically disable bidders (unlike global SafeFrame settings)

### `prebid`

**Description:** Prebid configuration.

**Required:** No - Optional.

**Reference:** [Prebid documentation setConfig](https://docs.prebid.org/dev-docs/publisher-api-reference/setConfig.html)

```javascript
{
	"prebid" : {
	    "priceGranularity" : {
	        "buckets": [
	                    {
                            "precision": 2,
                            "max": 20,
                            "increment": 0.01
	                    }
	                ]
	    },
	    "schain": {
	    	"validation": "strict",
	    	"config": {
				"ver":"1.0",
				"complete": 1,
				"nodes": [{ "asi":"network.com", "sid":"abc123", "hp":1 }]
			}
		}
	}
}
```

### `prebid.bidCaching`

**Description:** Stores bids to be reused in future auctions. If `false`, it is disabled.

**Required:** No - Optional.

**Properties:**

* `maxLength`: The maximum size of the bid in bytes, to prevent bids with very large creatives.
* `floor`: Stores only bids above this CPM.

```javascript
{
	"prebid" : {
		"bidCaching" : {
	    	"maxLength": 100000,
	    	"floor": 0.10
	    }
	}
}
```

### `prebid.floors` dynamic schema fields from `ortb2` (wrapper extension)

**Description:** When the Price Floors module is enabled and `prebid.floors.data.schema.fields` includes one or more supported dynamic fields Values are resolved from current `ortb2` and matched case-insensitively.

If a value is not available, the wrapper returns `*` so Price Floors can match wildcard/default rules.

**Required:** No - Optional (works only when Price Floors is configured).

**Works only if:**

* Price Floors module is enabled and has `prebid.floors.data.schema.fields`.
* For `country`, `region`, `city`, `os`, `browser`: those values exist in `ortb2` (typically via `wrapper.firstPartyData: true`, or another source that sets `ortb2` before auction).
* For `eids`: user IDs are available in `ortb2.user.ext.eids` (typically when `userSync.userIds` is configured and IDs are present).

**Supported dynamic schema fields:**

* `country` -> `ortb2.device.geo.country` (alpha-2 or alpha-3; normalized to lowercase alpha-3 for matching)
* `region` -> `ortb2.device.geo.region`
* `city` -> `ortb2.device.geo.city`
* `os` -> `ortb2.device.sua.platform.brand` (operating system / platform brand)
* `browser` -> primary browser from `ortb2.device.sua.browsers[0].brand`
* `eids` -> `ortb2.user.ext.eids[].source` (see matching below)

**Normalization behavior:**

* All extracted scalar values are lowercased.
* `country` rule keys accept alpha-2 or alpha-3 and are normalized to lowercase alpha-3.
* `eids` sources are normalized to a sorted, deduplicated list; at match time the wrapper returns a single source token for Price Floors exact matching.
* Rule matching stays case-insensitive.

**`eids` matching:** A floor rule matches when **any** source listed in the rule’s `eids` segment (comma-separated) is present in the auction’s `ortb2.user.ext.eids` list. Example: rule `pubcid.org` matches an auction with eids `id5-sync.com,pubcid.org`.

> **Warning: Rule order matters for `eids` when multiple rules could match.** When a user has more than one EID source and separate floor rules exist for each source, the **first matching rule in the `values` object wins** — not the highest floor value. Place higher-priority rules earlier in the `values` map to control which floor is applied.
>
> **Example:** A user has eids `["id5-sync.com", "pubcid.org"]` and the config is:
>
> ```json
> "values": {
>   "usa|pubcid.org":   19,
>   "usa|id5-sync.com": 20
> }
> ```
>
> The floor applied will be **19** (`usa|pubcid.org`) because that rule appears first, even though `usa|id5-sync.com` has a higher value. To ensure the higher floor is applied, place the higher-valued rule first:
>
> ```json
> "values": {
>   "usa|id5-sync.com": 20,
>   "usa|pubcid.org":   19
> }
> ```

#### Example: single dynamic schema field (`country`)

```javascript
{
  "wrapper": {
    "firstPartyData": true
  },
  "prebid": {
    "floors": {
      "data": {
        "currency": "USD",
        "schema": {
          "fields": ["country"]
        },
        "values": {
          "rou": 1.0,
          "deu": 0.8
        },
        "default": 0.1
      }
    }
  }
}
```

#### Example: multiple dynamic schema fields

```javascript
{
  "prebid": {
    "floors": {
      "data": {
        "currency": "USD",
        "schema": {
          "fields": ["country", "os"]
        },
        "values": {
          "rou|windows": 1.2,
          "rou|android": 0.9,
          "*|*": 0.1
        }
      }
    }
  }
}
```

#### Example: combine Prebid native + wrapper dynamic schema fields

```javascript
{
  "prebid": {
    "floors": {
      "data": {
        "currency": "USD",
        "schema": {
          "fields": ["mediaType", "size", "country"]
        },
        "values": {
          "banner|300x250|rou": 1.5,
          "banner|*|*": 0.4,
          "*|*|*": 0.1
        }
      }
    }
  }
}
```

### `userSync.triggerAction`

**Description:** Defines the user interaction that will trigger a user sync.

**Required:** No - Optional.

**Possible Values:** `scroll`, `click`, `idle`, `timed`.

```javascript
{
  "userSync": {
    "triggerAction": "click"
  }
}
```

### `userSync.triggerDelay`

**Description:** Delay (in milliseconds) after the `triggerAction` occurs before initiating user sync.

**Required:** No - Optional.

```javascript
{
  "userSync": {
    "triggerDelay": 2000
  }
}
```

### `prebidBidderSpecific`

**Description:** Prebid configuration for specific bidders. Can take an array for multiple bidders or an object for a single one.

**Required:** No - Optional.

**Reference:** [Prebid documentation setBidderConfig](https://docs.prebid.org/dev-docs/publisher-api-reference/setBidderConfig.html)

```javascript
{
    "prebidBidderSpecific" : [
    	{
        	"bidders" : ["rubicon","pubmatic"],
        	"config" : {
    		    "schain": {
    		    	"validation": "strict",
    		    	"config": {
    					"ver":"1.0",
    					"complete": 1,
    					"nodes": [{ "asi":"network.com", "sid":"abc123", "hp":1 }]
    				}
    			}
        	}
        },
    	{
        	"bidders" : ["gourmetads"],
        	"config" : {
    		    "schain": {
    		    	"validation": "strict",
    		    	"config": {
    					"ver":"1.0",
    					"complete": 1,
    					"nodes": [{ "asi":"othernetwork.com", "sid":"cdf345", "hp":1 }]
    				}
    			}
        	}
        }
    ]
}
```

### `amazon`

**Description:** Configures the Amazon/A9 wrapper.

**Required:** No - Optional.

**Properties:**

* `enabled`: Enables/disables the wrapper.
* `pubID`: The Amazon ID, from the AM or Dashboard.
* `adServer`: The ad server.

```javascript
{
	"amazon" : {
    	"enabled" : true,
	    "pubID": "123",
	    "adServer": "googletag"
	}
}
```

### `amazon.declareRefresh`

**Description:** Optional parameter for Amazon/A9 Config that will send the `adRefresh` parameter as configuration.

**Required:** No - Optional.

**Reference:** [Amazon/A9 Config documentation](https://ams.amazon.com/webpublisher/uam/docs/reference/api-reference.html#adrefresh)

**Possible Values:**

* `true`: Sends `adRefresh` to `0` for initial requests and `1` for refresh requests.
* `false`: Does not send `adRefresh` at all.

```javascript
{
	"amazon" : {
    	"enabled" : true,
	    "pubID": "123",
	    "adServer": "googletag",
	    "declareRefresh" : true
	}
}
```

### `amazon.schain`

**Description:** Optional parameter for Amazon/A9 Config that will send the `schain` parameter as configuration.

**Required:** No - Optional.

**Reference:** [Schain Object](https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/supplychainobject.md#object-schain)

**Notes:** The object passed will be assigned to the `schain` property of the Amazon configuration.

**Code Examples:**

```javascript
{
	"amazon" : {
    	"enabled" : true,
	    "pubID": "123",
	    "adServer": "googletag",
	    "schain" : {
           "ver":"1.0",
           "complete": 1,
           "nodes": [{ "asi":"example.com", "sid":"1234", "hp":1 }]
        }
	}
}
```

### `amazon.timeout`

**Description:** Sets a custom timeout for Amazon/A9 bid requests in milliseconds. When configured, Amazon will use this timeout value independently from the Prebid/wrapper timeout. This allows you to optimize Amazon's bidding window separately from other header bidding partners.

**Required:** No - Optional.

**How It Works:**

* If set to a valid number (greater than 0), Amazon will use this custom timeout for bid requests
* If set to `false`, `0`, or not included, Amazon will use the default Prebid/wrapper timeout
* The timeout applies to both the Amazon `fetchBids` call and the wrapper's internal fallback mechanism
* When a custom timeout is set, a log message will indicate that Amazon is using a custom timeout value

**Use Cases:**

* Give Amazon more time to respond when they historically return slower but valuable bids
* Reduce Amazon's timeout when you need faster page loads and Amazon responds quickly
* Test different timeout strategies for Amazon independently from other bidders

**Valid Values:**

* `false`: Use default Prebid timeout (default behavior)
* `0`: Use default Prebid timeout (same as false)
* Any positive number: Custom timeout in milliseconds (e.g., `1500`, `2500`)

**Default:** `false` (uses Prebid/wrapper timeout)

**Code Examples:**

```javascript
// Example 1: Amazon uses custom 1500ms timeout (Prebid uses default 2000ms)
{
	"wrapper": {
		"timeout": 2000
	},
	"amazon" : {
    	"enabled" : true,
	    "pubID": "123",
	    "adServer": "googletag",
	    "timeout": 1500
	}
}
```

```javascript
// Example 2: Amazon uses default Prebid timeout (2000ms)
{
	"wrapper": {
		"timeout": 2000
	},
	"amazon" : {
    	"enabled" : true,
	    "pubID": "123",
	    "adServer": "googletag",
	    "timeout": false
	}
}
```

```javascript
// Example 3: Give Amazon extra time (2500ms) while other bidders use 2000ms
{
	"wrapper": {
		"timeout": 2000
	},
	"amazon" : {
    	"enabled" : true,
	    "pubID": "123",
	    "adServer": "googletag",
	    "timeout": 2500,
	    "declareRefresh": true
	}
}
```

**Notes:**

* Amazon's timeout is independent from Prebid's timeout
* If Amazon times out, the auction will continue and ads will render normally
* The wrapper includes a safety mechanism to ensure ads render even if Amazon fails or times out
* When `amazon.timeout` is set, you'll see a log message: `__ A9/Amazon : Using custom timeout: [value]`

### `forceReWrittingPBJS`

**Description:** If `true`, it clones the Prebid global variable as `pbjs` to avoid conflicts with GAM creatives. When there are multiple instances of Prebid on the page, this must be disabled.

**Required:** No - Optional.

```javascript
{
	"forceReWrittingPBJS" : true
}
```

### `debug`

**Description:** Sets the wrapper's built-in logging level for the browser console. Turning this on in the config makes the wrapper log its activity for every visitor, which is useful in staging but should normally be left off in production (use the per-visitor URL flags in [Troubleshooting](/troubleshooting) instead). Setting it to `'details'` enables verbose, opt-in logging.

**Required:** No - Optional.

**Possible Values:**

* `true`: Standard debug logging.
* `'details'`: Verbose logging (equivalent to the `[globalVar]_debug=DETAILS` URL flag).
* `false` or omitted: No debug logging (default).

```javascript
{
	"debug" : "details"
}
```

## adunits.json

**Description:** This file contains settings individually for each adunit of the wrapper.

**Notes:**

* Each entry is an adunit.
* Cannot have multiple adunits mapped to the same div.
* You can have multiple divs mapped to the same adunit.

Each adunit has the following properties:

### `adunit`

**Description:** The GAM adunit path.

```javascript
{
	"adunit" : "/123/abc"
}
```

### `device`

**Description:** An array of devices (as defined in `deviceDetection.json`) where the adunit will display.

```javascript
{
	 "device": ["bigDesktop","desktop","tablet"]
}
```

### `mediaTypes`

**Description:** MediaTypes in the format accepted by Prebid.

**Reference:** [Prebid documentation AdUnit Reference](https://docs.prebid.org/dev-docs/adunit-reference.html#adunitmediatypes)

```javascript
{
	"mediaTypes" : {"banner" : {"sizes" : [[728,90],[970,90],[970,250],[728,250]] }}
}
```

### `conditionalMediaTypes`

**Description:** MediaTypes for each device type (as defined in `deviceDetection.json`). It will overwrite the default MediaTypes if the device is detected.

```javascript
{
	"conditionalMediaTypes" : {
        "bigDesktop":       {"banner" : {"sizes" : [[728,90],[970,90],[970,250],[728,250],[1200,280]] }},
        "desktop" :         {"banner" : {"sizes" : [[728,90],[970,90],[970,250],[728,250]] }},
        "tablet" :          {"banner" : {"sizes" : [[728,90],[728,250]] }},
        "mobile" :          {"banner" : {"sizes" : [[1,1]] }}
    }
}
```

### `additionalNonHBSizes`

**Description:** Sizes that are added to the GAM request, but not the header bidding requests.

```javascript
{
	"additionalNonHBSizes" : ["fluid"]
}
```

### `conditionalNonHBSizes`

**Description:** Additional sizes for each device type (as defined in `deviceDetection.json`). It will overwrite the default `additionalNonHBSizes` if the device is detected.

```javascript
{
	"conditionalNonHBSizes" : {
	        "bigDesktop":       ["fluid"],
	        "desktop" :         ["fluid"],
	        "tablet" :          ["fluid"],
	        "mobile" :          [[1,1]]
	    }
}
```

### `forceGAMSizes`

**Description:** When set, the sizes sent to GAM for this ad unit are replaced entirely by this array (instead of banner sizes plus `additionalNonHBSizes`). Use when you need GAM to request specific sizes regardless of HB sizes. Same format as sizes: array of `[width, height]` pairs or `"fluid"`.

```javascript
{
	"forceGAMSizes" : [[300,250],[300,600]]
}
```

### `conditionalForceGAMSizes`

**Description:** Force GAM sizes per device type (as defined in `deviceDetection.json`). Overwrites the default `forceGAMSizes` when the device is detected. Each key is a device label; value is an array of sizes.

```javascript
{
	"conditionalForceGAMSizes" : {
	        "bigDesktop": [[970,250],[728,90]],
	        "desktop" :   [[728,90]],
	        "tablet" :    [[300,250]],
	        "mobile" :    [[320,50],[300,250]]
	    }
}
```

### `outofpage`

**Description:** If `true`, defines the adunit as Out Of Page.

**Default:** `false`

```javascript
{
	"outofpage" : true
}
```

### `targeting`

**Description:** Key-value name combination to send as targeting to GAM. Takes an object where the key of the object is the name of the key-value. The values can be a string or an array of strings.

```javascript
{
	"targeting" : 	{
			"pos" : "top",
			"age" : "13",
			"gender" : "m"
    }
}
```

### `lazyLoaded`

**Description:** If `true`, enables lazy loading for the adunit.

**Default:** `false`

```javascript
{
	"lazyLoaded" : true
}
```

### `richMediaFormat`

**Description:** Enables a rich media format for the adunit. Takes an object with `type` and `options` properties.

**Default:** `-`

```javascript
{
	"richMediaFormat": {"type" : "adhesion" , "options" : {"closeButton":"true"}}
}
```

### `refreshTimed`

**Description:** The time in seconds after which the adunit will be automatically refreshed. Set to `0` to disable timed refresh.

**Default:** `0`

```javascript
{
	"refreshTimed" : "30"
}
```

### `refreshViewable`

**Description:** The time in seconds after which the adunit will be refreshed once it becomes viewable. Set to `0` to disable viewable refresh.

**Default:** `0`

```javascript
{
	"refreshViewable" : "30"
}
```

### `css`

**Description:** CSS styles to apply to the div.

**Default:** `-`

```javascript
{
	"css" : "padding: 2px; margin: 1px;"
}
```

### `bids`

**Description:** An array of Prebid bidder configurations for the adunit. Each bidder object contains the bidder name and its parameters.

**Reference:** Full list of Prebid bidders and parameters can be found [here](https://docs.prebid.org/dev-docs/bidders.html).

**Default:** `[]`

```javascript
{
	"bids": [
		{"bidder": "onetag",	"params": { "pubId": "abc"}},
		{"bidder": "amx", 	"params": {"tagId": "dfg"}},
		{"bidder": "connectad", "params": {"siteId": 123,"networkId": 123}}
        ]
}
```

### `bids` filters:

**Description:** Uses the specific bid entry only if the condition is satisfied; otherwise, the bid will be ignored.

#### `size` filter

**Description:** Uses the specific bid if the size set in the filter matches one of the requested sizes.

**Value:** An array of width and height: `[width,height]`.

```javascript
{
	"bids": [
		{"bidder": "amx", 		"params": { "tagId": "tag-for-all-size"}},
		{"bidder": "amx", 		"params": { "tagId": "tag-for-728x90"}, "size":[728,90]},
		{"bidder": "amx", 		"params": { "tagId": "tag-for-300x250"}, "size":[300,250]}
        ]
}
```

#### `device` filter

**Description:** Uses the specific bid if the device set in the filter matches the detected device.

**Value:** An array of values from the devices listed in the `deviceDetection.json` file (e.g., `["desktop","tablet","mobile"]`).

```javascript
{
	"bids": [
		{"bidder": "amx", 		"params": { "tagId": "tag-for-all-device"}},
		{"bidder": "amx", 		"params": { "tagId": "tag-for-desktop"}, "device":["desktop"]},
		{"bidder": "amx", 		"params": { "tagId": "tag-for-mobile"}, "device":["mobile"]}
        ]
}
```

#### `testParameter` filter

**Description:** Uses the specific bid only if the value of `testParameter` is set to `true` in the URL query string. It is used to create test pages.

**Example:** If the value is set to `testBidder`, for the bid to be used, the URL where the wrapper is called must have `testBidder=true` (e.g., `https://example.com?testBidder=true`).

```javascript
{
	"bids": [
		{"bidder": "amx", 		"params": { "tagId": "generic-tag"}},
		{"bidder": "amx", 		"params": { "tagId": "test-tag"}, "testParameter":"testBidder"}
        ]
}
```

## deviceDetection.json

**Description:** This file defines the types of devices that will be used in `adunits.json`. The condition is based on the screen or window size, depending on how it is configured in `config.json` at `deviceDetection`.

**Properties (for each device entry):**

1. `name`: The name of the device.
2. `condition`: A condition that needs to be respected for that device to be detected.

**Notes:**

* Conditions with any of the `<`, `=`, `>` operators are accepted.
* Can use macro `{SCREENWIDTH}` for the size of the window/screen.
* It must cover the full width of the screen possibilities from `0` to infinite.
* The devices must not overlap.

**Default:**

```javascript
[
	{"name" : "desktop", 	"condition" : "{SCREENWIDTH} >= 1024"},
	{"name" : "tablet", 	"condition" : "{SCREENWIDTH} < 1024 && {SCREENWIDTH} >= 768"},
	{"name" : "mobile", 	"condition" : "{SCREENWIDTH} < 768"}
]
```

## modules.json

**Description:** This file contains all modules used by Prebid. Each network will have one module. The generic syntax is `biddernameBidAdapter`. There are some exceptions.

**Notes:**

* `indexExchange` module is named `ixBidAdapter`.
* Bidders using an alias will use the module of the parent bidder (e.g., `districtm`, `gourmetads` will use `appnexusBidAdapter`).

```javascript
[
    "ixBidAdapter",
    "aolBidAdapter",
    "gumgumBidAdapter",
    "openxBidAdapter",
    "yieldmoBidAdapter",
    "pubmaticBidAdapter",
    "33acrossBidAdapter",
    "conversantBidAdapter",
    "sharethroughBidAdapter",
    "rhythmoneBidAdapter",
    "onetagBidAdapter",
    "connectadBidAdapter"
]
```


# Customization

This section details how to customize the Header Bidding wrapper using custom scripts and modules, for Prebid 10 and later.

**In plain terms:** beyond the settings in [Configuration](/configuration), you can add your own JavaScript that becomes part of the wrapper build. This is for developers who need behaviour that settings alone can't express. If you're not writing code, you can skip this page.

**Two ways to reach the wrapper — and when to use each:**

* **From a custom script built into the wrapper** (this page): read the global variable name from the config, since the script runs inside the wrapper's own environment. That's the `var pbjs = window[config.globalVar]` pattern shown below.
* **From a snippet on the publisher's page** (see [Public API](/public-api)): just use the global variable directly by name — `pbjs` by default, or whatever your site sets in `config.globalVar`.

Both approaches talk to the same object; they only differ in how they get a reference to it. Neither uses the old `$$PREBID_GLOBAL$$` macro, which was removed in Prebid 10.

Overview

* Write modular scripts using the `custom_[name].js` convention
* Use the configured wrapper global from `config.json` instead of the deprecated `$$PREBID_GLOBAL$$` macro
* Prefer queueing code that interacts with the wrapper API

**CRITICAL:** From [7.22.0](/release-notes), a throw while a `custom_*.js` file is loading no longer takes down the wrapper — but **that custom script is skipped**. Always wrap wrapper API calls (`getUserInfo`, `getConfig`, `setConfig`, `aliasBidder`, `onEvent`, and similar) in `pbjsInstance.cmd.push(function() { ... })`. Do not call them at the top of the file. Failed scripts log `[wrapper] custom script failed: <filename>` in the console.

## Custom Script Files

Custom script/modules files can be loaded and concatenated to the core code. For the file to be parsed it needs to have the name with following syntax: `custom_[filename].js`

e.g.: `custom_interstitial.js`

It will always start with `custom_` and the code needs to be written in javascript.

Any valid javascript is allowed.

Can import any module.

Must reference the Prebid instance via the wrapper configuration instead of the `$$PREBID_GLOBAL$$` macro (removed in Prebid 10).

### Accessing the Prebid Global (Prebid 10+)

Custom scripts run inside the wrapper environment. To access the Prebid instance in a way that is compatible with Prebid 10 and later, read the wrapper configuration and create a local reference:

```javascript
var config = require('./config.json');
var pbjsInstance = window[config.globalVar] || {};
pbjsInstance.cmd = pbjsInstance.cmd || [];
```

You can then safely queue commands on `pbjsInstance.cmd`, for example to define an alias:

```javascript
var config = require('./config.json');
var pbjsInstance = window[config.globalVar] || {};
pbjsInstance.cmd = pbjsInstance.cmd || [];

pbjsInstance.cmd.push(function() {
    pbjsInstance.aliasBidder('improvedigital', 'weborama');
});
```

### Executing Code After Page Load

Import `docReady` from `_utils.js` to run code after the DOM is ready. It is not attached to `window`.

```javascript
import { docReady } from '../_utils.js';

docReady(function() {
    // DOM is ready
});
```

### Including Source Files

You can import modules from the `src` directory into your custom scripts. However, because of the build process, the relative path to these files will be one level deeper than it appears in the source tree. For example, to import `utils.js` from the `src` folder, you would use `../utils.js`.

### Example

Here is an example of a custom script that uses `docReady` from `_utils.js`, an import from the `src` directory, and the wrapper configuration to access the Prebid instance:

```javascript
import { logMessage, logError } from '
```


# Public API

This section documents the public API exposed by the wrapper, grouped into Data Attributes, Functions, and Events.

**In plain terms:** the "API" is the set of things you're allowed to use from your own page — HTML attributes you add to ad containers, JavaScript commands you can call (like "refresh all ads"), and events you can listen for (like "this ad became viewable"). You don't need any of this for the wrapper to work; it's here for when you want extra control.

**About `pbjs` in the examples:** `pbjs` is the wrapper's global control object — the handle your code uses to talk to the wrapper. Its name is set per site by the `globalVar` setting in `config.json` (see [Configuration](/configuration#globalvar)). The examples below use `pbjs` because that's the default; **if your site uses a different `globalVar`, substitute that name.**

**Why commands are wrapped in `pbjs.cmd.push(...)`:** the wrapper loads asynchronously, so it may not be ready the instant your code runs. Instead of calling it directly, you add your instruction to a command queue (`pbjs.cmd`), and the wrapper runs it as soon as it's ready. The `(pbjs = pbjs || { cmd: [] })` part simply makes sure the queue exists before you push to it, even if the wrapper hasn't loaded yet.

> **Note for those upgrading from older docs:** earlier versions referred to a `$$PREBID_GLOBAL$$` build macro. As of Prebid 10 that macro no longer exists. Use your configured global variable (`pbjs` by default), as shown throughout this page and in [Customization](/customization).

## Data Attributes

Add the following `data-` attributes to ad unit containers. Use single quotes around attribute values, especially when passing JSON.

Required: `data-aaad` and `data-aa-adunit`.

* **Aaad** (`data-aaad`): Marks the element as an ad unit.
  * Values: `'true'` to enable, `'false'` to disable.
  * Required on all body ad unit elements.
* **Adunit** (`data-aa-adunit`): Full GAM ad unit code path to map the element.
  * Example: `'/22181265/Test_abcd'` or multi-level `'/22181265/Top/Child'`.
  * Use the GAM Ad unit CODE, not the UI name.
  * Required.
* **Sizes** (`data-aa-sizes`): Restrict allowed sizes for the ad unit.
  * JSON array of `[width,height]` pairs, e.g. `'[[300,250],[300,600]]'`.
* **OutOfPage** (`data-aa-outofpage`): Marks the ad unit as out-of-page.
  * Values: `'true'` or `'false'`.
* **Device** (`data-aa-device`): Restrict display by device types.
  * JSON array of strings, e.g. `'["desktop","tablet"]'`.
* **Targeting** (`data-aa-targeting`): Custom GAM targeting key-values at ad unit level.
  * JSON object, e.g. `'{"category":"cars","section":"auto"}'`.
* **Lazy Loaded** (`data-aa-lazy-loaded`): Enable lazy loading near viewport.
  * Values: `'true'` or `'false'`.
* **Refresh timed** (`data-aa-refresh-timed`): Auto-refresh rate in seconds after render.
  * Integer as string, e.g. `'60'`.
* **Refresh viewable** (`data-aa-refresh-viewable`): Auto-refresh rate in seconds after becoming viewable.
  * Integer as string, e.g. `'60'`.
* **Additional non hb sizes** (`data-aa-additional-non-h-b-sizes`): Sizes sent only to GAM (excluded from HB auctions).
  * JSON array of size pairs or string `"fluid"`, e.g. `'["fluid",[1,1]]'`.
* **Force GAM sizes** (`data-aa-force-gam-sizes`): Sizes sent to GAM for this ad unit, replacing the default (banner sizes + additional non-HB sizes). When set, GAM slot is defined with exactly these sizes.
  * JSON array of size pairs or `"fluid"`, e.g. `'[[300,250],[300,600]]'`.

### Example

```html
<div
  data-aaad='true'
  data-aa-adunit='/22181265/Test_abcd'
  data-aa-sizes='[[300,250],[300,600]]'
  data-aa-device='["desktop","tablet"]'
  data-aa-targeting='{"category":"cars","section":"auto"}'
  data-aa-lazy-loaded='true'
></div>
```

## Functions

All function calls should be queued and executed via the global command queue `pbjs.cmd`. Replace examples accordingly.

### Refresh

* **Refresh All**: Refresh all ad units on the page.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.refresh();
});
```

* **Refresh Adunits**: Refresh by GAM ad unit codes.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.refreshAdunits(['/dfpAccountId/Adunit1','/dfpAccountId/Adunit2']);
});
```

* **Refresh IDs**: Refresh by element IDs.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.refreshIds(['div-id-1','div-id-2']);
});
```

* **Refresh Elements**: Refresh by element handles.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.refresh([el1, el2]);
});
```

### Destroy

* **Destroy All**: Destroy all ad units on the page.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.destroy();
});
```

* **Destroy Adunits**: Destroy by GAM ad unit codes.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.destroyAdunits(['/dfpAccountId/Adunit1','/dfpAccountId/Adunit2']);
});
```

* **Destroy IDs**: Destroy by element IDs.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.destroyIds(['div-id-1','div-id-2']);
});
```

* **Destroy Elements**: Destroy by element handles.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.destroy([el1, el2]);
});
```

### Dynamic Content Processing

When new ad unit DIVs are injected after page load, notify the wrapper to process them.

* **Process Ads on Page**

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.processAdsOnPage();
});
```

* **Alternative (DOM Event)**

```javascript
document.dispatchEvent(new CustomEvent('aaw', { detail: { command: 'processAdsOnPage' } }));
```

### Privacy Settings

Pass privacy signals for compliance frameworks.

* **Set Privacy Settings**

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.setPrivacySettings({
    childDirectedTreatment: true
  });
});
```

* **Set Multiple Privacy Settings**

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.setPrivacySettings({
    childDirectedTreatment: true,
    underAgeOfConsent: true
  });
});
```

* **Clear Privacy Setting**

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.setPrivacySettings({
    childDirectedTreatment: null
  });
});
```

### Wrapper Settings

Configure global wrapper behavior.

* **Set Timeout (ms)**

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.setWrapperConfig('timeout', 800);
});
```

* **Set Lazy Load Fetch Distance (px)**

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.setWrapperConfig('lazyLoadFetch', 1500);
});
```

* **Set Lazy Load Fetch Distance in Portviews**

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.setWrapperConfig('lazyLoadFetchPortview', 2);
});
```

### Globals

Global variables exposed by the wrapper.

* **isLoaded**: Boolean that indicates when the wrapper has finished loading.

```javascript
if (pbjs && pbjs.isLoaded) {
  console.log('Wrapper ready');
} else {
  (pbjs = pbjs || { cmd: [] }).cmd.push(function () {
    console.log('Wrapper is now ready');
  });
}
```

* **wrapperVersion**: String representing the wrapper version.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  console.log('Wrapper version:', pbjs.wrapperVersion);
});
```

### Wrapper Introspection

Utility getters for wrapper state and configuration.

* **getWrapperConfig()**: Returns the current wrapper configuration object.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  const config = pbjs.getWrapperConfig();
  console.log('Wrapper config:', config);
});
```

* **getWrapperInternalAdunits()**: Returns the internal list of wrapper ad units.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  const adunits = pbjs.getWrapperInternalAdunits();
  console.log('Wrapper adunits:', adunits);
});
```

* **getWrapperDeviceDetection()**: Returns detected device information used by the wrapper.

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  const device = pbjs.getWrapperDeviceDetection();
  console.log('Wrapper device detection:', device);
});
```

## Events

Refer to your integration guide for any additional events available in your build.

### impressionViewable

Fires once per ad render when the wrapper’s own viewability tracker considers the impression viewable: at least **50%** of the slot’s bounding box intersects the viewport for a continuous **1 second**. This applies to **GAM-rendered** slots and **fallback-rendered** creatives. It is **independent** of `config.refresh.viewabilityProvider` (refresh scheduling still only uses the wrapper tracker when `viewabilityProvider` is `'wrapper'`).

For **GAM**, observation begins only after a **non-empty** `slotRenderEnded` (no creative means no tracker on that event). If the wrapper then serves a **fallback** creative, observation starts from the fallback render instead.

Subscribe with `pbjs.onEvent` inside a command callback so the handler is registered after the wrapper registers the event name:

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.onEvent('impressionViewable', function (data) {
    console.log('Ad became viewable:', data);
  });
});
```

**Payload**

* **divId** — DOM id of the ad container element.
* **adunit** — GAM ad unit path (`data-aa-adunit` on the container).
* **eventTrigger** — `'gam'` for GAM-rendered impressions, or a fallback reason code such as `'fallbackImps'`, `'fiH'`, `'fiFTF'`, `'fiECF'`.
* **advertiserId** — For GAM: line-item advertiser id, or `companyIds[0]` when present (e.g. open bidding). For fallback: winning bidder code from Prebid targeting when available, otherwise `'house'`.
* **targetingMap** — GAM slot targeting map for GAM renders, or the Prebid `targetingMap` passed into the fallback renderer.
* **renderedAt** — Epoch milliseconds when the render was recorded (observation start).
* **viewableAt** — Epoch milliseconds when the 1 s viewability dwell completed.
* **timeToViewable** — `viewableAt - renderedAt` in milliseconds (includes the 1 s dwell).

### fallbackRenderEnded

Fires when a **fallback-rendered** creative finishes parsing inside its iframe (the browser has reached `DOMContentLoaded` for that document). **GAM-rendered** slots do not trigger this event. The event is **not** emitted when a fallback render is skipped (e.g. rich media formats or the dedup guard that prevents a double render in the same slot).

Subscribe with `pbjs.onEvent` inside a command callback so the handler is registered after the wrapper registers the event name:

```javascript
(pbjs = pbjs || { cmd: [] }).cmd.push(function () {
  pbjs.onEvent('fallbackRenderEnded', function (data) {
    console.log('Fallback render finished parsing:', data);
  });
});
```

**Payload**

* **divId** — DOM id of the ad container element.
* **adunit** — GAM ad unit path (`data-aa-adunit` on the container).
* **eventTrigger** — Fallback reason code such as `'fallbackImps'`, `'fiH'`, `'fiFTF'`, `'fiECF'`.
* **advertiserId** — Winning bidder code from Prebid targeting when available, otherwise `'house'`.
* **targetingMap** — The Prebid `targetingMap` passed into the fallback renderer (may be emp


# Key-Values

**What is a key-value?** It's a small labelled piece of information the wrapper attaches to each ad request sent to Google Ad Manager (GAM). Each one has a short **Name** (the label GAM sees) and a **Value**. GAM uses these to decide which ad to show and to power your reporting — for example, you can report on how ads perform by device, by winning bidder, or by connection speed.

You don't have to set most of these up: the wrapper collects and sends them automatically. Some are controlled by settings in [Configuration](/configuration) (mostly under `targeting.*`); those are noted where relevant. New to the terms below (CPM, bidder, viewable, SafeFrame)? See the [Glossary](/glossary).

The current key-values are:

### Wrapper Version

**Description:** The major version of the wrapper.

**Name:** `wvr`

**Possible Values:**

* `3`: For the new wrapper.
* `2`: For the old wrapper.

### Prebid Winner Bidder (Prebid Specific)

**Description:** Prebid sends the winning bidder name to GAM.

**Name:** `hb_bidder`

**Possible Values:** The name of the bidder (e.g., `appnexus`, `pubmatic`).

### Prebid Winning Bid Value (Prebid Specific)

**Description:** Prebid sends the winning bid value to GAM.

**Name:** `hb_pb`

**Possible Values:** Depends on pricing, typically from `0.01` to `20.00`.

### Prebid Winning Format (Prebid Specific)

**Description:** Prebid sends the format type of the winning bid to GAM.

**Name:** `hb_format`

**Possible Values:** `banner`, `video`, `native`.

### Prebid Winning Source (Prebid Specific)

**Description:** Prebid sends the source of the winning bid to GAM.

**Name:** `hb_source`

**Possible Values:** `client`, `s2s`.

### Prebid Winning Sizes (Prebid Specific)

**Description:** Prebid sends the sizes of the winning bid to GAM.

**Name:** `hb_size`

**Possible Values:** The value of the sizes in `WIDTHxHEIGHT` format (e.g., `728x90`).

### Prebid Ad Category (Prebid Specific)

**Description:** Prebid sends the ad category of the winning bid to GAM, based on the IAB taxonomy, if disclosed by the bidder.

**Name:** `hb_acat`

**Possible Values:** The IAB taxonomy category ID of the winning bid, formatted as a string (e.g., `IAB1-18` for "News"). Categories follow the [IAB Content Taxonomy 1.0](https://github.com/katieshell/Taxonomies/blob/main/Content%20Taxonomies/Content%20Taxonomy%201.0.tsv).

### Prebid Advertiser Category Defined (Prebid Specific)

**Description:** Indicates whether the winning bid has advertiser category (`hb_acat`) data. Useful for reporting or targeting when the bidder disclosed an IAB category.

**Name:** `hb_acdef`

**Possible Values:** `0` (no ad category on the bid), `1` (bid has ad category).

### Prebid Ad Domain (Prebid Specific)

**Description:** Prebid sends the domain of the winning bid to GAM, if disclosed by the bidder.

**Name:** `hb_adomain`

**Possible Values:** The domain of the advertiser associated with the winning bid, formatted as a string (e.g., `example.com`).

### Prebid Ad Domain Defined (Prebid Specific)

**Description:** Indicates whether the winning bid has advertiser domain (`hb_adomain`) data. Useful for reporting or targeting when the bidder disclosed an ad domain.

**Name:** `hb_addef`

**Possible Values:** `0` (no ad domain on the bid), `1` (bid has ad domain).

### Prebid Winning Bid Cache Status

**Description:** Sends the cache status of the winning bid to GAM.

**Name:** `hb_cs`

**Possible Values:** `current`, `cached`, `storage`.

### Prebid Bid Density

**Description:** Sends the count of the number of bids received.

**Name:** `hb_bd`

**Possible Values:** The number of total bids.

### Flexible Safe Frames Signal

**Description:** Indicates whether SafeFrames are recommended for a specific impression based on the winning bid characteristics. The signal is set automatically by the wrapper according to configured rules that evaluate the bidder, advertiser domain, ad category, or ad unit. This key-value can be used in GAM line items or creative templates to conditionally enable SafeFrames.

**Configuration:** Set via `dfp.flexibleSafeFramesSignal` in config.json with conditions for bidders, advertiser domains, ad categories, or specific ad units.

**Name:** `hb_sframe`

**Possible Values:**

* `0`: SafeFrames not recommended for this impression
* `1`: SafeFrames recommended for this impression

### Price Range Bucket

**Description:** Provides a way to report based on a range of prices, rather than a specific CPM, allowing for more flexible and efficient reporting.

**Name:** `hb_rpb`

**Possible Values:** A string representing a price range, with increments of 0.10. The format is `[lower_bound]-[upper_bound]`, where bounds are formatted to two decimal places and separated by a hyphen (e.g., `0.50-0.60`). If a bid has a CPM of 1.23, the `hb_rpb` key will have the value `1.20-1.30`.

**Notes:** To use this key, it must be added to the `allowTargetingKeys` array in your Prebid configuration:

```javascript
{
   "targetingControls": {
     "allowTargetingKeys": ["hb_pb", "hb_rpb", "hb_deal"]
   }
}
```

### Adunit Not Hidden

**Description:** Checks if the adunit is hidden through HTML/CSS.

**Name:** `anh`

**Possible Values:**

* `true`: Adunit is not hidden.
* `false`: Adunit is hidden.
* For rich media formats, the name of the format (e.g., `adhesion`, `sticky`, `interstitial`, `peel`).

### PreRender Status

**Description:** Checks the Chrome prerender status.

**Name:** `prst`

**Possible Values:**

* `no`: The page is not prerendered.
* `before`: The page is prerendering but not activated yet.
* `after`: The page was prerendered and is now activated.

### Page Navigation Type

**Description:** Represents how the page navigation was initiated. Can be enabled in `config.targeting.pageNavigationType`.

**Name:** `pnType`

**Possible Values:**

* `reload`: Page was reloaded/refreshed.
* `push`: New navigation entry (normal navigation).
* `replace`: Current entry was replaced.
* `traverse`: Navigation through history (back/forward).
* `navigate`: Normal navigation (clicking a link, typing a URL, etc.).
* `back_forward`: Navigation via browser back/forward buttons.
* `prerender`: Page was prerendered.
* `reserved`: Reserved value.
* `unknown`: When navigation type cannot be determined.

### Wrapper Iframe Environment

**Description:** The wrapper checks if it is loaded within an iframe and what type of iframe.

**Name:** `wie`

**Possible Values:**

* `top`: Wrapper is not in an iframe.
* `friendly`: Wrapper is in a friendly iframe.
* `cross`: Wrapper is in a cross-domain iframe.
* `safe`: Wrapper is in SafeFrames.

### Wrapper Re-write Global Conflict

**Description:** Detects if there is a conflict when the wrapper attempts to re-write the default Prebid global variable.

**Name:** `wrc`

**Possible Values:**

* `nc`: No Conflict.
* `fr`: Forced Re-write set, but no conflict.
* `cr`: Conflict Re-write detected.

### Tab In Focus

**Description:** Detects if the browser tab/window where the ad is displayed is in focus.

**Name:** `tif`

**Possible Values:** `true`, `false`.

### Refresh Iteration Counter

**Description:** Counts the number of refreshes for an adunit.

**Name:** `refresh_count`

**Possible Values:** An integer representing the refresh count.

### Refreshed Inventory Boolean

**Description:** Tracks whether the inventory has been refreshed.

**Name:** `refreshed`

**Possible Values:** `true`, `false`.

### Refreshed Accelerated Seconds

**Description:** Represents the number of seconds the refresh was accelerated by.

**Name:** `ras`

**Possible Values:** From `0s` to `30s`.

### Display Advertisers History

**Description:** Logs all Google Ad Manager (GAM) advertiser/company IDs that displayed an ad.

**Name:** `dah`

**Possible Values:** A list of GAM advertiser IDs.

### Last Advertiser Displayed

**Description:** Logs the last Google Ad Manager (GAM) advertiser/company ID that displayed an ad.

**Name:** `lad`

**Possible Values:** The GAM ID of the last advertiser displayed.

### Last User Interaction

**Description:** The time elapsed since the last user interaction (click, touch, scroll, visibility change, resize).

**Name:** `lui`

**Possible Values:**

* From `0s` to `59s`.
* From `1m` to `59m`.
* `1h` for interactions exceeding 59 minutes.

### Session Depth

**Description:** The number of pageviews made in the current session.

**Name:** `sesdepth`

**Possible Values:** An integer representing the pageview count for the session.

### GAM Library Load Time

**Description:** The time it takes for the GAM library to load, relative to the Wrapper Load Time.

**Name:** `gpt_l`

**Possible Values:** From `0` to `10000` in `100` increments.

### Wrapper Load Time

**Description:** The time it takes for the Wrapper to load, relative to page navigation.

**Name:** `wrap_l`

**Possible Values:** From `0` to `10000` in `100` increments.

### Page Load Time

**Description:** The time it takes for the page to load. This is important as the first ad processing occurs upon page load.

**Name:** `page_r`

**Possible Values:** From `0` to `10000` in `100` increments.

### Wrapper Analytics Auction Init

**Description:** The time it takes for the auction to be initiated, relative to the Wrapper Load Time.

**Name:** `waai`

**Possible Values:** From `0` to `10000` in `100` increments.

### Wrapper Analytics Auction End

**Description:** The time it takes for the auction to end, relative to the auction initiation.

**Name:** `waae`

**Possible Values:** From `0` to `10000` in `100` increments.

### Wrapper Analytics Bidders Timeout

**Description:** Identifies bidders that timed out, relative to Prebid's detection.

**Name:** `wabt`

**Possible Values:** The name of the bidders.

### Wrapper Analytics Bidders Timeout Real

**Description:** Identifies bidders that timed out before bids were sent to GAM.

**Name:** `wabtr`

**Possible Values:** The name of the bidders.

### Connection DownLink

**Description:** The connection downlink speed.

**Name:** `cndl`

**Possible Values:**

* `0`: Unknown.
* `0.1`: Under 1MB.
* `1`: 1-9.99 MB.
* `10`: 10-99.99 MB.
* `100`: 100-999.99 MB.
* `1000`: >= 1000 MB.

### Connection RTT

**Description:** The connection Round Trip Time speed.

**Name:** `cnrtt`

**Possible Values:**

* `0`: Unknown.
* `10`: <= 10ms.
* `100`: <= 100ms.
* `900`: <= 900ms.
* `1000`: >= 1000ms.

### Connection Type

**Description:** The connection type.

**Name:** `cntp`

**Possible Values:** `na`, `bluetooth`, `cellular`, `ethernet`, `none`, `wifi`, `wimax`, `other`, `unknown`.

### Connection Effective Type

**Description:** The connection speed type.

**Name:** `cnet`

**Possible Values:** `na`, `slow-2g`, `2g`, `3g`, `4g`, `5g`.

### Connection Save Data

**Description:** Indicates if the connection has save data enabled.

**Name:** `cnsd`

**Possible Values:** `true`, `false`.

### Page Ad Density PreRequest

**Description:** Represents ad density before requests, based on the biggest ad size available.

**Name:** `padpr`

**Possible Values:** From `0` to `100`.

### Page Ad Density

**Description:** Represents ad density after ads have been rendered.

**Name:** `pad`

**Possible Values:** From `0` to `100`.

### Google Ad Manager Identification

**Description:** Checks if the GAM cookie, used to identify the user, exists.

**Name:** `gads`

**Possible Values:** `true`, `false`.

### Cookies Enabled

**Description:** Checks if the browser allows third-party cookies.

**Name:** `cookieEnabled`

**Possible Values:** `true`, `false`, `na`.

### User Identifications Services/Providers

**Description:** The wrapper checks which User Identification services detected the user.

**Name:** `uids`

**Possible Values:** Name of the User Identification services.

### User Identifications Services/Providers Count

**Description:** The wrapper counts how many User Identification Services detected the user.

**Name:** `uids_c`

**Possible Values:** The number of User Identification services.

### Topics API Interests

**Description:** The interests according to Topics API.

**Name:** `topicsapi`

**Possible Values:** Topics API Taxonomy.

**Notes:** For more information on how topics are curated and selected, refer to [Google Privacy Sandbox Topics](https://developers.google.com/privacy-sandbox/relevance/topics#manually-curated).

### Individual User Identifications Services/Providers

**Description:** Sets a key-value for each configured User Identification Service/Provider, indicating if the user has been identified.

**Name:** Name of the Service/Provider configured.

**Possible Values:** `true`, `false`.

### UTMs utm\_campaign

**Description:** The wrapper checks if UTMs are set in the URL and sends the `utm_campaign` value to GAM.

**Name:** `utm_campaign`

**Possible Values:** Value of the `utm_campaign` parameter.

### UTMs utm\_source

**Description:** The wrapper checks if UTMs are set in the URL and sends the `utm_source` value to GAM.

**Name:** `utm_source`

**Possible Values:** Value of the `utm_source` parameter.

### UTMs utm\_medium

**Description:** The wrapper checks if UTMs are set in the URL and sends the `utm_medium` value to GAM.

**Name:** `utm_medium`

**Possible Values:** Value of the `utm_medium` parameter.

### UTMs utm\_content

**Description:** The wrapper checks if UTMs are set in the URL and sends the `utm_content` value to GAM.

**Name:** `utm_content`

**Possible Values:** Value of the `utm_content` parameter.

### Device

**Description:** Checks the device type.

**Name:** `device`

**Possible Values:** `desktop`, `tablet`, `mobile`.

### Browser

**Description:** Checks the browser.

**Name:** `browser`

**Possible Values:** `edge`, `chrome`, `firefox`, `safari`, `opera`, `ie`, `other`.

### Operating System

**Description:** Checks the operating system.

**Name:** `os`

**Possible Values:** `linux`, `mac`, `windows`, `other`.

### Browser Language Code

**Description:** Checks the browser language code.

**Name:** `blc`

**Possible Values:** A comprehensive list of language codes (e.g., `en-US`, `fr-CA`, `zh-TW`).


# Rich Media Formats

**In plain terms:** a rich media format is a more eye-catching way of presenting an ad — for example an ad that sticks to the bottom of the screen, stays in view as the visitor scrolls, or briefly covers the page. These formats typically earn more than a plain box in the page. The wrapper ships with several ready-to-use formats (adhesion, sticky, peel, interstitial) that you can turn on per ad unit with a few settings, and it also lets developers build entirely new ones.

This page has two parts: the built-in formats you can simply configure (jump to [RichMedia Formats Core Modules](#richmedia-formats-core-modules)), and the developer toolkit for creating custom formats (the sections just below). If you only want to switch on an existing format, you can skip straight to the core modules.

RichMedia Formats are custom scripts that allow manipulation of how ads are displayed and interact on the page. RichMedia Formats Modules enable the creation of custom RichMedia Formats with various functionalities.

RichMedia Formats Modules can be added as a Custom script file in the `src` folder of the wrapper.

Here is an example of a RichMediaFormat Module: [Example](https://gitlab.com/adops/wrapper-richmediaformats/-/blob/master/example/src/custom_exampleRichMediaFormatAdapter.js). This example simply adds a label overlay over the ad to display the name of the adunit.

## Importing RichMedia Manager

**Description:** This provides the modular functionality inside the wrapper and is required for modularization to work.

```javascript
import richMediaManager from '../../src/_richMediaManager.js';
```

## Add format to RichMedia Manager

**Description:** Calling the `addFormat` function adds the format to the RichMedia Manager, making it available for use in the wrapper. The function takes an object as a parameter with the following properties:

**Properties:**

1. `name`: The name of the RichMediaFormat. This name is used in the module and when defining adunits as RichMediaFormats.
2. `options`: An object that holds all the default values for the options. While not strictly required to define a default for all options, it is recommended to have a default value for every option.
3. `bannerPos`: The ORTB 2.0 definition of the position of the ad on the page.
   * `0`: Unknown
   * `1`: ATF (Above The Fold)
   * `2`: DEPRECATED
   * `3`: BTF (Below The Fold)
4. `initFunc`: This function is called after the ad divs are processed on the page. It takes the DOM element of the ad div as a parameter and can alter or mutate ad divs before the ads are rendered.
5. `registerListener`: This function is called when the GAM `slotRenderEnded` event is fired. It takes the DOM element of the ad div and the GAM event parameter as arguments. This is where you can render the ad.

```javascript
export const richMediaFormat = {
	"name" : "example",
	"options" : {"option1":"value1"},
	"bannerPos" : 0,
	"initFunc" : function(el){},
	"registerListener" : function(el,event){}
};

richMediaManager.addFormat(richMediaFormat);
```

## RichMedia Formats Core Modules

**Description:** Some rich media formats are built-in as core modules and can be included and configured directly in the wrapper. To add a core module, add the rich media format module to the `modules.json` file.

An adunit can be configured in one of two ways:

1. **In `adunits.json`**: By setting the `richMediaFormat` property.

   ```json
   {
      "adunit":"/22181265/Test_abcd",
      "device":["desktop","tablet","mobile"],
      "mediaTypes":{"banner":{"sizes":[[728,90]]}},
      "additionalNonHBSizes":[],
      "targeting":{"pos":"top"},
      "lazyLoaded":"false",
      "richMediaFormat":{"type":"adhesion","options":{"closeButton":"true"}},
      "refreshTimed":"0",
      "refreshViewable":"0",
      "css":"border: 0px;",
      "bids" : [
            {"bidder":"appnexus","params":{"placementId":"123456"}}
      ]
   }
   ```
2. **In body div tag**: By setting the data attribute `data-aa-rich-media-format`.

   ```html
   <div data-aaad='true' data-aa-adunit='/22181265/Test_abcd' data-aa-rich-media-format='{"type":"adhesion","options":{"closeButton":"true"}}'></div>
   ```

### Adhesion

**Type:** `adhesion`

**Module:** `adhesionRichMediaFormatAdapter`

**Options:**

* `closeButton`: If set to `true`, it will add a close button that will close the ad.
* `position`: Possible values `header` and `footer`. It will place the adhesion at the header or footer of the page.
* `bottomPosition`: The distance from the bottom of the page. It takes any CSS value for the `bottom` property.
* `topPosition`: The distance from the top of the page. It takes any CSS value for the `top` property.
* `autoClose`: Integer value representing seconds until the format will automatically close.
* `closePermanent`: If set to `true`, when a user closes the format, it will also destroy the adunit.

### Sticky

**Type:** `sticky`

**Module:** `stickyRichMediaFormatAdapter`

**Options:**

* `closeButton`: If set to `true`, it will add a close button that will close the ad.
* `top`: Integer in pixels representing distance from the top. It MUST be used in conjunction with `right` or `left`.
* `bottom`: Integer in pixels representing distance from the bottom. It MUST be used in conjunction with `right` or `left`.
* `left`: Integer in pixels representing distance from the left. It MUST be used in conjunction with `top` or `bottom`.
* `right`: Integer in pixels representing distance from the right. It MUST be used in conjunction with `top` or `bottom`.
* `autoClose`: Integer value representing seconds until the format will automatically close.
* `closePermanent`: If set to `true`, when a user closes the format, it will also destroy the adunit.

### Peel Ad

**Type:** `peel`

**Module:** `peelRichMediaFormatAdapter`

**Options:**

* `closeButton`: If set to `true`, it will add a close button that will close the ad.
* `top`: Integer in pixels representing distance from the top. It MUST be used in conjunction with `right` or `left`.
* `bottom`: Integer in pixels representing distance from the bottom. It MUST be used in conjunction with `right` or `left`.
* `left`: Integer in pixels representing distance from the left. It MUST be used in conjunction with `top` or `bottom`.
* `right`: Integer in pixels representing distance from the right. It MUST be used in conjunction with `top` or `bottom`.
* `closePermanent`: If set to `true`, when a user closes the format, it will also destroy the adunit.

### Interstitial

**Type:** `interstitial`

**Module:** `interstitialRichMediaFormatAdapter`

**Options:**

* `timeOpen`: Integer value representing the time in seconds until the close button is available to click.
* `timeOpenShow`: If `true`, it will show the timer until the close button is available.
* `maxDisplayPerSession`: Integer value representing the maximum displays in a session.
* `pageviewDisplayStart`: Integer value representing the first pageview count when the interstitial will display.
* `pageviewDisplayEvery`: Integer value representing when to display the interstitial repeatedly based on pageview count.
* `backgroundColor`: Hex value or other CSS color representing the background of the interstitial.
* `opacity`: Float value representing the CSS opacity of the background.


# Troubleshooting

Use these tips to diagnose and debug wrapper integrations. Most problems come down to a small mismatch between what's on the page and what's in the configuration — the checks below catch the common ones quickly.

The debugging tools work by adding a short flag to the end of the page's web address (a "query string"). This turns on an on-screen console or extra logging just for you, without affecting normal visitors.

> **A note on `pbjs` in this page:** `pbjs` is the wrapper's global variable name, set per site by the `globalVar` setting in `config.json`. It's `pbjs` by default and is used throughout these examples. **If your site uses a different `globalVar`, replace `pbjs` with that name** — including in the URL flags below (e.g. a site using `chp` would use `chpConsole=true`).

## Symptoms

* No ads rendering
* Long auctions or frequent timeouts
* Unexpected size or device behavior
* Ad refresh not happening as expected

## How to verify

* Check that `data-aaad='true'` is present on ad unit divs
* Check that `data-aa-adunit` uses the GAM Ad unit CODE and full path
* Confirm `Sizes` and device attributes match configuration
* Verify the wrapper is loaded: `pbjs.isLoaded === true`

## Enable Wrapper Console (via URL)

Append this query string to your page URL to show the wrapper console UI overlay:

```
pbjsConsole=true
```

Example:

```
https://example.com/page?pbjsConsole=true
```

This opens an on-page console with high-level status, ad unit states, and actions.

## Enable Verbose Debug Logging (via URL)

Append this query string to enable verbose logging in the browser console:

```
pbjs_debug=true
```

Example:

```
https://example.com/page?pbjsConsole=true&pbjs_debug=true
```


# Privacy Disclaimer

**Version:** 1.0 — July 2026 **Applies to:** the header-bidding wrapper built from this repository (a customized Prebid.js build, "the Wrapper") **Audience:** companies deploying the Wrapper on their websites ("Deploying Companies") and their legal/privacy teams

> **Purpose of this document.** This document is a privacy disclaimer and technical disclosure: an inventory of the device storage and network requests performed by the Wrapper itself, with a legal categorization of each. It exists so that Deploying Companies can meet their own obligations under the GDPR, the ePrivacy Directive, and US state privacy laws. It is technical documentation, **not legal advice** — see the Disclaimer at the end of this document.

***

## 1. Roles and allocation of responsibility

**The Deploying Company is the data controller** (GDPR Art. 4(7)) for all personal data processed on its websites through the Wrapper. It decides to use the Wrapper, selects and configures the demand partners, identity modules, RTD modules, and tags, hosts the analytics backend, and operates the Consent Management Platform (CMP).

**The Wrapper is software executing the Deploying Company's configuration.** It does not process data for its own purposes. Data collected by the Wrapper's analytics module is transmitted exclusively to an endpoint operated by (or for) each Deploying Company; datasets are not pooled or shared across companies, and no cross-site profiles are built. For any data processed on behalf of a Deploying Company, that company's own privacy policy governs how the data is used.

**Third parties configured into the Wrapper — bidders/demand partners, user ID modules, RTD modules, user-sync endpoints, and page tags (e.g., Google Publisher Tag, Google Tag Manager, Microsoft Clarity) — are independent controllers** of the processing they perform once they receive data or execute on the page. Their processing is governed by their own privacy policies and, where applicable, by the IAB Europe Transparency & Consent Framework (TCF) responsibility allocation. See Section 5.

**Caveat that Deploying Companies must understand:** under CJEU case law (*Fashion ID*, C-40/17; *Wirtschaftsakademie*, C-210/16), a website operator that embeds third-party technology is a **joint controller for the collection and transmission phase** of that third party's processing. Responsibility for what third parties do with data afterwards lies with those third parties, but the decision to send them data in the first place belongs to the Deploying Company. This is why consent gating via the CMP (Section 6) is the load-bearing safeguard.

***

## 2. Technical inventory — device storage used by the Wrapper itself

All keys are namespaced with the per-site global variable (`<gv>` below), so every identifier is **first-party and scoped to the individual website**. None of these values are shared across sites or with third parties, except as expressly noted.

| Key                                         | Type                                   | Lifetime                       | Contents & purpose                                                                                                                                                                                                                                                                                                       | Legal categorization                                                                                                                |
| ------------------------------------------- | -------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| `_<gv>_sid`                                 | Cookie (SameSite=Lax) + sessionStorage | 60 minutes                     | Random UUID session identifier. Correlates events within a browsing session for monitoring, debugging, and detection of anomalous behavior (e.g., abusive click/reload patterns).                                                                                                                                        | Security / fraud prevention / debugging — TCF **Special Purpose 1**; strictly-necessary exemption claimed under ePrivacy Art. 5(3). |
| `_<gv>_uid`                                 | Cookie (SameSite=Lax)                  | 30 days                        | Random UUID browser identifier. Used to recognize recurrence of technical faults and to identify similar behavior patterns originating from apparently different devices/browsers that may be malicious (spoofing, invalid traffic). Consumed only by the per-company analytics module; **never** added to bid requests. | Security monitoring / troubleshooting — TCF **Special Purpose 1**. See risk note in Section 7.1.                                    |
| `_<gv>_sesdepth`                            | sessionStorage                         | Session                        | Integer page-depth counter (pages viewed this session). Used as reporting/auction context.                                                                                                                                                                                                                               | Strictly necessary auction context / measurement support.                                                                           |
| `_<gv>_anep`                                | localStorage                           | Until cleared / failover reset | Which analytics endpoint URL is in use (failover selection). No personal data.                                                                                                                                                                                                                                           | Strictly necessary technical setting.                                                                                               |
| `_<gv>_trackbids`                           | localStorage                           | 24 h (self-expiring timestamp) | Debug flag enabling verbose bid logging. No personal data.                                                                                                                                                                                                                                                               | Debugging — Special Purpose 1.                                                                                                      |
| `_<gv>_hbWrapperFpd`                        | localStorage                           | Until overwritten              | Cached first-party context from the CDN edge or fallback lookup: coarse IP-derived geolocation (country) and the IP observed at lookup time.                                                                                                                                                                             | Technical cache supporting geo context & troubleshooting. See risk note in Section 7.2.                                             |
| `_<gv>_userInfo`                            | localStorage                           | Until overwritten              | Derived user-info cache (IP at lookup time, country). Same source and purpose as above.                                                                                                                                                                                                                                  | Same as above.                                                                                                                      |
| `_<gv>_bc_<adunit>_<adId>`, `_<gv>_bc_idx_` | localStorage                           | Expiring; evicted on quota     | Cached winning/unused bid objects (ad markup, price metadata, ad unit) for re-use across pages. Contains **no user identifiers**.                                                                                                                                                                                        | Strictly necessary for the ad-delivery function requested by the publisher.                                                         |
| `_<gv>_console`                             | localStorage                           | 1 h (self-expiring timestamp)  | Enables the on-page debugging console for operators. No personal data.                                                                                                                                                                                                                                                   | Debugging tool state.                                                                                                               |

The Wrapper does **not** use IndexedDB, does not read or write third-party cookies, and does not employ fingerprinting techniques to generate identifiers (identifiers are random UUIDs; device signals read for bot detection are described in Section 3.1).

***

## 3. Technical inventory — network requests made by the Wrapper itself

### 3.1 Per-company analytics endpoint

Configured per Deploying Company; operated by or for that company (data hosted per company, not pooled).

**Data transmitted:** page URL and referrer (truncated to 1024 chars), site/environment identifiers, pageview ID, session ID (`_<gv>_sid`), browser ID (`_<gv>_uid`), browser and device characteristics (user agent, screen/device class), network quality (rounded downlink, RTT), coarse IP-derived geolocation received from the CDN edge (country, city, region, postal code), Core Web Vitals metrics, A/B variant assignments, auction lifecycle events (ad units, bidders, bid prices, latencies, errors), and bot-detection signals (`navigator.webdriver` flag, absence of language list, user-agent anomalies). The visitor's IP address is inherently visible to the receiving server at the transport level; the Wrapper does not add it to the payload.

**Purposes:** monitoring, performance measurement, debugging, security/invalid-traffic analysis. **Not used for:** cross-site profiling, ad targeting, audience building, or sale/sharing.

**Legal categorization:** first-party measurement and security telemetry processed under the Deploying Company's controllership; GDPR legal basis legitimate interests (Art. 6(1)(f)) for security, fraud prevention, debugging and aggregate performance analytics. Where the endpoint is hosted by a party other than the Deploying Company, that party acts as a processor (Art. 28) and a DPA is required.

### 3.2 CDN (Cloudflare) — bundle delivery and edge context

The Wrapper bundle is served from a CDN (Cloudflare). The CDN edge may derive coarse geolocation from the connecting IP (standard CDN functionality) and inject it as `window.hbWrapperFpd`, including an A/B bucket assignment. When the CDN edge did not provide this context (`window.hbWrapperFpd` absent), the Wrapper calls `https://cloudflare.com/cdn-cgi/trace` as a fallback, which returns the visitor's IP and country code; these are cached locally (Section 2). In both cases Cloudflare receives standard HTTP requests (IP, user agent) as a technical consequence of content delivery. **The Deploying Company should verify Cloudflare's privacy policy and terms** and list Cloudflare as a recipient/processor in its own disclosures where applicable.

### 3.3 Data injected into bid requests (optional `firstPartyData` feature)

When a Deploying Company enables `wrapper.firstPartyData` in its configuration, the Wrapper merges the following into the OpenRTB (`ortb2`) object sent to **all configured bidders**:

* **Coarse IP-derived geolocation** — country, city, region, postal code, IP-lookup lat/lon, UTC offset. This is derived at the CDN edge from the IP address; it is not GPS and does not meet the TCF "precise geolocation" threshold (< 500 m).
* **IP address (`device.ip`/`device.ipv6`)** — passed through for troubleshooting and malware/invalid-traffic detection by the receiving networks. The Wrapper does not itself store this value beyond the local caches in Section 2. Note that bidders contacted client-side observe the visitor's IP at the HTTP layer regardless.
* **Context signals** — device class (mobile flag), A/B bucket, and similar non-identifying auction context.

The Wrapper **never** injects its own `_<gv>_sid`/`_<gv>_uid` identifiers into bid requests. Third-party user IDs (EIDs) are handled exclusively by Prebid's consent-gated user ID modules configured by the Deploying Company.

**Legal categorization:** transmission of personal data (IP, coarse geo) to configured demand partners, initiated on the Deploying Company's instruction; purposes limited to ad delivery, troubleshooting, and fraud/malware detection (TCF Special Purpose 1 and applicable purposes signaled via the TC string). The Deploying Company is responsible for enabling this feature only where its CMP establishes an adequate lawful basis for the transmission.

### 3.4 What the Wrapper does not request

The Wrapper itself makes no other network calls. All further requests observed on a page — bid requests, user syncs (pixels/iframes), identity resolution calls, RTD lookups, ad creatives, GPT/GTM/Clarity and other tags — belong to third parties or to company-configured integrations (Section 5).

***

## 4. Consent handling behavior

The Wrapper detects the page CMP automatically (`__tcfapi` for TCF/GDPR, `__gpp` for GPP/US state laws) at initialization and configures Prebid's consent management accordingly, **before** user-sync and user ID module initialization, so that:

* when the CMP provides a consent string (TC string / GPP string), the Wrapper **passes it to the third parties** it contacts — bidders, user ID modules, and user-sync endpoints — with each request;
* when no CMP is present, or the CMP does not provide a consent string, requests are sent without one, and **each third party decides how to process such a request** under its own legal obligations;
* **user syncs** are deferred until after the auction and triggered only per configuration, with the same consent-string pass-through;
* for GDPR, TCF v2 signals are re-checked at each auction; for the US, GPP sections (including US National/state strings) are passed through to bidders.

If no CMP is present on the page, the Wrapper cannot obtain a consent string. **Deploying a CMP — and ensuring it functions correctly — is the Deploying Company's responsibility** wherever consent-based processing occurs (EU/EEA/UK, and opt-out signal handling in US states).

The Wrapper's own storage (Section 2) is initialized at load time under the security/debugging categorization stated there, independent of CMP state. See Section 7.1.

***

## 5. Third parties — independent responsibility

This section covers all endpoints and scripts that the Wrapper contacts or loads **because the Deploying Company configured them**: demand partners / bidders (client- and server-side), user ID / identity modules, RTD modules, user-sync endpoints, and page tags the Wrapper can inject when configured (Google Publisher Tag, Google Tag Manager, Microsoft Clarity, Amazon TAM/A9, and similar).

1. **Independent controllership.** Each such third party determines its own purposes and means for the data it receives (bid requests, sync pixels, script execution context) and is an independent controller under GDPR Art. 4(7), and/or a "third party"/"business" under CCPA/CPRA. Its processing is governed by its own privacy policy and — for TCF-registered vendors — by its Global Vendor List registration.
2. **Consent transmission.** The Wrapper transmits the TC string / GPP string with bid requests and syncs. Acting on those signals (including honoring refusals and opt-outs) is each vendor's own legal obligation under TCF Policies and applicable law.
3. **Due diligence.** The Deploying Company selects these vendors in its configuration and must perform its own due diligence: verify GVL registration, review vendor privacy policies, ensure vendor disclosure in its CMP and cookie notice, and maintain contracts where required. No representation or warranty is made as to any third party's practices; the authoritative source is each vendor's own current legal documentation.
4. **Storage by third parties.** Cookies and storage set by bid adapters, ID systems, sync pixels, or tags (including any storage written by adapter code bundled in this repository on behalf of a vendor) belong to the respective vendor's controllership and must appear in the Deploying Company's cookie notice under that vendor's name.
5. **Custom scripts.** Any custom script deployed or configured by the Deploying Company that loads third-party assets (tags, pixels, libraries, creatives, or any other external resource) is the Deploying Company's sole responsibility, including compliance of those assets and their providers with applicable legislation.

***

## 6. Obligations checklist for Deploying Companies

1. Operate a compliant **CMP** (TCF-registered for EU/EEA traffic; GPP-capable for US traffic) on every page running the Wrapper.
2. List the Wrapper's first-party storage (Section 2) in your **cookie notice**, under "strictly necessary / security" and "performance" as categorized, including the 30-day `_<gv>_uid` with its purpose and duration.
3. List your configured **vendors** (bidders, ID modules, RTD providers, tags) in the CMP and privacy policy; keep the list current with your wrapper configuration.
4. Ensure a **DPA (Art. 28)** exists with whoever hosts your analytics endpoint and CDN, if not you.
5. Define **retention** for your analytics dataset (recommendation: define a fixed window aligned with your troubleshooting cycle, e.g., 13 months maximum, and document it).
6. Route **data subject requests** concerning wrapper data to your own DPO/privacy contact; the identifiers are yours (first-party), so access/erasure is executed in your analytics store and by cookie deletion.
7. If you enable `wrapper.firstPartyData`, confirm your CMP disclosures cover transmission of IP and coarse geolocation to your configured demand partners.
8. Conduct a **legitimate interests assessment (LIA)** — and where appropriate a DPIA — for the security/debugging telemetry, referencing this document's inventory.

***

## 7. Residual risk notes (read before relying on this document)

### 7.1 Ungated first-party identifiers

The `_<gv>_sid` (60 min) and `_<gv>_uid` (30 days) identifiers are written before CMP interaction, on the categorization that they are strictly necessary for security monitoring, fraud/anomaly detection, and troubleshooting (ePrivacy Art. 5(3) exemption; TCF Special Purpose 1). This position is **defensible but not risk-free**: EU regulators construe the strictly-necessary exemption narrowly (WP29 Opinion 04/2012; EDPB Guidelines 2/2023), and a 30-day identifier used for security monitoring where systematic invalid-traffic analysis is not continuously operated may be challenged, in particular by the French CNIL and German DSK. Mitigations available to Deploying Companies: (a) operate and document an actual recurring security/IVT analysis over this data; (b) alternatively, configure or request consent-gating of the 30-day identifier and rely on the session identifier alone for non-consenting users. The 30-day duration reflects the operator's documented need for month-on-month troubleshooting analysis.

### 7.2 IP addresses in localStorage caches

The `_<gv>_hbWrapperFpd` and `_<gv>_userInfo` caches persist the IP observed at lookup time until overwritten. IP addresses are personal data (*Breyer*, C-582/14). Recommendation: treat these caches as part of the security/troubleshooting categorization above, and prefer country-only caching in a future revision.

***

## 8. Disclaimer — not legal advice

This document is a technical disclosure and privacy disclaimer provided to Deploying Companies for information purposes only. It does not constitute legal advice, does not create any advisory relationship, and no warranty is given as to its completeness or its sufficiency for compliance in any jurisdiction. Each Deploying Company remains solely responsible for its own compliance with applicable data protection and privacy legislation, including its choice and configuration of third parties, its CMP, and its own disclosures. **Please obtain your own independent legal advice before relying on anything in this document.**

*This document describes the code in this repository as of the version date. Regenerate after material changes to storage keys, endpoints, or data flows.*


# Release Notes

This section contains the release notes for different versions of the Header Bidding wrapper.

## How to read these notes

Each bullet is tagged with the area it affects (e.g. **Prebid**, **Analytics**, **SafeFrames**, **Config**). "Fast-Forward prebid PR" means a fix from the upstream Prebid.js project was pulled in ahead of a full version update.

## Release Schedule

Releases go out every **Tuesday morning**. Before a version reaches full traffic, it is A/B tested the prior week on **10% of traffic** to verify stability — ad requests, revenue, CPM, and viewability are checked to confirm they remain within normal ranges.

## Version 7.32.0 (2026-10-27)

* **Prebid:** Updated to [Prebid.js 11.39.0](https://github.com/prebid/Prebid.js/releases/tag/11.39.0).
* **Infrastructure:** Updated the hbwrapper Node.js runtime to 22.23.4 for the [CVE-2026-111497](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases) security alert (Brotli decoder RCE / Node2Shell). Builder, agent, public API, web, and pcache all run on the patched version.
* **Wrapper:** Mitigates multiple wrapper instances on the same page. The first wrapper to load claims ownership of the page; any later wrapper aborts instead of competing for the same GPT slots, placements, and targeting.
* **Bid caching:** The reusable creative cache in browser storage is now capped at about 1 MB. On each page load and after every auction the wrapper drops expired entries and trims the least valuable creatives first so higher-paying ones stay. A new creative that still cannot fit is skipped without deleting better ones already stored.
* **Bid caching:** Fixed stale renders when the same ad unit is placed more than once on a page. The auction listed that ad unit once per placement, so the same stored creative was handed to every placement with the same ad ID. GAM could serve it on both and Prebid flagged the second render as stale, leaving that slot blank. Each stored creative is now offered once per auction, so it lands on a single placement and the others compete with their own bids.
* **Builder:** Auto-build on commit. Every 5 minutes the builder picks up new commits in the config repositories and builds each changed wrapper on both master and pre-release, then deploys to the CDN and updates the gist codes, the same pipeline as a manual build. Several commits to the same wrapper produce a single build; a commit touching several wrappers builds all of them. Can be switched on or off per account.
* **Builder:** Builds requested from the UI always go ahead of automatic builds in the queue. Use the UI when a change must go live immediately; otherwise auto-build picks it up within 5 minutes.
* **Management:** Automatic builds are tagged `auto` in the build logs, together with the commits that triggered them. The Builder page shows when the next automatic check runs. Build errors are still shown only in the UI for now; email and Slack notifications are planned.

## Version 7.31.0 (2026-10-20)

* **Prebid:** Updated to [Prebid.js 11.38.0](https://github.com/prebid/Prebid.js/releases/tag/11.38.0).
* **Config:** Renamed `dfp.appendNetworkCodeToGTPTag` to `dfp.appendNetworkCodeToGPTTag` (typo fix).
* **Revenue / Refresh:** Fixed Header Bidding prices being lost on Safari and Firefox. These browsers process ad events in a different order than Chrome, so the winning bid's price was already cleared when the ad rendered: Estimated CPM read as 0, refresh acceleration never applied to high-value placements, and viewability events were missing bidder and price. The wrapper now captures the targeting sent to GAM at request time and uses it with priority, so all browsers behave the same.
* **Analytics:** Tracking events are now delivered reliably when the visitor switches tabs, minimizes the browser or leaves the page. Previously some of these events (e.g. Core Web Vitals) could be dropped, especially on Safari/iOS.
* **Analytics:** Improved the analytics collectors so that rejected requests report the real error instead of a browser CORS error, making delivery issues easier to diagnose.
* **Storage:** Wrapper browser-storage writes (analytics routing preference, debug flags, first-party geo cache, UTM targeting, session frequency caps, and similar small values) are now best-effort: if the browser refuses a write because storage is full or blocked, the page keeps loading instead of stopping with no ads. On each page start the wrapper also drops its own expired or obsolete entries (old monthly routing preferences, expired debug flags, and unused leftovers), so they do not pile up across visits. Live identity and first-party data used for normal auctions are left alone.

## Version 7.30.0 (2026-10-13)

* **Prebid:** Updated to [Prebid.js 11.37.0](https://github.com/prebid/Prebid.js/releases/tag/11.37.0). Bumped 4 versions to get some fixes on latency for viewability detection #15421 , Sanitize ORTB #15616.
* **Prebid:** Fast-Forward prebid PR [15691](https://github.com/prebid/Prebid.js/pull/15691) — User ID: initialize submodules added by a later `setConfig` / `mergeConfig` (otherwise a provider registered after the first userSync config could stay uninitialized for that pageview).
* **Prebid:** Fast-Forward prebid PR [15711](https://github.com/prebid/Prebid.js/pull/15711) — TTD Bid Adapter: on a fast network failure to `direct.adsrvr.org` (e.g. DNS blocked on Safari), retry once on the failover domain `bid-openpath.ttdcdn.org`.
* **Analytics:** The analytics endpoint storage key now includes the calendar month, so a saved endpoint choice expires after one month instead of sticking indefinitely.
* **Config:** Added `dfp.appendNetworkCodeToGTPTag` — when `true`, appends `?network-code=` (from `dfpAccount`) to the GPT `gpt.js` URL so Funding Choices loads via that network; a string value sets the network code explicitly; `false`/omitted leaves the tag unchanged.
* **Refresh:** Fixed refresh `accelerate` using a stale Estimated CPM. The estimated CPM was only updated when GAM filled the slot, so after an empty render the accelerate step still used the CPM of the last filled render and could shorten the refresh with nothing bought. Empty renders now reset it to 0, or to our bid's price when `emptyCreativeFallback` renders it.

## Version 7.29.0 (2026-10-06)

* **Prebid:** Updated to [Prebid.js 11.33.0](https://github.com/prebid/Prebid.js/releases/tag/11.33.0).
* **Prebid:** Fast-Forward prebid PR [15398](https://github.com/prebid/Prebid.js/pull/15398)
* **Targeting:** Fixed empty/no-bid ad units ignoring `wrapper.targetingPrefix` for custom keys (`hb_bd`, `hb_addef`, `hb_acdef`). They now use the configured prefix so they match the keys sent when there is a bid.
* **Analytics Dashboard:** Throws visual error when the API endpoint returns an error.

## Version 7.28.0 (2026-09-29)

* **Prebid:** Updated to [Prebid.js 11.32.0](https://github.com/prebid/Prebid.js/releases/tag/11.32.0).
* **Traffic Integrity:** Take in account if browser is old is likely to be a bot, in combination with other sight will mark it as IVT and higher score
* **Traffic Integrity:** Using Client Hints for Chromium browsers to detect if the User Agent is spoofed.
* **Config:** Enabled `wrapper.firstPartyData` for all wrappers. Testing found no downside to having it on.

## Version 7.27.1 (2026-09-22)

* **Custom scripts:** Fixed a build bug that dropped some utility helpers from the bundle, which stopped custom scripts that used those helpers from running.

## Version 7.27.0 (2026-09-22)

* **Prebid:** Updated to [Prebid.js 11.31.0](https://github.com/prebid/Prebid.js/releases/tag/11.31.0).
* **Rich Media:** Reworked the close button on the adhesion, sticky and peel formats so it is policy compliant — it no longer overlaps the creative, and is clearly visible on any page background and easier to click.
* **Management:** Redesigned the management UI so it matches the look and feel of the rest of the product.
* **Traffic Integrity:** Fixed User ID ingestion
* **Traffic Integrity:** Added a higher score for 12 know datacenters

## Version 7.26.0 (2026-09-15)

* **Analytics:** Traffic Integrity Score dashboard deployed to management.
* **Prebid:** Updated to [Prebid.js 11.30.0](https://github.com/prebid/Prebid.js/releases/tag/11.30.0).
* **Prebid:** Fix ts-strict by typing wrapper auction helpers without typeof auctionManager
* **Brand Safety:** More tells for brand safety block detection (IAS passback creative / ad-blocking explainer).
* **Ads:** Fixed an issue where undefined `mediaTypes` broke ad calls. It now defaults to a 1x1.

## Version 7.25.0 (2026-09-08)

* **Prebid:** Updated to [Prebid.js 11.29.0](https://github.com/prebid/Prebid.js/releases/tag/11.29.0).
* **Traffic Integrity:** The TIS scoring request now includes `userId` — the same 30-day browser identifier already used by analytics. It was omitted from the payload until now, so the endpoint could not tie repeat visits to the same browser.
* **Traffic Integrity:** Added more Relay networks to the whitelist to not mark them as datacenter ASN.
* **Traffic Integrity:** Removed a check that banned WebView
* **SafeFrames:** Synced `biddersNotSafeFramesOk` with Prebid docs (`safeframes_ok: false`). Added `'copper6ssp', 'ezoic', 'mmplus', 'ocm', 'pinelake', 'sonarads', 'synapseHX', 'uniquest_widget'`. Removed `'adsinteractive', 'eclickads', 'mobupps', 'ras'`. Kept rename aliases `'bridgeupp'`, `'minutemediaplus'`, `'uniquestWidget'` alongside the new codes. Case-fixed `'eightPod'` → `'eightpod'`. Kept `'kueezrtb'` (works with Safe Frames despite docs).

## Version 7.24.0 (2026-09-01)

* **Prebid:** Updated to [Prebid.js 11.28.0](https://github.com/prebid/Prebid.js/releases/tag/11.28.0).
* **Builder:** An interrupted precompile pass (for example a custom script that fails to compile) now forces a full recompile on the next build, so a half-written precompiled file can no longer be reused and ship a wrapper with missing `_utils.js` helpers.

## Version 7.23.0 (2026-08-25)

* **Prebid:** Updated to [Prebid.js 11.27.0](https://github.com/prebid/Prebid.js/releases/tag/11.27.0).
* **Builder:** Priority for main wrapper and lower priority of pre-release tasks. Still FIFO.
* **Traffic Integrity:** Improved Chrome detection in Traffic Integrity Score matching to reduce false negatives on genuine Chrome traffic.
* **Traffic Integrity:** Excluded a set of known ASNs from TIS matching to prevent false-positive blocks on legitimate traffic sources.

## Version 7.22.0 (2026-08-18)

* **Prebid:** Updated to [Prebid.js 11.26.0](https://github.com/prebid/Prebid.js/releases/tag/11.26.0).
* **OpenRTB:** Wrapper-built ad units now set `ortb2Imp.secure: 1` so bid requests require HTTPS creatives. A publisher-set `ortb2Imp.secure` (including `0`) is still honored. See [Glossary](/glossary).
* **Prebid:** Fast-Forward prebid PR [15383](https://github.com/prebid/Prebid.js/pull/15383).
* **Traffic Integrity (new):** **Traffic Integrity Score (TIS)** — invalid traffic (IVT) scoring on page load. The wrapper asks a scoring endpoint how likely the visit is to be non-human and receives a score from 0 to 100 (100 = almost certainly a bot). A visit scoring at or above the configured threshold stops the wrapper. Configured with [`wrapper.trafficIntegrity`](/configuration#wrappertrafficintegrity).
* **Traffic Integrity:** **Off by default.** `block` is the switch: until a threshold is set, e.g. `"block": 70`, no scoring request is made and nothing changes for existing sites.
* **Traffic Integrity:** When a visit is blocked, the wrapper stops doing any further ad work: no processing, no bid requests, no GAM requests, and no refreshes. Ads that already rendered are left in place rather than torn down.
* **Traffic Integrity:** The check is asynchronous, so the verdict normally lands before the first auction but is not guaranteed to. Loading of the Google Publisher Tag itself is not prevented; what is prevented is slot definition and auctions.
* **Traffic Integrity:** The scoring request has no timeout and is never cancelled. A slow verdict is applied when it arrives, so it still stops refreshes, lazy-loads and later auctions for the rest of the pageview. Nothing on the page waits for the response, so this costs no page speed.
* **Traffic Integrity:** Fails open by design — a network failure, a malformed response, or no response at all blocks nothing and the wrapper continues normally.
* **Traffic Integrity:** No endpoint configuration and no timeout setting. The URL is derived from the analytics host already used by the build, with `/tis` appended. The wrapper fires no additional analytics event for TIS, and nothing is written to cookies or local storage.
* **Builder:** Added as dependency libraries from prebid when wrapper functionality and custom scripts need it, otherwise things are not loaded in time.
* **Builder:** If dependency is missing or something is wrong with dependency it will fail the build.
* **Builder:** More failure checks and fuller job logs, so a failed build can be diagnosed from the build page without server logs. The job log now shows:
  * the real Git/CDN error when publishing fails
  * the commit code, and whether that commit reached the CDN or is still waiting locally
  * how long the job waited in the queue before it started
  * unexpected crashes written into the job log (not only the server console)
  * the size of the built wrapper file
  * how long the git pull and CDN publish steps took
  * the compile exit code when the wrapper build itself fails
  * the real gist-update error message (it could previously appear as “NaN”)
* **Custom scripts (CRITICAL):** Load-time errors in `custom_*.js` no longer stop the entire wrapper. A throw while the custom file is evaluating is caught, logged as `[wrapper] custom script failed: <filename>`, and that script is skipped. The rest of the wrapper continues. Note: Do **not** call wrapper APIs (`getUserInfo`, `getConfig`, `setConfig`, `aliasBidder`, `onEvent`, and similar) at the top of a custom script. Queue them with `pbjsInstance.cmd.push(function() { ... })`. Top-level calls can run before the wrapper has attached those methods; the custom script will fail and will not run. See [Customization](/customization). Errors inside `cmd.push` / event callbacks are **not** isolated by this change.
* **Custom scripts:** `docReady` moved from a `window.docReady` polyfill in the wrapper bundle to an exported helper in `_utils.js`. **Important:** Do **not** use `window.docReady` anymore — it is no longer defined on `window`. Import it instead: `import { docReady } from '../_utils.js';` then call `docReady(function() { ... })`. Update any custom script or Rich Media module that still references `window.docReady`. See [Customization](/customization).
* **Wrapper:** The wrapper global (`config.globalVar`) and its `cmd` / `que` queues are created at the start of the bundle, before webpack entries and `custom_*.js` files run. Custom scripts that do `window[config.globalVar] || {}` now always get the real instance instead of a detached local object. See [Customization](/customization).
* **Monitors:** HTTP uptime monitors now also track TLS certificate expiry on the configured HTTPS host. When the leaf cert will expire within a per-monitor window (default 7 days), an SSL incident opens, the monitor shows a warning, and the same notification channels as downtime are used. The incident closes and a recovery notice is sent when the cert is renewed beyond that window. The expiry date is shown on the monitor even when no alert is due. HTTP URLs are skipped.

## Version 7.21.0 (2026-08-11)

* **Prebid:** Updated to [Prebid.js 11.25.0](https://github.com/prebid/Prebid.js/releases/tag/11.25.0).
* **Ads:** Duplicate ad container ids on the same page: only the first is processed; extras are skipped and logged.
* **Ads:** When an ad container is removed and replaced with a new DOM node that keeps the same id, the new node is treated as a new placement (new identity), not a continuation of the old one.
* **Ads:** Successfully bound containers are claimed so the same placement is not defined twice.
* **Ads:** If a new container appears with an id that already has a GAM slot, the old GAM definition is destroyed before the new container is set up.
* **Ads:** No publisher markup changes required. Normal refresh and experimental GAM `"redefine"` still apply when the same DOM node stays in place.

## Version 7.20.0 (2026-08-04)

* **Prebid:** Updated to [Prebid.js 11.24.0](https://github.com/prebid/Prebid.js/releases/tag/11.24.0).
* **GAM:** Removed confirmed click penalty (CCP) detection and tracking. GAM no longer exposes `confirmedClickVisible` in ad iframes the way the wrapper relied on, so the `ccp` page targeting key, session storage flag, and `ccp` analytics event have been removed. Remove `"ccp"` from `analytics.track` if present.

## Version 7.19.1 (2026-07-29)

* **Prebid:** Fast-Forward prebid PR [15362](https://github.com/prebid/Prebid.js/pull/15362)

## Version 7.19.0 (2026-07-28)

* **Prebid:** Updated to [Prebid.js 11.23.0](https://github.com/prebid/Prebid.js/releases/tag/11.23.0).
* **Modules:** Added the Prebid `currency` module to the default wrapper modules; it becomes a common asset for all wrappers.
* **GAM:** Updated Google Ad Manager setup to follow Google’s new public config API.
* **Refresh (experimental):** Added `refresh.gamStrategy` (`"refresh"` | `"redefine"`). `"redefine"` recreates the GAM slot on each refresh instead of refreshing the existing one. Not tested in production — leave unset (or `"refresh"`) unless you are evaluating it.
* **SafeFrames:** Fixed `forceSafeFramesForAdunits` when the list is empty — it is now treated as off, so Safe Frames are not considered enabled and bidders are no longer disabled by mistake.
* **SafeFrames:** Fixed Flexible Safe Frames Signal when no bidder, domain, category, or ad unit lists are provided (or they are empty) — the feature stays disabled instead of turning on with nothing to match.
* **Ads:** Fixed house fallback creatives when the size map is empty — it is now treated as off, so the house fallback path does not run with no creatives configured.
* **Analytics:** Fixed analytics tracking when the `track` list is empty — it is now treated as off, so related listeners (such as CSP tracking) are not started unnecessarily.

## Version 7.18.0 (2026-07-21)

* **Prebid:** Updated to [Prebid.js 11.22.0](https://github.com/prebid/Prebid.js/releases/tag/11.22.0).

## Version 7.17.0 (2026-07-14)

* **Prebid:** Updated to [Prebid.js 11.21.0](https://github.com/prebid/Prebid.js/releases/tag/11.21.0).
* **Prebid:** Bid `requestId` / `bidId` values are now always standard UUIDs for client, S2S, and stored-bid injection paths. The wrapper-specific `hw<globalVar>hw` identifier format is reserved for `adId` only, which keeps the render-security gate (`renderAd`, secure-creative messaging) unchanged while making analytics and cross-pageview deduplication unambiguous.
* **Stored bids:** When a cached bid is re-injected into an auction, its `requestId` and `bidderRequestId` are now minted as UUIDs (matching the live client path) instead of wrapper-format strings that looked like `adId` values.
* **Stored bids:** CPM is normalized to a number before a bid is written to localStorage. The currency module can leave converted values as strings (`toFixed(4)`); storing them as numbers fixes floor checks, highest-CPM-first ordering when serving from cache, and targeting comparisons. Bids already in storage with string CPMs are coerced back to numbers on read until they expire.
* **Consent:** Privacy consent is applied earlier on page load, without changing consent settings you already have in place.
* **Debugger:** Removed some noisy, repetitive log messages from the debugger console — high-frequency adapter output is now logged at `details` level only, so it no longer floods the console on every auction.
* **Analytics:** Fixed analytics endpoint retry after a failed POST — the 1-second retry now passes proper success/error callbacks (instead of an empty object). The retry is still a single failover attempt to the alternate endpoint; if that retry also fails, tracking stops instead of looping.
* **Analytics (Alpha):** **Brand Safety Block Detection** (`brandSafetyBlock`) — After each ad render, scans friendly ad iframes (including nested frames) for known brand-safety block placeholders (DoubleVerify clouds, PubMatic PM\_BP\_Block, IAS firewall wipes, GeoEdge and similar). Fires an event and analytics with the vendor, evidence found, and GAM context (advertiser/creative/line item). SafeFrame slots are not scannable.
* **Analytics (Alpha):** **Heavy Ad Intervention** (`heavyAdIntervention`) — Tracks Chrome Heavy Ad Intervention on prebid banner creatives. A snippet injected into each bid reports the intervention (id, message, source) back to the wrapper before the frame unloads, together with bid details. Prebid bids only.
* **Analytics (Alpha):** **Heavy Asset Intervention** (`heavyAssetIntervention`) — Tracks browser interventions on the main page (not inside a creative), e.g. when Chrome intervenes on a third-party script or cookie-sync iframe. Reports intervention id, message, and the URL/source file of the offending asset.

## Version 7.16.0 (2026-07-07)

* **Prebid:** Updated to [Prebid.js 11.20.0](https://github.com/prebid/Prebid.js/releases/tag/11.20.0).
* **Analytics:** CSP tracking improved; de-dupe of fallback tracker events.
* **Build:** Refactored `through2` and `fancyLog` usage to native Node.js streams (`node:stream`) and `gulplog` after upstream removed those packages in 11.20.0.
* **Stored bids:** De-dupe for a cooldown period to address stale renderer for quick auctions
* **Stored bids:** A cached bid is now purged from storage as soon as its creative reaches a terminal render state — `adRenderSucceeded` (status RENDERED), `bidWon`, `staleRender`, `adRenderFailed` or `expiredRender` — so the same `adId` can never be re-served to a later auction/slot. This complements the push cooldown and stops the staleRender flood caused by a rendered/consumed creative being re-injected. The push-cooldown map entry is dropped at the same time.
* **Code style:** Applied Prebid.js ESLint formatting to wrapper modules; no functional changes.

## Version 7.15.0 (2026-06-30)

* **Prebid:** Updated to [Prebid.js 11.18.0](https://github.com/prebid/Prebid.js/releases/tag/11.18.0). See [Prebid 11.0 release notes](https://docs.prebid.org/dev-docs/pb11-notes.html) for upstream breaking changes (removed modules, API changes, viewability overhaul, etc.).
* **Build:** Mass production builds skip some checks to speed delivery.
* **Build:** Fixed bidder metadata so aliases inherit the parent network GVL ID. Networks missing a GVL id on their aliases were throwing errors at build: **mediasquare** (`msq`), **nativery** (`nat`), **oms** (`brightcom`, `bcmssp`), **performax** (`px`), **prisma** (`prismadirect`).
* **oftmedia / Microsoft adapter:** The `oftmedia` bidder has been migrated from the AppNexus adapter to `msftBidAdapter`. Existing wrapper configs were updated in all wrapper config repos: for every site whose `adunits.json` includes `oftmedia`, the script adds `msftBidAdapter` to `modules.json` and renames the bid parameter from `placementId` to `placement_id` (e.g. `{"bidder":"oftmedia","params":{"placement_id":"123456789"}}`). From now on, any new or manual `oftmedia` setup must use `msftBidAdapter` in `modules.json` and the Microsoft parameter names (`placement_id`, not `placementId`).
* **Prebid `auctionOptions`:** The wrapper default prebid config now sets `rejectInvalidMediaTypes: false` and `rejectUnknownMediaTypes: false`. Prebid 11.0 enables stricter media-type validation in core by default; these flags are turned off so existing wrapper behavior is unchanged—bids are not rejected for format mismatches or missing `meta.mediaType` declarations.
* **Prebid `bidResponseFilter`:** Prebid 11.18 added `mediaTypes.enforce` (default `true` upstream) to the `bidResponseFilter` module, alongside existing `cat`, `adv`, and `attr` enforcement. The wrapper keeps all of these defaults permissive (`enforce: false`, `blockUnknown: false`), consistent with version 7.2.0. To enable strict media-type filtering on a site, add under `prebid` in the site config:

```json
"bidResponseFilter": {
  "mediaTypes": {
    "enforce": true
  }
}
```

Optional: set `rejectIbvBannerOnMultiFormat: true` under `mediaTypes` to reject banner bids on multi-format in-banner video ad units (requires `enforce: true`).

* **GPID:** When the same GAM ad unit path (`data-aa-adunit`) appears on a page more than once—as in infinite-scroll or feed layouts—`ortb2Imp.ext.gpid` now receives a stable `#`-suffix uniquifier so DSPs can tell concurrent placements apart. On adunit-mapped pages duplicate slots get an ordinal (`#2`, `#3`, …) while the first occurrence keeps the bare path, and single-slot pages are unchanged. On targeting-mapped pages (`adunitMapping: "targeting"`), where every placement intentionally shares one GAM path and is distinguished by the mapping-key targeting value (`adunitMappingKey`, e.g. `pos`), the gpid instead carries that value as the suffix (e.g. `/123/example.com/apple_section#ATF1`), with a further `-1`, `-2`, … only when the same value genuinely repeats. Each slot’s index is assigned once and cached on the element (`data-aa-gpid-index`) so GPIDs stay consistent across refreshes. In all cases `ortb2Imp.ext.data.adserver.adslot` remains the bare GAM path.
* **Prebid:** Fast-Forward prebid PR [14983](https://github.com/prebid/Prebid.js/pull/14983)

## Version 7.14.0 (2026-06-23)

* **Build:** The wrapper build is now 2–3× faster. It reuses cached results for commonly used files instead of rebuilding everything each time.

## Version 7.13.0 (2026-06-16)

* **Analytics:** Core Web Vitals (`cwv`) sampling can be overridden per site with optional `analytics.cwvSampling` (a number from `0` to `1`). When omitted, the default sample rate remains `0.20` (20%). Enable tracking with `"cwv"` in `analytics.track` as before; set `"cwvSampling": 1` for 100% sampling or `"cwvSampling": 0.10` for 10%. The event name sent to ingestion is unchanged (`cwv`).
* **Device detection:** Refactored `detectWidth`/`detectHeight` for readability and to avoid returning `0` in degenerate frames (e.g. an iframe where `innerWidth` is `0`); device sizing is unchanged for real browsers/devices. Added an error log when more than one `deviceDetection` rule matches the current width (overlapping rules), to help catch misconfigured rules; the last matching rule still wins as before.
* **Scripts:** Migrated formatting and check scripts from the Prebid 9 version to the Prebid 10 version.
* **Prebid:** Fast-Forward prebid PR [15010](https://github.com/prebid/Prebid.js/pull/15010)
* **Prebid:** Fast-Forward prebid PR [14741](https://github.com/prebid/Prebid.js/pull/14741) — `mergeConfig` now notifies only the config topics that were actually merged, instead of re-firing every subscriber (for example `currency`, `s2sConfig`, price floors) on unrelated partial updates such as `mergeConfig({ ortb2: ... })`. This avoids spurious listener side effects during wrapper setup and prevents modules from reacting to config they did not change.
* **Prebid:** Fast-Forward prebid PR [14490](https://github.com/prebid/Prebid.js/pull/14490) — pubstack bid adapter initial release.
* **Prebid:** Fast-Forward prebid PR [14637](https://github.com/prebid/Prebid.js/pull/14637) — Pubstack adapter default values for `ttl` and `netRevenue`.
* **Prebid:** Pubstack adapter — fix for Prebid 10 port: inlined `getAdUnitElement` (Prebid 11-only utility).

## Version 6.95.0 (2026-06-16)

* **Wrapper:** The 6.*.* version is deprecated, this is the last version and was updated only as a fail-safe, but will not be deployed.
* **Prebid:** Fast-Forward prebid PR [15010](https://github.com/prebid/Prebid.js/pull/15010)
* **Prebid:** Fast-Forward prebid PR [14741](https://github.com/prebid/Prebid.js/pull/14741) — `mergeConfig` now notifies only the config topics that were actually merged, instead of re-firing every subscriber (for example `currency`, `s2sConfig`, price floors) on unrelated partial updates such as `mergeConfig({ ortb2: ... })`. This avoids spurious listener side effects during wrapper setup and prevents modules from reacting to config they did not change.

## Version 7.12.0 (2026-06-09)

* **SafeFrames:** Added 'tadvertising\_blis','adnimation','apester','asterio','iprom','logly' to bidders not safe for safe frames
* **Price Floors:** Floor rules now support dynamic schema fields — `country`, `region`, `city`, `os`, `browser`, and `eids` — so publishers can set different floors based on the visitor's geography, device, or identity partners present in the auction. Values are resolved automatically from the enriched request data; no changes to Prebid core required. See [Configuration](/configuration#prebidfloors-dynamic-schema-fields-from-ortb2-wrapper-extension) for field reference and examples.

## Version 6.94.0 (2026-06-09)

* **SafeFrames:** Added 'tadvertising\_blis','adnimation','apester','asterio','iprom','logly' to bidders not safe for safe frames
* **Price Floors:** Floor rules now support dynamic schema fields — `country`, `region`, `city`, `os`, `browser`, and `eids` — so publishers can set different floors based on the visitor's geography, device, or identity partners present in the auction. Values are resolved automatically from the enriched request data; no changes to Prebid core required. See [Configuration](/configuration#prebidfloors-dynamic-schema-fields-from-ortb2-wrapper-extension) for field reference and examples.

## Version 7.11.0 (2026-06-02)

* **Analytics:** `integrityCheck` improve when the event is sent.
* **Migration:** Prepare for full deployment of this version

## Version 6.93.0 (2026-06-02)

* **Analytics:** `integrityCheck` improve when the event is sent.

## Version 7.10.0 (2026-05-26)

* **Console:** Major console update to version 2.0.0.
* **First party data:** OpenRTB `device.geo.type` is set to `2` (IP address) when geo is enriched from IP lookup.
* **Multi-wrapper coexistence:** Bids now carry a distinctive identifier signature reserved for our wrapper, so render and cross-frame messaging from other header-bidding stacks on the same page are recognized as external and courteously ignored—reducing spurious render failures and analytics noise.
* **Analytics:** `integrityCheck` now checks for multiple wrappers on the page.
* **Cookie detection:** The cookie-check helper no longer errors when unrelated browser messages arrive. Cookie detection still works as before.

## Version 6.92.0 (2026-05-26)

* **Console:** Major console update to version 2.0.0.
* **First party data:** OpenRTB `device.geo.type` is set to `2` (IP address) when geo is enriched from IP lookup.
* **Multi-wrapper coexistence:** Bids now carry a distinctive identifier signature reserved for our wrapper, so render and cross-frame messaging from other header-bidding stacks on the same page are recognized as external and courteously ignored—reducing spurious render failures and analytics noise.
* **Analytics:** `integrityCheck` now checks for multiple wrappers on the page.
* **Cookie detection:** The cookie-check helper no longer errors when unrelated browser messages arrive. Cookie detection still works as before.

## Version 7.9.0 (2026-05-19)

* **Analytics:** Integrity checks (`integrityCheck`) now run after pattern blocking so blocked sessions are not reported to analytics.

## Version 6.91.0 (2026-05-19)

* **Analytics:** Integrity checks (`integrityCheck`) now run after pattern blocking so blocked sessions are not reported to analytics.
* **Prebid:** Fast-Forward prebid PR [13934](https://github.com/prebid/Prebid.js/pull/13934)

## Version 7.8.0 (2026-05-12)

* **Console:** Update to version 1.4.3 -> Added RTT (round-trip time) to Core Web Vitals

## Version 6.90.0 (2026-05-12)

* **Console:** Update to version 1.4.3 -> Added RTT (round-trip time) to Core Web Vitals

## Version 7.7.0 (2026-05-05)

* **Prebid:** Minor code cleanup and formatting improvements for better readability
* **Prebid:** Updated comments and alignment; no functional changes

## Version 6.89.0 (2026-05-05)

* **Prebid:** Minor code cleanup and formatting improvements for better readability
* **Prebid:** Updated comments and alignment; no functional changes

## Version 7.6.0 (2026-04-28)

* **Public API:** Added new event `fallbackRenderEnded` that fires when a fallback-rendered creative finishes parsing in its iframe. See the Public API docs for the payload.

## Version 6.88.0 (2026-04-28)

* **Public API:** Added new event `fallbackRenderEnded` that fires when a fallback-rendered creative finishes parsing in its iframe. See the Public API docs for the payload.
* **Prebid:** Fast-Forward prebid PR [14516](https://github.com/prebid/Prebid.js/pull/14516)
* **Prebid:** Reverted -> Fast-Forward prebid PR [14679](https://github.com/prebid/Prebid.js/pull/14679)

## Version 7.5.0 (2026-04-21)

* **Device detection:** Detects device type from screen size in a safer way (no dynamic code execution).

## Version 6.87.0 (2026-04-21)

* **Device detection:** Detects device type from screen size in a safer way (no dynamic code execution).
* **Viewability event:** You can subscribe when the wrapper treats an ad as viewable. Details and field names are in the documentation.
* **Viewability tracking:** The wrapper tracks viewability for all its ad slots after an ad is shown. How viewability-driven refresh works is unchanged; see the documentation if you use that option.
* **Bug fix:** In rare cases a backup ad could load twice in the same slot; that no longer happens.
* **Prebid:** Fast-Forward prebid PR [14679](https://github.com/prebid/Prebid.js/pull/14679)

## Version 7.4.0 (2026-04-14)

* **Port helpers:** if modules do not exist in prebid 10, convert the prebid 9 names.
* **Deployment:** Changed deployment
* **Testing:** Added Creative ID to test bids

## Version 6.86.0 (2026-04-14)

* **Deployment:** Changed deployment
* **Testing:** Added Creative ID to test bids

## Version 7.3.0 (2026-04-07)

* **Bug Fix:** Do not send EID and EID Permissions if bidder is not in the PBS list

## Version 6.85.0 (2026-04-07)

* **Prebid:** Fast-Forward prebid PR [14255](https://github.com/prebid/Prebid.js/pull/14255)
* **Prebid:** Fast-Forward prebid PR [14567](https://github.com/prebid/Prebid.js/pull/14567)
* **Prebid:** Fast-Forward prebid PR [14581](https://github.com/prebid/Prebid.js/pull/14581)
* **Bug Fix:** Do not send EID and EID Permissions if bidder is not in the PBS list

## Version 7.2.0 (2026-03-31)

* **Prebid:** Set yielding to false - In prebid 10, processQueue yields the main browser thread after executing each command in the queue, to improve UX (and some related metrics such as [interaction to next paint](https://web.dev/articles/inp)). This causes high revenue impact , so will disable as default.
* **Console:** Updated console overlay to version 1.4.2, it was behind (1.4.0) compared to the other wrapper version.
* **Bid Filter Module:** Changed the default for enforce and block unknown to false, since now it includes media types in validations, a lot of bids do not declare media types in their meta, so it will block a lot of bids.
* **Viewable provider:** When viewability provider is wrapper, it will not respect MaxEmpty and MaxContinousEmpty settings

## Version 6.84.0 (2026-03-31)

* **Prebid:** Fast-Forward prebid PR [13704](https://github.com/prebid/Prebid.js/pull/13704)
* **Prebid:** Port `magnite` bidder from prebid 10
* **Viewable provider:** When viewability provider is wrapper, it will not respect MaxEmpty and MaxContinousEmpty settings

## Version 7.1.0 (2026-03-24)

* **Analytics:** For staleRender and expiredRender do not track bid.ad since is big and useless
* **Prebid:** Fast-Forward prebid PR [14583](https://github.com/prebid/Prebid.js/pull/14583)

## Version 6.83.0 (2026-03-24)

* **Analytics:** For staleRender and expiredRender do not track bid.ad since is big and useless
* **Prebid:** Fast-Forward prebid PR [14583](https://github.com/prebid/Prebid.js/pull/14583)

## Version 7.0.0 (2026-03-19)

* **Prebid 10:** Updated to prebid 10
* **Build:** Make new build process, to include also typescript and javascript.
* **Build:** Optimize building to take 10-15s instead of 40-60s. Eliminated precompiling useless files.
* **UserId:** Always include userId, most likely every wrapper will need it.
* **Debugging:** Change the top comment for identification; different color to match schema of hbwrapper for debug logging.
* **Prebid 10 Core:** Migrate prebid 9 core features changed for hbwrapper to prebid 10.
* **Test Bids:** Add catId to test bids.
* **Fixes:** Fix bid caching, fix hybrid S2S, fix custom targeting, fix deduplicating user sync.
* **Migration:** Migrate features from Version 6.79.0 onwards that were not included in previous migration.
* **Global Variable:** Fix global variable issue and new way prebid 10 provides it.
* **Bid Adapter:** Convert imds to advertising bid adapter.
* **RTD Module:** Add rtdModule when an rtdModule exists.
* **Targeting:** Change `wvr` key value to value 7 for this version of wrapper for AB testing.

## Version 6.82.0 (2026-03-17)

* **Prebid:** Preparation to migrate to prebid 10

## Version 6.81.0 (2026-03-10)

* **Safe Frames:** Added bidders to the list of bidders that do not support safe frames: 'alchemyx', 'allegro', 'das', 'harrenmedia', 'yaleo'
* **Console:** Updated console overlay to version 1.4.2 with an improved CMP tab summary aligned with the IAB CMP Validator (clearer bullet-list layout, explicit counts for purposes, vendors, and special features) and a dedicated, easy-to-copy `tcString` field.
* **Console Timeline:** Timeline tab now tracks and summarizes resource loads (grouped by initiator type and domain) and allows expanding the underlying resource calls from a single summary row.
* **Debugging:** Cleaned up default console logging output and added a `details` debug mode for verbose, opt‑in logs (enabled via `$$PREBID_GLOBAL$$_debug=DETAILS` or `config.debug = 'details'`).
* **Analytics:** Added persistent tracking identifiers for pageview, session, and user to all analytics events (with session/local storage plus cookie fallbacks and SPA navigation support).
* **Analytics Pageview FPD:** Enriched initial `pageview` analytics event with geo and A/B bucket context (country, city, region, postal code, and `ab.bucket`).

## Version 6.80.0 (2026-03-03)

* **Pattern Blocking:** Improve bot list to cover more known bots.
* **Console:** Updated console overlay to version 1.4.0 and refactored the Troubleshooting tab into three sections (Errors, Warnings, Optimizations) for clearer grouping.
* **Console Troubleshooting:** Enhanced troubleshooting events to include optimization guidance messages that explain issues, impact, and concrete recommendations (e.g. slow wrapper init, slow page load, long auctions, slow GAM responses, slow creatives).
* **CMP / Console:** Send TCF `tcString` to console and display a decoded consent summary in the CMP tab (including policy version, purpose/vendor consents, and delegated vendor presence for TCF 2.3).

## Version 6.79.0 (2026-02-24)

* **Intelligent Bidder Manager:** Removed `intelligentBidderManager` feature and `_intelligentBidderManager.js` module. Config `config.wrapper.intelligentBidderManager` and related behavior (bidder error/timeout tracking, secondary bidders, HTTP request threshold) are no longer supported.
* **Sizes:** Remove shuffling the ad sizes.
* **GAM targeting:** GAM page-level targeting remove `fsize` that was sending the first size in ad request
* **Config:** All schain to prebidSpecific instead of global.
* **GAM:** Added support Pause banner ads for web (Alpha) [Docs](https://support.google.com/admanager/answer/16680235)
* **Targeting:** Added `hb_addef` (Ad Domain Defined) and `hb_acdef` (Advertiser Category Defined). Value is `0` by default; set to `1` when the winning bid has `hb_adomain` (ADOMAIN) or `hb_acat` (ACAT) respectively.

## Version 6.78.0 (2026-02-17)

* **First-party data:** Added `config.wrapper.firstPartyData`. When `true`, enriches ortb2 with data like: geo, IP, carrier, bot score, A/B bucket. NOTICE: In the next release User Info API (`getUserInfo`) and `updateUserInfo` event will be removed from Public API. Can query ortb2 data to pull those info.
* **GAM targeting:** GAM page-level targeting is set with key `ab_bucket` and the bucket value.
* **Bids:** Transform mediafuse placementId in integer for S2S
* **GAM sizes:** Added `forceGAMSizes` and `conditionalForceGAMSizes` (adunit definitions) and `data-aa-force-gam-sizes` (page). When set, GAM slot sizes are forced to these values instead of banner sizes + additional non-HB sizes.

## Version 6.77.0 (2026-02-10)

* **Prebid:** Fast-Forward prebid PR [13527](https://github.com/prebid/Prebid.js/pull/13527)
* **Prebid:** Fast-Forward prebid PR [14001](https://github.com/prebid/Prebid.js/pull/14001)
* **Prebid:** Fast-Forward prebid PR [13671](https://github.com/prebid/Prebid.js/pull/13671)
* **Prebid:** Fast-Forward prebid PR [14119](https://github.com/prebid/Prebid.js/pull/14119)
* **Bid cache:** Reverted the cooldown safeguard, is not needed and in some cases it causes issues
* **Bid cache:** Make sure that stored bids are not added twice into the auction

## Version 6.76.0 (2026-02-03)

* **Console:** Update console to v1.3.1 (If the console doesn't display due to lack of resources, it will try again in 3-4 seconds)
* **Targeting:** Treat `hb_cs` (cache status) and `hb_bd` (bid density) as standard keys (added to `TARGETING_KEYS` and `_prebid_config.json` `allowTargetingKeys`) to avoid mixed current/cached values and ensure consistent GAM targeting.
* **Bid cache:** Added push cooldown safeguard (4 seconds) to prevent the same stored bid from being pushed into multiple auctions before `bidWon` fires.
* **Bid cache:** Handle `QuotaExceededError` when storing bids in localStorage. On quota exceeded, automatically evict expired bids and the 5 oldest cached bids, then retry. If eviction fails or the bid is too large, skip storage and log a warning suggesting to lower `prebid.bidCaching.maxLength`.

## Version 6.75.0 (2026-01-27)

* **Console:** Update console to v1.3.0 (fix disableClientSideAdapters to disableBiddersClientSide)
* **Missing Modules:** fix disableClientSideAdapters to disableBiddersClientSide

## Version 6.74.0 (2026-01-20)

* **Config:** remove misspelled properties in config.json : emtpyCreativeFallback and preViewLenght and deprecated disableClientSideAdapters

## Version 6.73.0 (2025-12-30)

* **Config:** Fixed typo in `lazyLoading.preViewLenght` → `preViewLength` (missing 'n' in "Length");
* **Config:** Fixed typo in `dfp.emtpyCreativeFallback` → `emptyCreativeFallback` (missing 'p' in "empty");
* **Config:** Fixed typo in log message `porviews` → `viewports`;
* **Config:** Added config validation - required properties (`id`, `code`, `globalVar`) now throw errors if missing; added default values for required-with-defaults properties;

## Version 6.72.0 (2025-12-23)

* **Automation:** Added bidders that do not support safe frames to disabled bidders when safe frames are enabled: 'adocean','alvads','ogury','programmaticX','topon','uniquestWidget';
* **Config:** Changed `disableClientSideAdapters` to `disableBiddersClientSide` representing better what it does;

## Version 6.71.0 (2025-12-16)

* **Prebid:** Update prebid to [9.53.5](https://github.com/prebid/Prebid.js/releases/tag/9.53.5)
* **Prebid:** Fast-Forward prebid PR [13775](https://github.com/prebid/Prebid.js/pull/13775)
* **Overlay:** Remove Bid Won from overlay

## Version 6.70.0 (2025-12-09)

* **Prebid:** Update prebid to [9.53.4](https://github.com/prebid/Prebid.js/releases/tag/9.53.4)

## Version 6.69.0 (2025-12-02)

* **Prebid:** Update prebid to [9.53.3](https://github.com/prebid/Prebid.js/releases/tag/9.53.3)

## Version 6.68.0 (2025-11-18)

* **Intelligent bidder manager:** Remove disableBiddersToStorage, now can use Intelligent bidder manager
* **programmaticx :** Fast-Forward programmaticx changes to adapter, PRs: [13549](https://github.com/prebid/Prebid.js/pull/13549)
* **PatterBlocking:** For geo pattern blocking, send the rule as index of the rule, not country code, to be able to report in analytics

## Version 6.67.0 (2025-11-11)

* **msft:** Fast-Forward Microsoft (aka Xandr, AppNexus) Adapter, PRs: [13952](https://github.com/prebid/Prebid.js/pull/13952) [14040](https://github.com/prebid/Prebid.js/pull/14040) [14076](https://github.com/prebid/Prebid.js/pull/14076)
* **IAS:** Do not display slide if is empty
* **IAS:** Added maxEmptySlides to stop adding slides if too many empty slides had been displayed
* **IAS:** Do not display until the ad creative is rendered
* **IAS:** addSlideThreshold default change from 0.8 to 0.7
* **Intelligent bidder manager:** Prioritize bidders that do not throw errors, do not timeout and don't have SRA (dynamic and with TTL)
* **Auction** Count the number of HTTP request for each bidder
* **Bid cache** Fix issue not setting cache bids to multiple adunits on the page

## Version 6.66.0 (2025-11-04)

* **BidCaching:** Fixed issue where lazyloaded or skipped ad units were incorrectly cached.
* **TestBids:** Updated visuals with borders and visible size labels.
* **Geo PatternBlocking:** Added country-level matching index support.
* **Amazon Timeout:** Introduced configurable and default timeout behavior for Amazon.
* **injectAtAuctionInit:** Removed feature due to no measurable improvement.
* **SafeFrame Protection:** Added optional config to disable automatic safeframe protection for unsupported networks.

## Version 6.65.0 (2025-10-28)

* Fix `hb_cs` and `hb_bd`
* Fast-Forward PR [13808](https://github.com/prebid/Prebid.js/pull/13808)
* splitAdUnitsBySizes do not send bids to filter out bids by sizes
* re-designed testbids
* maxLimit=0 and maxLimit=false is different
* option to add cache bids in auction init
* patten blocking remove the enable option (is enabled per rule)
* patter blocking geo block
* added flexible safe frame signal

## Version 6.64.0 (2025-10-21)

* Changed from simple disabling bidders on errors to Intelligent Bidder Error Manager
* Improvements to storage bid cache (Improvement: Adunit-Based Indexing, Auction-Filtered Bid Retrieval, Memory-Cached DOM Queries, Pre-Computed Size Matching, Optimized getBoundingClientRect() Usage, automatic Cleanup System )
* Fast-Forward PR [13572](https://github.com/prebid/Prebid.js/pull/13572)
* Fast-Forward PR [13774](https://github.com/prebid/Prebid.js/pull/13774)
* Added config.wrapper.requestForEachSize

## Version 6.63.0 (2025-10-14)

* Update analytics endpoint to clear cache
* Update IAS tracking

## Version 6.62.0 (2025-10-07)

* Track load time in pageviews
* Track viewport width/height
* Track script count
* Track connection type
* Track ready State

## Version 6.61.0 (2025-09-30)

* Modify and analyze some formatting and check scripts

## Version 6.60.0 (2025-09-23)

* Change pattern blocking to return the matching rule
* Check browser for integrity checks

## Version 6.59.0 (2025-09-16)

* DFP to GAM transition plan

## Version 6.58.0 (2025-09-09)

* Update bidder list that does not support SafeFrames
* Amazon Schain new config instead of global schain

## Version 6.57.0 (2025-09-02)

* Clean fallback renderers that already delivered
* IAS Format - inherit device, sizes, additional sizes, targeting
* Check if device should be skipped before richmedia
* Check lazyloading before container
* Move analytics functionality to a different file so it can be imported
* Shuffle sizes and send key value fsize to see if there is any impact
* Fast-Forward Sevio Bid Adapter: [13529](https://github.com/prebid/Prebid.js/pull/13529), [13633](https://github.com/prebid/Prebid.js/pull/13633), [13729](https://github.com/prebid/Prebid.js/pull/13729)
* Remove hard-coded aliases
* Remove disable bidders query string
* Disable fast click protection
* Refactor Native Functionality
* Disable Native Functionality
* IAS - stored bids work on sequential slides
* IAS - disable for richmedia formats
* Added pattern blocking

## Version 6.56.0 (2025-08-26)

* Make sure KueezRTB S2S doesn't have pId
* Remove unnecessary variables in functions
* Refresh Count and Accelerate Refresh tracking on element instead of GAM adunit
* Improve Amazon refresh declaration
* Faster checks for targeting flags
* Added PageNavigationType Targeting
* Upgrade console to v.1.2.0 (Added Schain Tab)

## Version 6.55.0 (2025-08-19)

* Updated to Prebid 9.53.2.
* Remove preloading of GPT and Amazon
* UserID A/B testing - throw each user ID test into a random bucket
* Infinite Ad Slider Format

## Version 6.54.0 (2025-08-12)

* Own wrapper viewability provider for refresh

## Version 6.53.0 (2025-08-05)

* Updated to Prebid 9.53.1.
* Bid Timeout Troubleshoot message updated to include Prebid Server timeout
* Candent fix aliases issue, fast forward a fix from [13647](https://github.com/prebid/Prebid.js/pull/13647)
* Do not show on page notification if document body is not ready

## Version 6.52.0 (2025-07-29)

* Updated to Prebid 9.52.0.
* Change the size validation to eliminate any entries if the sizes have more than 2 entries
* Updated to console 1.1.0
* Send Troubleshooting messages to console (No Ads, No GPT response, GPT not loaded, Targeting prefix enabled so SafeFrame and S2S disabled, SafeFrames enabled and A9 disabled, Rendering Ad with Fallback Renderer, Cannot render ad with Fallback Renderer due to being a richmedia format, An ad having both timed and viewable refresh, called processing ads without an ad element on page, cannot find a div id for the ad, the div id is not handled by the wrapper, too many adunits into one single call, bidders that timeout, Ad render fail, ad render stale, ad render expired, any auction debug - including bidder failing to reach endpoints or modules not being included)
* Remove hard-coded test pages

## Version 6.51.0 (2025-07-22)

* Updated to Prebid 9.51.0.
* Fast-forwarded Rumble PR: [13543](https://github.com/prebid/Prebid.js/pull/13543).
* Added `hb_rpb` (Ranged Price Bucket) key-value.

## Version 6.50.0 (2025-07-15)

* Updated to Prebid 9.50.0.
* Removed Chrome facilitating testing.
* Topics API is no longer enabled by default, but can still be configured.

## Version 6.49.0 (2025-07-08)

* Updated to Prebid 9.49.1.

## Version 6.48.0 (2025-07-01)

* Updated to Prebid 9.48.0.
* Fixed Gulp version incompatibility.
* Fixed fancyLog migration.
* Fixed PluginError migration.
* Added utility function to show page notifications.
* Implemented page notifications for tracked bids.
* Implemented page notifications for test bids.
* Updated wrapper console version to 1.0.0.
* Console is now specific to the global variable.
* Modified console log styling.
* Removed TopicsAPI A/B Test to Publisher Provided Signals.

## Version 6.47.0 (2025-06-24)

* Updated to Prebid 9.46.0.
* Introduced `userSync.triggerAction` and `userSync.triggerDelay` configurations.

## Version 6.46.0 (2025-06-17)

* Updated to Prebid 9.45.0.
* Updated babel/eslint-parser to version 7.27.5 to fix eslint ^9.x.x incompatibility.
* Fixed polyfill inclusion.
* Disabled babel-caching for webpack.
* Fixed debugging mode due to Prebid 9.45.0 issues; reverted commit \[5a85f82].

## Version 6.45.0 (2025-06-10)

* Updated to Prebid 9.44.1.
* Updated the list of bidders that do not support Safe Frames.

## Version 6.44.0 (2025-06-03)

* Added ACAT to whitelist key values.
* Fixed ACAT handling when an array is returned by bidders (<https://github.com/prebid/Prebid.js/pull/13218>).

## Version 6.43.0 (2025-05-27)

* Updated to Prebid 9.43.0.
* Removed UUID, CACHE\_ID, and CACHE\_HOST values from targeting to prevent S2S bids from being considered in AMP or in-app.

## Version 6.42.0 (2025-05-20)

* Updated to Prebid 9.42.0.
* Ensured UUID starts with a letter to avoid CSS selector problems.
* Implemented tracking for staleRender, expiredRender, and adRenderFailed events.
* Improved bot detection by removing cookie checks and adding invalid/spoof checks.
* Removed deprecated `pbadslot`; deprecation warning for `pbadslot` use; prefer `gpid` (<https://github.com/prebid/Prebid.js/pull/11660>).

## Version 6.41.0 (2025-05-13)

* Updated to Prebid 9.41.0.
* Removed pre-connect bidders and analytics.
* Removed `dfp.adExpansion` as Inventory Rules in GAM now handle this.
* Modified UserSync firing mechanism; now configurable on click, scroll, idle, or timed events.
* Updated CoreWebVitals tracking to v5, addressing breaking changes.
* Prepared for deprecation of `ortb2Imp.ext.data.pbadslot`.

## Version 6.40.0 (2025-05-06)

* Updated to Prebid 9.40.0.
* Improved bot detection by removing screen, webdriver, headless, and touch checks.
* Fixed `ua_bot` in bot detection.

## Version 6.39.0 (2025-04-29)

* Updated to Prebid 9.39.0.
* Prioritized GDPR: if GDPR is set, GPP will not be sent.
* Improved basic bot detection.
* Processed `data-aa-targeting` as string for boolean and number values.

## Version 6.38.0 (2025-04-22)

* Updated to Prebid 9.38.0.

## Version 6.37.0 (2025-04-15)

* Updated to Prebid 9.37.0.

## Version 6.36.0 (2025-04-08)

* Updated to Prebid 9.36.0.

## Version 6.35.0 (2025-04-01)

* Updated to Prebid 9.35.0.
* Improved GPP tracking; removed `MspaOptOutOptionMode` and `MspaServiceProviderMode`.
* Implemented tracking for session winning bids via URL query string.

## Version 6.34.0 (2025-03-25)

* Updated to Prebid 9.34.0.
* Set `userSync.auctionDelay` to 50ms; any value greater than 0 will initialize User IDs before auction, reducing delay impact.
* Increased CMP timeout to 90 seconds.

## Version 6.33.0 (2025-03-18)

* Updated to Prebid 9.33.0.
* Froze PenPal version used in console to fix incompatibility issues.

## Version 6.32.0 (2025-03-11)

* Updated to Prebid 9.32.0.
* Added `prst` key-value.

## Version 6.31.0 (2025-03-05)

* Updated to Prebid 9.31.0.
* Implemented CWV data ingest for A/B test data.

## Version 6.30.0 (2025-02-25)

* Updated to Prebid 9.30.0.
* Implemented analytics tracking for bidder errors.
* Implemented analytics tracking for excessive ads on page.

## Version 6.29.0 (2025-02-18)

* Updated to Prebid 9.29.0.
* Initial release of bot detection and blocking.
* Analytics improvements.

## Version 6.28.0 (2025-02-11)

* Updated to Prebid 9.28.0.
* Changed cache storage for bids from session to local.

## Version 6.27.0 (2025-02-04)

* Updated to Prebid 9.27.0.

## Version 6.26.0 (2025-01-28)

* Updated to Prebid 9.26.0.

## Version 6.25.0 (2025-01-14)

* Updated to Prebid 9.25.0.
* Converted Criteo `networkId` to string for S2S validation.

## Version 6.24.0 (2025-01-07)

* Updated to Prebid 9.24.0.

## Version 6.23.0 (2024-12-31)

* Updated to Prebid 9.23.0.
* Fixed Storage bids.

## Version 6.22.0 (2024-12-24)

* Limited S2S user syncs to 20.
* Added console USP API deprecation notice.

## Version 6.21.0 (2024-12-17)

* Updated to Prebid 9.22.0.
* Ensured `cookiesEnable` does not throw errors for non-stringified JSON messages.
* Ensured key-value mapping uses string values, not arrays.
* Added new CMP console messages.
* Fixed Config page on Console.

## Version 6.20.0 (2024-12-10)

* Updated to Prebid 9.21.0.
* Updated the list of bidders that do not support safe frames.

## Version 6.19.0 (2024-12-03)

* Updated to Prebid 9.20.0.
* Modified and made configurable how Disabled Bidders to Storage works.
* Made `disableBiddersToStorage` configurable.
* Implemented analytics track sampling.
* Implemented tracking for pageviews with no ads.
* Implemented CWV tracking.
* Added Topics API A/B test key values.

## Version 6.18.0 (2024-11-26)

* Updated to Prebid 9.19.0.
* Prevented adding bidders on `bidderError` if it's an S2S request.

## Version 6.17.0 (2024-11-19)

* Updated to Prebid 9.18.0.

## Version 6.16.0 (2024-11-12)

* Updated to Prebid 9.17.0.
* Implemented `pauseOutOfView` at the adunit level.

## Version 6.15.0 (2024-11-05)

* Updated to Prebid 9.16.0.
* Fast-forwarded NextMillennium PR: [12304](https://github.com/prebid/Prebid.js/pull/12304).
* Fixed `hb_bd` and `hb_cs` after targeting update.
* Added failsafe to prevent multiple observations of elements in view.

## Version 6.14.0 (2024-10-29)

* Added new S2S networks.

## Version 6.13.0 (2024-10-22)

* Removed KueezRTB from disabled bidders when safe frame is enabled.
* Added `dfp.houseFallback` configuration.
* Added `targeting.domain` configuration.
* Added `destroy(null,false)` second parameter to prevent element removal.
* Added `targeting.id` configuration.
* Added `targeting.code` configuration.

## Version 6.12.0 (2024-10-15)

* Updated to Prebid 9.15.0.
* Added `config.refresh.pauseOutOfView`.
* Implemented element removal on destroy.

## Version 6.11.0 (2024-10-08)

* Updated to Prebid 9.14.0.
* Added Refreshed Accelerate Seconds Key Value Targeting.
* Implemented Wrapper Version tracking.

## Version 6.10.0 (2024-10-01)

* Updated to Prebid 9.13.0.

## Version 6.9.0 (2024-09-24)

* Updated to Prebid 9.12.0.
* Added new S2S default bidders: "adyoulike", "ix", "iqzone", "mediafuse", "minutemedia", "oms", "richaudience", "rise", "sharethrough", "unruly", "rubicon".

## Version 6.8.0 (2024-09-17)

* Implemented sending IP to bidders as ortb2.
* Implemented tracking for FallbackImpressions with distinct events for `failedToFetchFallback` and `emtpyCreativeFallback`.
* Refactored fallback renderer.
* Refactored refresh queue to prepare for view-only refresh availability.

## Version 6.7.1 (2024-09-11)

* Fixed issue with 3rd party cookie iframe insertion when no body is available.

## Version 6.7.0 (2024-09-10)

* Updated to Prebid 9.11.0.
* Changed `targeting.cookieEnabled` to test cookies from 3rd party domains.
* Added `refresh.continueOnEmpty`.

## Version 6.6.0 (2024-09-03)

* Updated to Prebid 9.10.0.
* Removed `get domain` helper function.

## Version 6.5.0 (2024-08-27)

* Updated to Prebid 9.9.0.
* Added `targeting.cookieEnabled`.
* Removed `targeting.tcf`.

## Version 6.4.0 (2024-08-20)

* Updated to Prebid 9.8.0.
* Added `targeting.refreshedInventory` key-value to track if inventory is refreshed.

## Version 6.3.0 (2024-08-13)

* Updated to Prebid 9.7.0.
* Fast-forwarded PR Fix: [PR 12093](https://github.com/prebid/Prebid.js/pull/12093).

## Version 6.2.0 (2024-08-06)

* Updated to Prebid 9.6.0.
* Changed consent timeout to 1000ms.
* Changed GPP notifications to console.

## Version 6.1.0 (2024-07-30)

* Updated to Prebid 9.5.0.
* Removed S2S timeout from config.

## Version 6.0.0 (2024-07-23)

* Updated to Prebid 9.4.1.
* Updated GPP tracking.
* Remade GeoFilter User ID.
* Increased `maxEntryPoints` for webpack.
* Updated consentModule TCF.
* Removed useless comments from final build.
* Implemented Script Src URL tracking.
* Implemented Conditional Timeout.
* Changed Prebid server config `timeout` to `maxTimeout`.

## Version 5.50.0 (2024-07-16)

* PB9: Hard-coded Topics API Iframes as they will no longer be available ([PR 11579](https://github.com/prebid/Prebid.js/pull/11579)).
* PB9: Prebid Server timeout changed to `maxTimeout` ([PR 11609](https://github.com/prebid/Prebid.js/pull/11609)).
* Changed `timeout` to `maxTimeout`, picking up values from `config.json`.
* PB9: Removed `enrichmentFpdModule` ([PR 11401](https://github.com/prebid/Prebid.js/pull/11401)).
* PB9: Node.js 20+ is now required ([PR 11528](https://github.com/prebid/Prebid.js/pull/11528)); recommending using 20.15.1 LTS.
* PB9: Updated Babel Core to 7.24.6 ([PR 11729](https://github.com/prebid/Prebid.js/pull/11729)).
* Removed deprecated USP (US CMP API) ([IAB USPrivacy](https://github.com/InteractiveAdvertisingBureau/USPrivacy/blob/master/CCPA/US%20Privacy%20String.md#the-us-privacy-signal-has-been-deprecated-as-of-january-31-2024-we-strongly-advise-all-users-of-the-us-privacy-string-to-transition-to-the-global-privacy-platform)).
* PB9: USP consent is no longer sent to bidders ([PR 11407](https://github.com/prebid/Prebid.js/pull/11407)).

## Version 5.49.0 (2024-07-09)

* Cleaned up code.

## Version 5.48.0 (2024-07-02)

* Prepared for Prebid 9.

## Version 5.47.0 (2024-06-25)

* Upgraded to Prebid 8.52.0.
* Added `lazyloadfetchportview` to `setWrapperConfig`.
* Disabled bidders that are not Safe Frame compatible when Safe Frames are enabled.

## Version 5.46.0 (2024-06-18)

* Upgraded to Prebid 8.51.0.
* Fixed automatic disabling of SafeFrames and S2S if a custom prefix is set.
* In `PubProvidedID` module, if no IDs are returned, `undefined` is returned to set correct targeting.
* `PubProvidedID` module now accepts `eidsFunction` as a string in config to execute the window function with that name.

## Version 5.45.0 (2024-06-11)

* Upgraded to Prebid 8.50.0.

## Version 5.44.0 (2024-06-04)

* Upgraded to Prebid 8.49.0.
* Updated webpack to prevent splitting into core-chunk.

## Version 5.43.0 (2024-05-28)

* Upgraded to Prebid 8.48.0.
* Updated console to 0.6.3 version (fixed CWV deleting navigation Types).
* Removed IDWard RTD.
* Removed AdRizer Analytics.

## Version 5.43.0 (2024-05-21)

* Upgraded to Prebid 8.47.0.
* Updated console to 0.6.2 version (added refresh to console, fixed CWV).
* Fixed standalone debugging; reverted hard-coded fix.

## Version 5.42.0 (2024-05-14)

* Upgraded to Prebid 8.46.0.
* Suppressed webpack entrypoint size errors/warnings.
* Added cat3 analytics.

## Version 5.41.1 (2024-05-02)

* Fixed constants for `targetingPrefix`.

## Version 5.41.0 (2024-04-30)

* Upgraded to Prebid 8.45.0 (skipped 8.44.0 due to [PR 11356](https://github.com/prebid/Prebid.js/issues/11356), which affected Safe Frames creatives).

## Version 5.40.0 (2024-04-23)

* Upgraded to Prebid 8.43.0.
* Implemented impression tracking for fallback renderer.
* Enabled suppression of stale renders.
* Disabled safe frames if `targetingPrefix` is set.
* Disabled Amazon if `forceSafeFramesUnderFloor` applies.
* Implemented temporary fix for [Issue 11365](https://github.com/prebid/Prebid.js/issues/11365).

## Version 5.39.0 (2024-04-16)

* Upgraded to Prebid 8.42.0.
* Disabled S2S when a custom targeting prefix is set.

## Version 5.38.0 (2024-04-09)

* Upgraded to Prebid 8.41.0.

## Version 5.37.0 (2024-04-02)

* Upgraded to Prebid 8.40.0.
* Ad Expansion: UI settings are now preserved if not explicitly set.
* Added Taboola endpoint to Topics API.

## Version 5.36.0 (2024-03-26)

* Upgraded to Prebid 8.39.0.
* Added `config.dfp.adExpansion` to configure `googletag.config.PageSettingsConfig_adExpansion`.

## Version 5.35.0 (2024-03-19)

* Upgraded to Prebid 8.38.0.

## Version 5.34.0 (2024-03-12)

* Upgraded to Prebid 8.37.0.
* Added Topics API OpenX Endpoint.
* Added Topics API Onetag Endpoint.
* Updated analytics endpoints.

## Version 5.33.0 (2024-03-05)

* Upgraded to Prebid 8.36.0.
* Disabled creative building for local testing.
* Fast-forwarded PR [11122](https://github.com/prebid/Prebid.js/pull/11122) for Conversant fix.
* Enabled user-agent-client-hints for `enrichmentFpdModule`.
* Fast-forwarded Gulpfile fix [PR 11098](https://github.com/prebid/Prebid.js/pull/11098).

## Version 5.32.0 (2024-02-27)

* Upgraded to Prebid 8.35.0.
* Fast-forwarded PR [11128](https://github.com/prebid/Prebid.js/pull/11128) for Insticator fix.
* Added ImproveDigital caller for Topics API.

## Version 5.31.0 (2024-02-20)

* Upgraded to Prebid 8.34.0.
* Changed UTM targeting from cookies to localStorage.
* Removed cookie helper functions; now using `storageManager` functions.
* Changed `__gads` cookie and targeting to use `storageManager`.
* Removed Liveramp ATS.

## Version 5.30.0 (2024-02-13)

* Upgraded to Prebid 8.33.0.

## Version 5.29.0 (2024-02-06)

* Upgraded to Prebid 8.32.0.
* Added `config.dfp.forceSafeFramesForAdunits`.
* Improved console log parameters for clarity.
* Analytics: tracking referrer for cross-domain iframes as `urlTop`.

## Version 5.28.0 (2024-01-30)

* Upgraded to Prebid 8.31.0.
* Made `topicsapi` key-value configurable.

## Version 5.27.0 (2024-01-23)

* Upgraded to Prebid 8.30.0.
* Sends `topicsapi` GAM key-value based on picked-up Topics API.
* Removed Save Ads functionality (to be rebuilt later).
* Added URL parameter to enable overlays: `$$PREBID_GLOBAL$$Overlay`.
* Removed dependency on cookies for console; now uses localStorage without storing user input.

## Version 5.26.0 (2024-01-16)

* Upgraded to Prebid 8.29.0.
* Enabled Topics API Module.


