Auction Orchestration
Learn how Trusted Server coordinates multiple demand sources in parallel to maximize revenue and minimize latency.
Overview
The auction orchestrator is the core system that manages server-side ad auctions. It launches bid requests to multiple demand providers simultaneously, collects responses, and selects winners.
Key capabilities:
- Parallel execution — Bid requests to all providers launch concurrently using Fastly's
select()API - Strategy-based winner selection — Automatic strategy detection based on configuration
- Mediator support — Optional external mediator for final winner selection and unified floor pricing
- Provider abstraction — Pluggable provider interface for adding new demand sources
- Creative processing — Winning creatives are rewritten to first-party proxy URLs by default, with opt-in sanitization
System Flow (Prebid + APS)
The following diagram shows the full auction flow when both Prebid and APS providers are configured with a mediator:
Architecture
Request Flow
The auction system processes requests through a pipeline of transformations:
POST /auction (AdRequest in Prebid.js format)
│
├─ Parse body → AdRequest { adUnits[] }
├─ Generate EC + fresh user IDs
├─ Convert adUnits → AdSlots with formats and bidder params
├─ Extract device info (User-Agent, geo)
│
▼
AuctionOrchestrator.run_auction()
│
├─ Detect strategy (parallel_only or parallel_mediation)
├─ Launch all providers in parallel via select()
├─ Collect responses as they complete
│
├─[parallel_only]─── Select highest decoded CPM per slot
└─[parallel_mediation]─── Forward decoded-price bids to mediator for final selection
│
▼
Convert OrchestrationResult → OpenRTB 2.x Response
│
├─[sanitize_creatives=true] Strip executable markup
├─[rewrite_creatives=true] Rewrite URLs and inject creative TSJS
├─ Add ext.orchestrator metadata
└─ Set consent and optional EID response headersKey Components
The orchestrator is composed of several modules:
| Module | Path | Purpose |
|---|---|---|
orchestrator.rs | crates/trusted-server-core/src/auction/ | Parallel execution and bid selection |
plan.rs | crates/trusted-server-core/src/auction/ | Provider-plan compilation and validation |
profile.rs | crates/trusted-server-core/src/auction/ | Typed OpenRTB profile policies |
routing.rs | crates/trusted-server-core/src/auction/ | Bidder ownership and provider routing |
openrtb.rs | crates/trusted-server-core/src/auction/ | Shared OpenRTB request and response handling |
provider.rs | crates/trusted-server-core/src/auction/ | AuctionProvider trait and planned provider |
telemetry.rs | crates/trusted-server-core/src/auction/ | Auction event construction |
types.rs | crates/trusted-server-core/src/auction/ | Auction request, response, and bid types |
formats.rs | crates/trusted-server-core/src/auction/ | TSJS and OpenRTB format conversions |
endpoints.rs | crates/trusted-server-core/src/auction/ | HTTP handler for POST /auction |
config.rs | crates/trusted-server-core/src/auction/ | Auction configuration types |
Configuration-first plan
At startup, Trusted Server compiles [auction.providers] and [auction.bidders] through one registry into an immutable AuctionPlan. Provider IDs, endpoints, profile defaults, routes, static extensions, and notification policy are resolved once. The same Arc<AuctionPlan> is shared by the orchestrator and integration registry; request handling does not reinterpret raw provider configuration.
The first version registers three OpenRTB 2.6 profiles in Rust:
standardfor the common banner subset and bounded static extensions;prebid-serverfor PBS request, response, cache, override, and diagnostics behavior; andapsfor APS account/SDK fields, response eligibility, and renderer output.
Each configured provider is an instance of the generic planned OpenRTB path. Multiple instances may select the same profile or endpoint and remain distinct through their provider IDs. The existing adserver_mock mediator stays in a separate static integration path selected by [auction].mediator.
Auction Strategies
The orchestrator automatically selects a strategy based on whether a mediator is configured.
Parallel Only
When no mediator is set, the orchestrator runs all providers in parallel and selects winners by comparing decoded prices directly. This is the simplest strategy.
[auction]
enabled = true
timeout_ms = 2000
[auction.providers.pbs-main]
protocol = "openrtb-2.6"
profile = "prebid-server"
endpoint = "https://prebid.example.com/openrtb2/auction"
routing = "explicit"
[auction.providers.aps-main]
protocol = "openrtb-2.6"
profile = "aps"
endpoint = "https://aps.example.com/e/pb/bid"
routing = "all_eligible"
profile_config = { account_id = "example-aps-account" }
[auction.bidders.example-server]
provider = "pbs-main"
# No mediator — direct price comparisonHow winner selection works:
- Collect bids from all providers.
- Group bids by slot ID.
- Skip bids without a decoded numeric price.
- Select the highest CPM for each slot.
- Apply floor prices and drop winners below the slot's floor.
APS OpenRTB supplies decoded prices, so eligible APS bids participate directly without requiring a mediator.
Parallel Mediation
When a mediator is configured, provider responses are forwarded to the mediator service for final winner selection and unified floor pricing.
[auction]
enabled = true
timeout_ms = 2000
mediator = "adserver_mock" # Enables mediation
[auction.providers.pbs-main]
protocol = "openrtb-2.6"
profile = "prebid-server"
endpoint = "https://prebid.example.com/openrtb2/auction"
routing = "explicit"
[auction.providers.aps-main]
protocol = "openrtb-2.6"
profile = "aps"
endpoint = "https://aps.example.com/e/pb/bid"
routing = "all_eligible"
profile_config = { account_id = "example-aps-account" }
[auction.bidders.example-server]
provider = "pbs-main"
[integrations.adserver_mock]
enabled = true
endpoint = "https://mediator.example.com/mediate"
timeout_ms = 500How mediation works:
- Run all providers in parallel (same as parallel_only).
- Collect all responses.
- Forward bids with decoded numeric prices to the mediator.
- Let the mediator apply policy and choose a winner.
- Restore render/accounting state from the selected source bid.
- Filter any mediator winner without a decoded price.
Mediation is optional for APS. APS reduces to one candidate per impression before mediation so the selected renderer can be restored without same-slot ambiguity.
Providers
Provider Interface
Demand sources implement the async, platform-neutral AuctionProvider. The trait receives an AuctionRequest and AuctionContext, launches a request as a ProviderRequestOutcome, and parses a PlatformResponse into an AuctionResponse. It also supplies capability, timeout, enablement, and platform-backend metadata. Providers that need request-local response state use the context-aware parsing hooks instead of storing mutable state on the shared provider instance.
The orchestrator launches every request before collecting pending responses, so providers can run concurrently without depending on a Fastly-specific API.
Prebid Provider
Transforms auction requests into OpenRTB 2.x format and sends them to a Prebid Server instance.
Request transformation:
AdSlot→ImpwithBanner { format: [Format { w, h }] }- Bidder params from slot config →
ext.prebid.biddermap - EC and fresh user IDs injected into
Userobject - Device info, geo data, and GPC signals included
- Optional Ed25519 request signing (see Request Signing)
Response parsing:
- Bids include decoded
priceas a decimal CPM. - Missing bid dimensions inherit the routed impression size only when that impression has one banner format. Ambiguous or mismatched dimensions are rejected.
- Creative HTML comes from the
admfield. - Winning creative URLs are rewritten to first-party proxy format by default when the
/auctionresponse is assembled. - Per-bidder timing (
responsetimemillis), errors, and warnings are attached as response metadata. response_admissionreports bounded rejected-bid and reason counts without retaining raw bid payloads.- When
debugis enabled, PBS debug payload and per-bid status (bidstatus) are also included.
[auction.providers.pbs-main]
protocol = "openrtb-2.6"
profile = "prebid-server"
endpoint = "https://prebid.example.com/openrtb2/auction"
routing = "explicit"
[auction.providers.pbs-main.profile_config]
debug = false
[auction.bidders.example-server]
provider = "pbs-main"APS Provider
Builds an independent banner OpenRTB request for Amazon Publisher Services.
Request transformation:
- banner
AdSlotformats become secure OpenRTB impressions; ext.accountuses canonicalaccount_id;ext.sdkidentifies the compatible Prebid contract; and- existing page, device, consent, identity, and geo privacy gates are preserved.
Response parsing:
- decoded USD prices compete directly with other providers;
- positive compatible dimensions and an HTTPS
creativeurlare required; - script creatives are rejected before winner selection unless explicitly enabled;
- one candidate per impression is retained deterministically; and
- a minimized typed renderer is preserved instead of creative markup or APS notifications.
[auction.providers.aps-main]
protocol = "openrtb-2.6"
profile = "aps"
endpoint = "https://aps.example.com/e/pb/bid"
routing = "all_eligible"
[auction.providers.aps-main.profile_config]
account_id = "example-aps-account"
debug = false
allow_script_creatives = falseSee APS OpenRTB Integration for rollout and rendering requirements.
AdServer Mock Mediator
An external mediation service that receives decoded-price bidder responses and performs final winner selection. APS prices are already decoded at the provider boundary.
Mediation request format:
{
"id": "auction-123",
"imp": [
{ "id": "header-banner", "banner": { "format": [{ "w": 728, "h": 90 }] } }
],
"ext": {
"bidder_responses": [
{
"bidder": "aps",
"bids": [{ "imp_id": "header-banner", "price": 2.5, "adm": null }]
},
{
"bidder": "prebid",
"bids": [
{ "imp_id": "header-banner", "price": 2.0, "adm": "<html>..." }
]
}
],
"config": { "price_floor": 0.5 }
}
}Mediation response: Standard OpenRTB with decoded prices and selected winners.
[integrations.adserver_mock]
enabled = true
endpoint = "https://your-mediator.example.com/adserver/mediate"
timeout_ms = 500
price_floor = 0.50Data Structures
AuctionRequest
The internal representation of an auction, converted from the incoming AdRequest:
pub struct AuctionRequest {
pub id: String, // UUID
pub slots: Vec<AdSlot>, // Ad placements
pub publisher: PublisherInfo, // Domain, page URL
pub user: UserInfo, // EC ID, fresh ID, consent
pub device: Option<DeviceInfo>, // UA, IP, geo
pub site: Option<SiteInfo>, // Domain, page
pub context: HashMap<String, serde_json::Value>, // Additional metadata
}AdSlot
Represents a single ad placement on the page:
pub struct AdSlot {
pub id: String,
pub formats: Vec<AdFormat>, // Supported sizes
pub floor_price: Option<f64>, // Minimum CPM
pub targeting: HashMap<String, serde_json::Value>, // Key-value targeting
pub bidders: HashMap<String, serde_json::Value>, // Per-bidder params
}Bid
The unified bid format used across all providers:
pub struct Bid {
pub slot_id: String,
pub price: Option<f64>, // Missing prices fail closed
pub currency: String,
pub creative: Option<String>, // APS uses renderer instead of markup
pub adomain: Option<Vec<String>>,
pub bidder: String,
pub width: u32,
pub height: u32,
pub nurl: Option<String>, // Win notification URL
pub burl: Option<String>, // Billing URL
pub renderer: Option<BidRenderer>,
pub metadata: HashMap<String, serde_json::Value>,
}The price field remains optional so missing-price bids fail closed. APS supplies a decoded price and a typed renderer instead of creative HTML; the renderer is retained through direct winner selection and mediation.
OrchestrationResult
The complete result of an auction:
pub struct OrchestrationResult {
pub provider_responses: Vec<AuctionResponse>, // All provider results
pub mediator_response: Option<AuctionResponse>, // Mediator result (if used)
pub winning_bids: HashMap<String, Bid>, // Slot ID → winning bid
pub total_time_ms: u64,
pub metadata: HashMap<String, serde_json::Value>,
}Input and Output Formats
Request Format (TSJS / Prebid.js)
The POST /auction endpoint accepts a Prebid.js-compatible AdRequest:
{
"adUnits": [
{
"code": "header-banner",
"mediaTypes": {
"banner": {
"sizes": [
[728, 90],
[970, 250]
]
}
},
"bids": [
{
"bidder": "appnexus",
"params": { "placementId": 12345 }
}
]
}
]
}Response Format (OpenRTB 2.x)
Auction results are returned in standard OpenRTB format with an ext.orchestrator metadata block:
{
"id": "auction-abc123",
"seatbid": [
{
"seat": "prebid",
"bid": [
{
"id": "bid-1",
"impid": "header-banner",
"price": 2.5,
"adm": "<iframe src=\"/first-party/proxy?tsurl=...&tstoken=sig\">...</iframe>",
"w": 728,
"h": 90
}
]
}
],
"ext": {
"orchestrator": {
"strategy": "parallel_mediation",
"providers": 2,
"total_bids": 3,
"time_ms": 145
}
}
}APS renderer winners use the same OpenRTB response with a typed renderer extension instead of adm:
{
"id": "auction-abc123",
"seatbid": [
{
"seat": "aps",
"bid": [
{
"id": "upstream-aps-bid-id",
"impid": "header-banner",
"price": 2.5,
"w": 728,
"h": 90,
"ext": {
"trusted_server": {
"renderer": {
"type": "aps",
"version": 1,
"accountId": "example-account",
"bidId": "upstream-aps-bid-id",
"tagType": "iframe",
"creativeUrl": "https://creative.example/render",
"aaxResponse": "fictional-base64-envelope",
"width": 728,
"height": 90
}
}
}
}
]
}
]
}For these bids, id preserves APS's upstream bid ID, crid is present only when APS supplies one, and adm is absent. TSJS understands this contract; other /auction consumers must render ext.trusted_server.renderer explicitly.
EC identity is maintained with the ts-ec cookie; auction responses do not emit EC ID headers.
Creative Processing
Winning creatives returned by POST /auction pass through two independent transforms. sanitize_creatives (opt-in, default false) strips executable markup with its inner content. rewrite_creatives (default true) runs an HTML rewriter (lol_html) that converts eligible external resource and click URLs to signed first-party paths, adds data-tsclick, rewrites inline CSS url(...) values, removes bidder-supplied <base> elements, and injects the unified creative TSJS runtime exactly once, whether or not the bidder supplied a <body> element. In every mode, a creative larger than the 1 MiB per-creative cap is rejected and its adm is dropped.
[auction]
sanitize_creatives = false
rewrite_creatives = truesanitize_creatives | rewrite_creatives | Winning-bid adm behavior |
|---|---|---|
false (default) | false | Deliver the creative exactly as the bidder returned it (subject to the size cap). |
true | false | Strip executable markup, then deliver without rewriting. Accepted asset and click URLs remain direct. |
false | true (default) | Rewrite eligible URLs, add click-guard attributes, and inject creative TSJS into the raw bidder markup. Executable markup is preserved. |
true | true | Sanitize first, then rewrite eligible URLs, add click-guard attributes, and inject creative TSJS. |
When sanitization is enabled, scripts, stylesheets, style blocks, forms, event handlers, dangerous URL schemes, and other rejected content are removed together with their inner content — which blanks script-based creatives. Disabling rewriting removes the injected creative runtime and first-party proxy/click mediation from the resulting adm, so the browser may contact third-party hosts without mediation. Sanitizer-accepted hosts are not allowlisted or trusted merely because their URLs remain in the output.
Both settings apply to winning-bid adm in both the shared POST /auction response converter and the production publisher SSAT/page-bids path. The former emits root-relative first-party URLs and injects creative TSJS; the latter emits absolute first-party URLs for its foreign-origin renderer and does not inject that bundle. HTML/CSS returned by /first-party/proxy continues to be rewritten independently. [debug].inject_adm_for_testing adds the diagnostic debug_bid blob and enables a testing-only direct GAM replacement; it does not control whether processed adm is delivered.
Elements handled by the rewrite pass:
| Element | Attributes | Target |
|---|---|---|
<img> | src, data-src, srcset | /first-party/proxy?tsurl=... |
<script> | src | /first-party/proxy?tsurl=... |
<link> | href, imagesrcset | /first-party/proxy?tsurl=... |
<iframe> | src | /first-party/proxy?tsurl=... |
<video>, <audio>, <source> | src | /first-party/proxy?tsurl=... |
<a>, <area> | href | /first-party/click?tsurl=... |
<style>, [style] | url() references | /first-party/proxy?tsurl=... |
SVG <image>, <use> | href, xlink:href | /first-party/proxy?tsurl=... |
The rewrite pass leaves relative URLs and non-network schemes unchanged. When sanitize_creatives is also enabled, sanitization runs first and strips dangerous schemes, so only sanitizer-accepted values reach this pass; with sanitization disabled, the rewriter operates on the raw bidder markup. Domains in the rewrite.exclude_domains config list (supports wildcards like *.cdn.example.com) are also skipped.
Each proxied URL includes a tstoken HMAC signature for tamper protection. See Proxy Signing for details.
Configuration
Full example
[auction]
enabled = true
sanitize_creatives = false # Opt-in; blanks script-based creatives when enabled
rewrite_creatives = true
timeout_ms = 2000
mediator = "adserver_mock"
[auction.providers.pbs-main]
protocol = "openrtb-2.6"
profile = "prebid-server"
endpoint = "https://prebid.example.com/openrtb2/auction"
timeout_ms = 900
routing = "explicit"
[auction.providers.pbs-main.profile_config]
debug = false
test_mode = false
consent_forwarding = "both"
[auction.providers.pbs-main.notifications]
suppress_all = false
suppress_seats = ["example-seat"]
[auction.providers.aps-main]
protocol = "openrtb-2.6"
profile = "aps"
endpoint = "https://aps.example.com/e/pb/bid"
routing = "all_eligible"
[auction.providers.aps-main.profile_config]
account_id = "example-aps-account"
debug = false
allow_script_creatives = false
[auction.bidders.example-server]
provider = "pbs-main"
[integrations.prebid]
enabled = true
timeout_ms = 1000
debug = false
client_side_bidders = ["example-browser"]
external_bundle_url = "https://assets.example.com/prebid/trusted-prebid.js"
[proxy]
allowed_domains = ["assets.example.com"]
[integrations.adserver_mock]
enabled = true
endpoint = "https://mediator.example.com/mediate"
timeout_ms = 500[auction.providers] is a map, not a provider-name list. Each provider ID owns endpoint/backend correlation and telemetry. [auction.bidders] maps each client-visible bidder ID to one provider. The mediator remains a separately registered integration selected by [auction].mediator.
Common provider fields and defaults:
| Field | Default | Meaning |
|---|---|---|
protocol | Required | openrtb-2.6 |
profile | standard | Typed OpenRTB behavior |
endpoint | Required | Fixed absolute HTTPS endpoint |
timeout_ms | Profile default | PBS 1000 ms, APS 800 ms, standard inherits auction timeout |
routing | explicit | explicit, or all_eligible for non-PBS profiles |
profile_config | {} | Profile-owned typed settings |
notifications | No suppression | Common nurl/burl suppression by all bids or returned seats |
APS normally uses all_eligible, which sends every compatible banner slot but never another provider's bidder parameters. explicit providers receive only centrally routed or trusted stored-request demand. The prebid-server profile rejects all_eligible because PBS requires bidder or stored-request demand on each impression.
Provider IDs must match ^[a-z][a-z0-9-]{0,62}$. Bidder IDs are limited to 128 UTF-8 bytes and cannot be the exact reserved browser envelope ID trustedServer. Static standard-profile request_ext and imp_ext objects are each limited to 16 KiB, eight container levels, and 256 keys at one object level. Notification seat lists are limited to 128 unique entries of at most 128 UTF-8 bytes each.
Validation and target capability
Target-independent ts config validate compiles profiles, defaults, routes, endpoints, bounds, signing structure, and mediator selection. Every adapter startup compiles the same plan and then validates backend-name prediction, fan-out capability, and target resource limits. Fastly and Axum allow multi-provider fan-out; Cloudflare and Spin currently reject enabled auctions with more than one provider. Fastly reserves 40 of its default 200 dynamic backend names for non-auction traffic and rejects auction plans whose provider IDs and reachable timeout buckets could require more than the remaining 160.
This tree does not yet have the EdgeZero callback required to run target-aware validation before ts config push --adapter <target> performs remote work. Until that callback lands, startup remains the mandatory target-aware gate.
Timeout behavior
For each provider, Trusted Server uses the smaller of its resolved timeout and the remaining auction budget for launch decisions and OpenRTB tmax. The mediator is not launched after the logical auction budget is exhausted.
No current adapter claims an abortable provider-wide total-request deadline. Already-launched work may complete after the logical budget, and a completed late response can remain eligible. Local decision and delivery also finish after network launch closes, so timeout_ms is not a hard wall-clock ceiling and an auction can exceed it.
Browser Prebid timeout_ms and debug stay under [integrations.prebid] and are independent of all server provider values. Server endpoint, timeout, routes, profile debug/test/overrides/consent, and notification suppression do not belong to the browser integration.
Environment variable overrides
The typed ts config validate, ts config diff, and ts config push flows can override existing scalar leaves. The pinned EdgeZero loader does not create missing leaves or replace arrays, tables, maps, or rules. Existing configs must add rewrite_creatives = true and sanitize_creatives = false before relying on those scalar overrides. Edit and re-push TOML for other values. Provider map keys preserve hyphens, so pbs-main uses the PBS-MAIN segment and needs env shell syntax:
env 'TRUSTED_SERVER__AUCTION__ENABLED=true' \
'TRUSTED_SERVER__AUCTION__REWRITE_CREATIVES=true' \
'TRUSTED_SERVER__AUCTION__SANITIZE_CREATIVES=false' \
'TRUSTED_SERVER__AUCTION__TIMEOUT_MS=2000' \
'TRUSTED_SERVER__AUCTION__PROVIDERS__PBS-MAIN__PROFILE_CONFIG__DEBUG=true' \
'TRUSTED_SERVER__AUCTION__MEDIATOR=adserver_mock' \
ts config validateBefore rolling back to a binary that does not know a creative-processing field, remove that field's non-default value (rewrite_creatives = false or sanitize_creatives = true), push the default-compatible blob, and then roll back. See Configuration for the complete migration, upgrade-sequencing, and rollback guidance.
Floor Prices
Floor prices can be set per-slot in the auction request. The orchestrator enforces floors after winner selection:
- In parallel_only mode: bids below the floor are dropped after selection
- In parallel_mediation mode: the floor is sent to the mediator in
ext.config.price_floor, and also enforced locally as a safety net - Bids without a decoded numeric price are dropped before delivery in both strategies
Error Handling
The orchestrator is designed to be resilient:
- Provider launch failure — The provider records a
launch_failedoutcome and other providers continue. If every eligible provider fails before producing a pending or immediate outcome, direct/auctionexecution returns502 Bad Gateway. Split publisher execution recordsdispatch_failedtelemetry and continues the origin response without bids. - Provider parse failure — If a response can't be parsed, an
AuctionResponse::error()is recorded. Other results are unaffected. - No providers configured — Completes as a no-bid without provider I/O.
- No provider produces a valid bid — Returns an empty
OrchestrationResultwith zero winning bids after recording provider outcomes. - Mediator returns bids without decoded prices — Those bids are filtered out with a warning.
Observability
Logging
The auction system logs at multiple levels throughout execution:
| Level | Examples |
|---|---|
info | Auction request received, provider launch, bid counts, winner selection, total timing |
debug | Bid-drop reasons, mediation restoration notes, creative processing mode and byte counts |
warn | Provider launch failures, parse failures, mediator bids without decoded prices |
Response Metadata
Every auction response includes structured metadata in ext.orchestrator:
{
"strategy": "parallel_mediation",
"providers": 2,
"total_bids": 3,
"time_ms": 145
}SSAT HTML Debug Comment
For local server-side auction template (SSAT) investigation, Trusted Server can insert a <!-- ts-debug: ... --> comment before the page's bids script. Enable it in trusted-server.toml, push the local configuration, restart the local server, and search the page source for ts-debug:
[debug]
auction_html_comment = true
[debug.auction_html_comment_options]
include_provider_responses = true
include_mediator_response = false
include_bids = false
verbosity = "full"
format = "pretty"ts config validate
ts config push --adapter fastly --local
fastly compute serveThis example is useful when investigating raw Prebid Server requests and responses without spending the dump budget on winning creatives. Raw PBS debug.httpcalls and resolvedrequest metadata also require debug = true under [auction.providers.<id>.profile_config] for the relevant Prebid Server provider.
| Option | Default | Behavior |
|---|---|---|
include_provider_responses | true | Include the provider response array |
include_mediator_response | true | Include the mediator response when a mediator ran |
include_bids | true | Include bid objects; when false, provider status and metadata remain |
metadata_keys | error_type, http_status, message | Subset of the fixed validated keys; gates them in redacted and upstream, ignored in full |
verbosity | redacted | Select redacted, upstream, or full sensitivity |
format | compact | Use compact outer JSON or indented outer JSON with pretty |
metadata_keys is a subset selector against a fixed allowlist — error_type, http_status, and message — never a way to add keys. Any other entry fails config load rather than being silently ignored.
The verbosity modes form an explicit sensitivity ladder:
redactedreconstructs only validatederror_type,http_status, and a server-generatedmessage, intersected withmetadata_keys. A successful provider response can therefore havemetadata: {}.upstreamadds provider-controlled errors, warnings, response timings, bid statuses, and bounded upstream-message fields. It builds on the redacted metadata, sometadata_keysstill gates the three validated keys, while the provider diagnostics are unlocked byverbosityalone. It does not include raw PBShttpcallsorresolvedrequest.fullincludes raw response metadata and untruncated creatives, ignoringmetadata_keysentirely. It can expose IP addresses, geo data, identifiers, consent strings, request signatures, and complete provider request/response bodies.
format = "pretty" indents only the outer dump. JSON-looking fields such as requestbody and responsebody remain strings exactly as captured, so their contents still appear escaped. Use a local JSON inspection tool when those nested values need additional formatting.
The summary line's winning=N count is computed before section filtering, so it can be nonzero while include_bids = false produces empty bid arrays. Every mode and format neutralizes HTML-comment terminators and enforces a 256 KiB total dump cap. A capped dump ends with …(truncated N bytes) and is no longer valid JSON.
Local debugging only
Do not enable the auction HTML comment in production. Even redacted can contain bid-level data and creative previews, while upstream and full may expose identity-bearing request data to anyone who can view the page source.