-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathtrusted-server.example.toml
More file actions
556 lines (518 loc) · 25.8 KB
/
Copy pathtrusted-server.example.toml
File metadata and controls
556 lines (518 loc) · 25.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
# =============================================================================
# Trusted Server — application configuration template
# =============================================================================
#
# This is the source-controlled starting point for an operator-owned
# `trusted-server.toml`. Copy it (`ts config init`), fill in the required
# values, and push it (`ts config push`) as an EdgeZero app-config blob.
#
# Only three sections are REQUIRED for the server to start and pass validation:
# 1. [[handlers]] covering /_ts/admin (admin authentication)
# 2. [publisher] (domain + origin)
# 3. [ec] passphrase (Edge Cookie identity secret)
#
# Everything below those is OPTIONAL. Most optional blocks are commented out —
# uncomment and edit one to enable it — but a few integrations are kept as active
# `enabled = false` stubs (see the Integrations section for why). All example
# hosts use `example.com`; replace them with your real endpoints in your private
# config, not in this template.
#
# `TRUSTED_SERVER__` env vars can override values when the `ts` CLI builds and
# validates this config for push (e.g. TRUSTED_SERVER__PUBLISHER__DOMAIN=...;
# nested keys use `__`). The overlay only replaces SCALAR leaves that already
# exist in the parsed TOML: a commented-out or absent key is silently ignored,
# and arrays or tables must be edited in TOML directly, not via env vars. The
# deployed runtime reads the pushed config blob, so these env vars do not change
# live behavior on their own.
# =============================================================================
# -----------------------------------------------------------------------------
# REQUIRED — Admin authentication
# -----------------------------------------------------------------------------
# HTTP Basic-auth handler(s). At least one handler whose `path` regex covers
# the /_ts/admin endpoints is mandatory; startup fails without it. Each handler
# needs a non-placeholder username/password (deploy validation rejects the
# sample password below).
[[handlers]]
# Regex matched against the request path. This one guards the admin surface.
path = "^/_ts/admin"
username = "admin"
password = "replace-with-admin-password-32-bytes"
# You can add more handlers to basic-auth-protect other path prefixes. The
# sample password below is a known placeholder that deploy validation rejects,
# so it forces a real secret before push:
# [[handlers]]
# path = "^/secure"
# username = "user"
# password = "replace-with-admin-password"
# -----------------------------------------------------------------------------
# REQUIRED — Publisher / origin
# -----------------------------------------------------------------------------
[publisher]
# Public domain Trusted Server is fronting.
domain = "example.com"
# Cookie scope for first-party identity cookies (leading dot = include subdomains).
cookie_domain = ".example.com"
# Upstream origin to proxy publisher content from. No trailing slash.
origin_url = "https://origin.example.com"
# HMAC secret for signing first-party proxy URLs. Replace before deploying.
proxy_secret = "change-me-proxy-secret"
# Optional: override the outbound Host header sent to origin_url.
# origin_host_header_override = "www.example.com"
# Optional: max bytes buffered when a response is post-processed in full (HTML
# rewriting/injection) instead of streamed. Default 16 MiB; larger responses
# return 502. Raise for deployments serving very large publisher pages.
# max_buffered_body_bytes = 16777216 # 16 MiB
# -----------------------------------------------------------------------------
# REQUIRED — Edge Cookie (EC) identity
# -----------------------------------------------------------------------------
[ec]
# Secret used to derive EC identifiers. Must be >= 32 chars and non-placeholder
# in production (deploy validation rejects known placeholders).
passphrase = "trusted-server-placeholder-secret"
# KV store that persists EC identity state. This is the physical store name
# bound per adapter (e.g. `ec_identity_store` in fastly.toml); edgezero.toml's
# logical KV id is `trusted_server_kv`.
ec_store = "ec_identity_store"
# Max concurrent partner pull-sync requests.
pull_sync_concurrency = 3
# Optional cluster-heuristic tuning (defaults shown):
# cluster_trust_threshold = 10 # entries with cluster_size <= this are individual users
# cluster_recheck_secs = 3600 # re-evaluate cluster_size after this many seconds
# Optional identity partners (SSP/DSP/identity vendors). Each needs a real,
# non-placeholder api_token (>= 32 bytes) at deploy. Configure real partners via
# private config, not this template.
# [[ec.partners]]
# name = "Example Partner"
# source_domain = "partner.example.com"
# OpenRTB source.atype (default 3); vendor-specific values are supported
# (PAIR uses 571187).
# openrtb_atype = 3
# include this partner's UIDs in auction user.eids
# bidstream_enabled = true
# api_token = "replace-with-partner-api-token-32-bytes-minimum"
# batch_rate_limit = 60 # max batch-sync requests/min (default 60)
# pull_sync_enabled = false # default false
# =============================================================================
# OPTIONAL — Core features (disabled/omitted by default)
# =============================================================================
# Custom headers added to every response (e.g. X-Robots-Tag: noindex).
# [response_headers]
# X-Robots-Tag = "noindex"
# Sign outbound OpenRTB/API requests. These are platform management-API store
# IDs used for key-rotation WRITES; the runtime reads keys from fixed store names
# (`jwks_store` / `signing_keys`), not these. To keep signing OFF, leave this
# whole block commented out. If you uncomment it - even with `enabled = false` -
# both store IDs are required and must be REAL values: the key rotate/deactivate
# admin routes read them regardless of `enabled`, so deploy validation rejects
# the placeholders below (replace them before pushing).
# [request_signing]
# enabled = false
# config_store_id = "<management-config-store-id>"
# secret_store_id = "<management-secret-store-id>"
# First-party HTML/CSS rewriting controls.
# [rewrite]
# Domains left as-is (not proxied/rewritten). Supports "*.example.com" wildcards.
# exclude_domains = ["*.cdn.example.com"]
# Tester-cookie endpoints: GET /_ts/set-tester sets ts-tester=true and
# GET /_ts/clear-tester clears it on publisher.cookie_domain.
# [tester_cookie]
# enabled = false
# Consent forwarding. All values below are the defaults — uncomment to override.
# [consent]
# mode = "interpreter" # "interpreter" (decode + forward) or "proxy" (raw passthrough)
# check_expiration = true # check TCF consent freshness
# max_consent_age_days = 395 # max age before consent is treated as expired (~13 months)
#
# [consent.gdpr]
# applies_in = ["AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","IS","LI","NO","GB"]
#
# [consent.us_states]
# privacy_states = ["CA","VA","CO","CT","UT","MT","OR","TX","FL","DE","IA","NE","NH","NJ","TN","MN","MD","IN","KY","RI"]
#
# [consent.us_privacy_defaults]
# notice_given = true # has the publisher shown CCPA notice?
# lspa_covered = false # is the publisher subject to LSPA?
# gpc_implies_optout = true # should Sec-GPC: 1 trigger opt-out?
#
# [consent.conflict_resolution]
# mode = "restrictive" # "restrictive" | "newest" | "permissive"
# freshness_threshold_days = 30
# Proxy behavior and first-party asset routing. Kept active with defaults.
[proxy]
# Verify TLS certs when proxying to HTTPS origins (default true; false only for
# local self-signed dev).
# certificate_check = true
# Allowlist for first-party proxy redirect destinations (SSRF guard). Supports
# exact ("example.com") and wildcard ("*.example.com", also matches apex).
# REQUIRED to include the Prebid external_bundle_url host when Prebid is enabled.
# allowed_domains = ["ads.example.com", "assets.example.com", "*.cdn.example.com"]
#
# Route first-party asset paths to a different backend origin. Longest matching
# prefix wins; only GET/HEAD participate; query string is preserved.
# [[proxy.asset_routes]]
# prefix = "/.image/"
# origin_url = "https://assets.example.com"
# Optional path rewrite before sending upstream (the prefix must match what the
# pattern expects — here both use `/.image/`):
# path_pattern = "^/\\.image/(.*)/[^/]+\\.([^/.]+)$"
# target_path = "/image/upload/$1.$2"
#
# Optional S3 SigV4 auth for a private origin:
# [proxy.asset_routes.auth]
# type = "s3_sigv4"
# region = "us-east-1"
# origin_query = "strip"
# secret_store = "s3-auth"
# access_key_id = "access_key_id"
# secret_access_key = "secret_access_key"
#
# Optional Fastly Image Optimizer for the route (references a profile_set below):
# [proxy.asset_routes.image_optimizer]
# enabled = true
# region = "us_east"
# profile_set = "default_images"
# Reusable Fastly Image Optimizer profile sets referenced by asset routes.
# Supported IO params are a strict subset: quality, resize-filter, format,
# width, height, crop. Keep production profile tables in private config.
# [image_optimizer.profile_sets.default_images]
# base_params = "quality=70&resize-filter=bicubic"
# default_profile = "default"
# unknown_profile = "use_default" # "use_default" or "reject"
# profile_param = "profile"
#
# [image_optimizer.profile_sets.default_images.profiles]
# default = "width=1920"
# thumbnail = "width=150&crop=1:1,smart"
# medium = "format=auto&width=828"
# Operator-controlled cache header policies for static/rehosted assets. Disabled
# rules never match, and matcher/policy validation is deferred until a rule is
# enabled; IDs must be non-empty and unique. Keep rules disabled unless the
# matched publisher paths are known to be content-addressed.
# [[cache.asset_rules]]
# id = "nextjs-static"
# enabled = false
# preset = "nextjs-static" # built-in matcher/policy preset
# visibility = "public"
# browser_ttl_seconds = 31536000
# edge_ttl_seconds = 31536000
# immutable = true
#
# [[cache.asset_rules]]
# id = "publisher-fingerprinted-assets"
# enabled = false
# path_globs = ["/assets/**/*.js", "/assets/**/*.css", "/assets/**/*.png", "/assets/**/*.webp"]
# Immutable custom rules require an unambiguous fingerprint_style, either "hex"
# or "esbuild-base32". "vite-base64-url" is allowed only for non-immutable rules
# because ordinary filenames can match its shape.
# fingerprint_style = "hex"
# visibility = "public"
# browser_ttl_seconds = 31536000
# edge_ttl_seconds = 31536000
# immutable = true
# Server-side auction. Provider/mediator names must match enabled integrations.
# Kept active with the creative-processing leaves present so the EdgeZero
# environment override can apply to them.
[auction]
enabled = false
# Rewrite winning-bid creative HTML to first-party endpoints (default true). Set
# false to skip proxy/click-URL conversion and creative TSJS injection.
# Sanitization is controlled separately by `sanitize_creatives` below. Restore
# true before rolling back to an older binary that rejects unknown fields.
rewrite_creatives = true
# Strip executable markup (script/object/embed/form/...) from winning-bid adm,
# removing those elements together with their inner content. Defaults to false
# (executable markup preserved). Note that with `rewrite_creatives = true` the
# adm is still not untouched: eligible URLs are rewritten, bidder `<base>`
# elements are removed, and the creative TSJS runtime is injected. Enable it
# whenever creatives can render in a context that shares the publisher origin
# (its primary defence there); leave it off when creatives render in a
# foreign-origin frame (e.g. the Prebid Universal Creative inside the ad
# server's iframe), since it removes script-based creatives entirely and would
# blank slots on a script-heavy demand stack.
sanitize_creatives = false
providers = []
timeout_ms = 2000
# mediator = "adserver_mock" # optional mediator integration
# Context keys the JS client may forward into auction requests (allowlist;
# empty blocks all).
allowed_context_keys = []
# Server-side ad slot templates + creative-opportunity auction. Kept active.
[creative_opportunities]
# Set false to disable server-side ad templates while keeping slot definitions
# and direct POST /auction callers. Structurally inactive templates fall back to
# the browser-only `Cache-Control: private, max-age=60` policy (this is one
# cause of it). Origin private/no-store policies, and bot/prefetch/consent-denied
# requests, retain their origin policy; CDN-specific cache headers are unchanged.
# Restore true, re-push, and finalize before rolling back to a binary that
# predates this setting.
enabled = true
gam_network_id = "123456789"
price_granularity = "dense"
# FCP is not affected by this value — body content above </body> has already
# streamed and painted before the hold begins. What this caps is the slip on
# DOMContentLoaded and window.load. 500 ms is the recommended default; raise
# only if your SSPs need more headroom and analytics confirm the DCL slip is OK.
auction_timeout_ms = 500
#
# Initial-page delivery mode (spike/experimental). `inline` is the default and
# current production behaviour; `esi` is an opt-in Fastly Core Cache experiment
# storing an inert comment in a shared, reader-neutral template cache. See
# docs/guide/configuration.md before enabling. This and the three cache-safety
# keys below belong in this [creative_opportunities] table.
# assembly_mode = "inline"
# Request headers (besides Accept-Encoding) the origin may name in Vary. Every
# emitted Vary name must be covered here or template storage is refused. Never
# include Cookie — shared templates must be reader-neutral.
# template_cache_vary = [
# "rsc",
# "next-router-state-tree",
# "next-router-prefetch",
# "next-router-segment-prefetch",
# ]
# Safety ceiling (seconds) for one shared template; TS uses the smaller of this
# and the origin-authorized remaining edge freshness. Default 60; range 1-86400.
# template_cache_max_age_seconds = 1200
# Unsafe unless independently verified: excludes cookie-bearing requests from the
# template cache by default. Set true only when origin HTML is byte-independent
# of Cookie; an origin `Vary: Cookie` is still refused.
# origin_is_cookie_independent = false
#
# `gam_unit_path` may be a template. Supported placeholders:
# {network_id} -> gam_network_id
# {slot_id} -> the slot's id
# {section} -> a path segment of the request, sanitized to [A-Za-z0-9_-];
# `section_segment` picks which one, `section_root` covers
# paths that have no such segment.
# A template with no placeholders (or an absent gam_unit_path) keeps the old
# behavior: verbatim path, or the default `/<network_id>/<slot_id>`.
#
# `section_root` is REQUIRED when any slot's template uses {section}. There is no
# default - the home-section name is publisher-specific. Must be [A-Za-z0-9_-]+.
#
# `section_segment` is the 0-based index of the segment that names the section;
# it defaults to 0 (the first segment). Set it to 1 for locale-prefixed URLs, so
# "/en/news/article" resolves to "news" instead of "en".
#
# Both are left commented out: no slot below uses {section}, and an unused key
# still ships in the pushed config blob.
# section_root = "home"
# section_segment = 0
#
# Slot templates. Add one block per slot below. (This is an array of tables, so
# the env overlay cannot set it - edit the `[[creative_opportunities.slot]]`
# blocks in TOML directly.)
# [[creative_opportunities.slot]]
# id = "leaderboard"
# gam_unit_path = "/123456789/leaderboard"
# div_id = "div-gpt-ad-leaderboard"
# page_patterns = ["/"] # glob syntax (not regex); "/" matches only the homepage
# formats = [{ width = 728, height = 90 }]
#
# Example templated slot (one rule serves every section). Uncomment
# `section_root` above when enabling it. Note that "/news/*" does not match
# "/news" - list the section landing page separately.
# [[creative_opportunities.slot]]
# id = "ad-header"
# gam_unit_path = "/{network_id}/example/{section}"
# page_patterns = ["/", "/news", "/news/*", "/reviews", "/reviews/*"]
# formats = [{ width = 728, height = 90 }]
# "/" -> /123456789/example/home
# "/news" -> /123456789/example/news
# "/news/x" -> /123456789/example/news
# "/reviews/y" -> /123456789/example/reviews
# Direct Tinybird auction telemetry (off by default). When enabled, `api_host`
# is required and must be a bare host (no scheme or path).
# [tinybird]
# enabled = true
# api_host = "api.us-east.tinybird.example" # required when enabled; host only
# secret_store = "ts_secrets" # Secret Store holding the append token
# auction_dataset = "auction_events" # Events API datasource name
# auction_token_secret = "tinybird_auction_append_token" # Secret Store key for the token
# Debug endpoints (all default false — never enable in production).
# [debug]
# Exposes GET /_ts/debug/ja4 returning TLS/JA4 fingerprint details. Disable
# after investigation; it reflects data browser JS cannot normally read.
# ja4_endpoint_enabled = false
# Injects a `<!-- ts-debug: ... -->` auction dump before `</body>`. NEVER enable
# in production: even the default "redacted" mode still includes bid-level fields
# and creative previews — it is not a fully anonymized dump.
# auction_html_comment = false
#
# Fine-grained control over the dump (all optional; defaults shown).
# [debug.auction_html_comment_options]
# include_provider_responses = true
# include_mediator_response = true
# include_bids = true
# Subset of the fixed validated metadata keys shown in "redacted" (and, for these
# three keys, "upstream") mode. Any other key fails config load.
# metadata_keys = ["error_type", "http_status", "message"]
# "redacted" (default), "upstream", or "full". "upstream" exposes six untyped
# provider diagnostic values that may contain request or identity data; "full"
# additionally exposes all response metadata and untruncated creatives. Never use
# either sensitive mode in production.
# verbosity = "redacted"
# "compact" (default) or "pretty"; pretty formats only the outer dump, JSON
# request/response bodies remain strings exactly as captured.
# format = "compact"
# =============================================================================
# OPTIONAL — Integrations
# =============================================================================
# Every integration is off by default. Most are fully commented out; uncomment a
# block and set `enabled = true` to activate it. Four (gpt, didomi, datadome,
# google_tag_manager) are kept as active `enabled = false` stubs so the `ts audit`
# CLI can flip them in place — leave those sections present. Integrations whose
# `enabled` defaults to true (prebid, permutive, lockr, ...) still stay OFF while
# their section is commented out. Required fields are noted per block.
# =============================================================================
# Prebid Server-side auction + first-party Prebid.js bundle.
# When enabled: `server_url` is required, and `external_bundle_url` is required
# (its host must be listed in [proxy].allowed_domains). Kept active but disabled.
[integrations.prebid]
enabled = false
server_url = "https://prebid.example.com/openrtb2/auction"
timeout_ms = 1000
bidders = []
debug = false
client_side_bidders = [] # bidders running via native Prebid.js adapters
# Keep selected GAM inventory out of Trusted Server's Prebid refresh auctions.
# Matching slots still refresh through GAM.
# excluded_gam_ad_unit_path_suffixes = ["/trackingonly"]
# Runtime bundle metadata — set after running `ts prebid bundle` and uploading:
# external_bundle_url = "https://assets.example.com/prebid/trusted-prebid-<sha256>.js"
# external_bundle_sha256 = "<manifest sha256>"
# external_bundle_sri = "<manifest sri>"
# Per-bidder / per-zone param overrides (canonical rule form):
# [[integrations.prebid.bid_param_override_rules]]
# when.bidder = "examplebidder"
# when.zone = "header"
# set = { placementId = "_abc" }
#
# Bundle build inputs consumed by the `ts prebid bundle` CLI (not the runtime):
# [integrations.prebid.bundle]
# adapters = ["rubicon"]
# user_id_modules = ["sharedIdSystem"]
# Next.js first-party rewriting for App Router / RSC payloads.
# [integrations.nextjs]
# enabled = true
# rewrite_attributes = ["href", "link", "siteBaseUrl", "siteProductionDomain", "url"]
# max_combined_payload_bytes = 10485760 # 10 MiB
# Testlight OpenRTB test integration. `endpoint` required when enabled.
# [integrations.testlight]
# enabled = true
# endpoint = "https://testlight.example.com/openrtb2/auction"
# timeout_ms = 1200
# rewrite_scripts = true
# Didomi CMP SDK/API first-party proxy. Kept active but disabled so `ts audit`
# can flip `enabled` to true when Didomi is detected on the audited page.
[integrations.didomi]
enabled = false
# sdk_origin = "https://sdk.example.com"
# api_origin = "https://api.example.com"
# Sourcepoint CMP first-party proxy.
# `cdn_origin` is intentionally omitted: the upstream CDN origin is pinned to
# Sourcepoint's own host and is not operator-selectable. Leave it unset so the
# validated default applies — overriding it with any other host fails config
# validation.
# [integrations.sourcepoint]
# enabled = true
# rewrite_sdk = true
# cache_ttl_seconds = 3600
# auth_cookie_name = "sp_auth" # optional: forward a custom authCookie upstream
# Osano consent management (proxy toggle only).
# [integrations.osano]
# enabled = true
# Permutive DMP. `organization_id` and `workspace_id` required when enabled.
# [integrations.permutive]
# enabled = true
# organization_id = "your-permutive-organization-id" # required (non-empty)
# workspace_id = "your-permutive-workspace-id" # required (non-empty)
# project_id = "your-permutive-project-id"
# api_endpoint = "https://api.example.com"
# secure_signals_endpoint = "https://secure-signals.example.com"
# lockr identity SDK. `app_id` required when enabled.
# [integrations.lockr]
# enabled = true
# app_id = "your-lockr-app-id" # required (non-empty)
# api_endpoint = "https://identity.example.com"
# sdk_url = "https://identity.example.com/trusted-server.js"
# cache_ttl_seconds = 3600
# rewrite_sdk = true
# DataDome bot protection. Proxies tags.js + signal-collection API first-party.
# Kept active but disabled so `ts audit` can flip `enabled` when detected.
[integrations.datadome]
enabled = false
# sdk_origin = "https://sdk.example.com"
# api_origin = "https://api.example.com"
# cache_ttl_seconds = 3600
# rewrite_sdk = true
# Server-side Protection API validation (fails open on timeout/error):
# enable_protection = false
# server_side_key_secret_store = "ts_secrets"
# server_side_key_secret_name = "datadome_server_side_key"
# protection_api_origin = "https://api.example.com"
# timeout_ms = 1500
# protection_excluded_methods = ["OPTIONS"]
# Client-side tag auto-injection (emits only when client_side_key is non-empty):
# client_side_key = ""
# inject_client_side_tag = true
# client_side_tag_url = "/integrations/datadome/tags.js"
# Temporary static-header bypass for an access-controlled STAGING environment
# only. A matching `x-ts-datadome-bypass` header skips server-side Protection
# API validation and is stripped before the origin sees it. The credential is
# loaded from the Secret Store at runtime (>= 32 bytes of high-entropy material).
# Never enable in production.
# [integrations.datadome.protection_test_bypass]
# enabled = true
# credential_secret_store = "ts_secrets"
# credential_secret_name = "datadome_protection_test_bypass"
# Google Publisher Tag (GPT) first-party proxy. Kept active but disabled so
# `ts audit` can flip `enabled` to true when GPT is detected.
[integrations.gpt]
enabled = false
# Kept as an active leaf so the environment override can apply; the overlay
# cannot create a missing configuration leaf. GAM attribution stays off until
# this is set true.
gam_attribution_enabled = false
# script_url = "https://ads.example.com/gpt.js"
# cache_ttl_seconds = 3600
# rewrite_script = true
# GPT runtime diagnostics browser overlay. Optional and enabled manually (not
# flipped by `ts audit`); serves a diagnostics module gated behind an activation
# query param + session cookie.
# [integrations.gpt_diagnostics]
# enabled = true
# Amazon Publisher Services (APS/TAM) OpenRTB. `account_id` required when
# enabled (`pub_id` is accepted as a deserialization alias only).
# [integrations.aps]
# enabled = true
# account_id = "example-aps-account-id" # required (non-empty); your APS account
# endpoint = "https://aps.example.com/e/pb/bid"
# timeout_ms = 1000
# Include raw APS request/response data in /auction metadata on test sites only.
# debug = false
# Script creatives require separate security validation before opt-in.
# allow_script_creatives = false
# Winning-bid renderer. Default `trusted_server` uses TS's opaque static renderer
# route; set `publisher_native` only for the controlled publisher-origin
# friendly-frame experiment.
# rendering_mode = "trusted_server"
# Set both when the deployment hostname differs from APS-authorized inventory.
# inventory_domain = "publisher.example"
# inventory_page_origin = "https://www.publisher.example"
# Google Tag Manager first-party proxy. Kept active but disabled so `ts audit`
# can fill container_id and flip `enabled` when GTM is detected. `container_id`
# is required when this integration is actually enabled.
[integrations.google_tag_manager]
enabled = false
# Invalid placeholder on purpose: enabling GTM without a real GTM-XXXXXX id
# fails validation. `ts audit` overwrites this when it detects a real container.
container_id = "GTM-REPLACE-ME"
# upstream_url = "https://tags.example.com"
# Mock ad server used for auction mediation in dev/testing.
# [integrations.adserver_mock]
# enabled = true
# endpoint = "https://adserver.example.com/mediate"
# timeout_ms = 1000
# Map auction context keys to mediation URL query params:
# [integrations.adserver_mock.context_query_params]
# example_segments = "segments"