-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathtrusted-server.example.toml
More file actions
675 lines (628 loc) · 31.7 KB
/
Copy pathtrusted-server.example.toml
File metadata and controls
675 lines (628 loc) · 31.7 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
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
# =============================================================================
# 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 = "handler_password"
# 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"
# Secret Store key for the HMAC secret used to sign first-party proxy URLs.
proxy_secret = "publisher_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 Store key for the secret used to derive EC identifiers.
passphrase = "ec_passphrase"
# 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
# Example partner configuration. Provision referenced keys in
# trusted_server_secrets before validating/pushing.
# [[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
# Only for inbound identify or batch-sync API access:
# api_token = "partner_api_token"
# Required when pull sync is enabled:
# ts_pull_token = "partner_ts_pull_token"
# 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"]
# Trust a fronting CDN's reader IP only when the same request also supplies
# the matching shared secret. The front door must set both headers on requests
# it sends here and remove client-supplied copies on its other routes.
# `shared_secret` is a key in trusted_server_secrets, not the credential itself.
# Fastly-only; see docs/guide/fastly.md for the required front-door setup.
# [trusted_client_ip]
# ip_header = "x-ts-client-ip"
# auth_header = "x-ts-client-ip-auth"
# shared_secret = "trusted_client_ip_shared_secret"
# 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
[integrations.js_asset_proxy]
enabled = false
# Uncomment to override upstream cache headers for every asset below.
# This replaces upstream directives, including private and no-store.
# Use only when each asset's bytes are identical for every visitor.
# cache_ttl_seconds = 3600
# Asset fetches use a fixed TrustedServer/1.0 User-Agent. Do not proxy assets
# that vary by browser User-Agent or use integrity hashes for UA-specific bytes.
[[integrations.js_asset_proxy.assets]]
path = "/assets/example-vendor-loader.js"
origin_url = "https://cdn.example.com/vendor-loader.js"
proxy = "enabled"
# 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 signing, initial fetch targets, and redirect
# targets. 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. Providers are declared below; mediator names must match
# enabled integrations. Kept active with the creative-processing leaves present
# so the EdgeZero environment override can apply to them.
[auction]
# Keep disabled until provider endpoints, routes, and profile values below are
# replaced with deployment-specific settings.
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
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 = []
# Example server-side provider declarations. Remove or customize before enabling auctions.
[auction.providers.pbs-main]
protocol = "openrtb-2.6"
profile = "prebid-server"
endpoint = "https://prebid.example.com/openrtb2/auction"
# `prebid-server` defaults to 1000 ms when omitted.
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 = []
[auction.bidders.example-bidder]
provider = "pbs-main"
# APS server behavior is also provider/profile-owned. Use routing = "all_eligible"
# when every banner-compatible slot should be eligible. The APS profile timeout
# defaults to 800 ms; debug and script creatives default to false.
# [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-id"
# debug = false
# allow_script_creatives = false
# inventory_domain = "publisher.example"
# inventory_page_origin = "https://www.publisher.example"
# 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. `inline` is the default and current production
# behaviour; `esi` is opt-in per deployment and stores an inert comment in a
# shared, reader-neutral template cache. See docs/guide/configuration.md and run
# scripts/template-cache-local-test.sh esi before enabling. This and the
# cache 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
# Optional exact, case-sensitive cookie names; omitted and empty lists are equal.
# Key bounded variants only, never account, session, or TS identity IDs.
# Absent and empty values select different variants. No cardinality limit exists.
# template_cache_key_cookies = ["ab_bucket"]
# Presence, including session=, bypasses template lookup and storage.
# template_cache_bypass_cookies = ["session"]
# With either list nonempty, false bypasses unlisted cookies; true asserts those
# cookies do not change origin HTML. No identity or consent cookie is exempt.
# With both lists empty, false bypasses all Cookie headers, as before.
# On the template path, origin `Vary: Cookie` is always refused. Readthrough
# has no response-side guard; run `ts origin probe-shareability` before enabling.
# Configured key-cookie dimensions disable readthrough, preserving template variants.
# origin_is_cookie_independent = false
# Invalid names, duplicates, cross-list overlap, and TS identity cookies in the
# key list reject configuration. Named policies bypass ambiguous/nonconforming
# Cookie fields, including duplicate key cookies.
# If a downstream CDN maps ab_bucket to X-Exp-Variant, also add x-exp-variant to
# template_cache_vary; that header alone cannot separate arms at TS.
# Rollback: older binaries reject both new fields even as empty lists. Remove
# both fields AND restore independence=false or disable ESI when HTML uses cookies.
#
# Applies shareability checks to the platform's origin cache. Default false keeps
# the existing policy: ad-serving requests bypass; other publisher requests use
# the platform default. True admits shareable ad requests and bypasses unshareable
# non-ad requests. A DIFFERENT cache from the template cache
# above, and a weaker one: the decision is made before the origin replies, so
# none of the template cache's response-side refusals (`Set-Cookie`, CSP nonce,
# missing freshness) apply. `ts origin probe-shareability` must pass on every
# axis and verdict first. Tagged readthrough objects can be purged with
# ts cache purge (--all or the exact reader-facing --page URL). Older untagged
# objects must expire on the origin TTL; see the configuration guide's rollback note.
# origin_readthrough_enabled = 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
# auction_dataset = "auction_events" # Events API datasource name
# auction_token_secret = "tinybird_auction_append_token" # Key in trusted_server_secrets
# 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.
# =============================================================================
# Browser-side Prebid.js integration. Server-side bidder routing belongs under
# [auction.providers] and [auction.bidders]. When enabled,
# `external_bundle_url` is required and its host must be listed in
# [proxy].allowed_domains. Kept active but disabled.
[integrations.prebid]
enabled = false
timeout_ms = 1000
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>"
# Bundle build inputs consumed by `ts prebid bundle`, not by the edge runtime.
# Values are exact upstream module stems without `.js`.
# [integrations.prebid.bundle.modules]
# bidder = ["rubiconBidAdapter"]
# Omit user_id for the curated default preset; use [] to select none.
# user_id = ["sharedIdSystem"]
# Omitted or empty analytics selects no analytics adapters.
# analytics = ["atsAnalyticsAdapter"]
# Prebid User ID modules that Trusted Server installs and keeps installed, so
# operators can manage identity centrally without publisher JavaScript changes.
# Each entry is forwarded to Prebid.js verbatim: `name` is a
# `userSync.userIds` entry name, `params` and `storage` are whatever that module
# documents. Trusted Server does not interpret them; supported names come from
# the checked-in User ID registry. Each `name` must appear only once.
#
# The module must be present in the built bundle: name it under
# [integrations.prebid.bundle].user_id_modules, or omit that list to take the
# generator's default preset. `ts prebid bundle` resolves every managed name
# through the checked-in User ID registry and fails if the generated manifest
# omits its required module without updating the configured hash or SRI.
#
# Persisting a resolved ID into the EC identity graph additionally needs a
# matching partner under [[ec.partners]] whose source_domain equals the module's
# OpenRTB EID source; without one the ID still reaches the auction but is never
# written to KV.
#
# [[integrations.prebid.managed_user_ids]]
# name = "sharedId"
#
# [integrations.prebid.managed_user_ids.storage]
# type = "cookie" # or "html5"
# name = "_sharedid"
# expires = 15 # days; omit to keep Prebid's default
# refresh_in_seconds = 1800 # omit to keep Prebid's default
# 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
geo_query_parameters = 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
# Required when enable_protection = true. The value is a key in
# trusted_server_secrets, not the DataDome credential itself.
# 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
# APS browser renderer ownership. Server-side APS behavior belongs under an
# [auction.providers] entry with profile = "aps".
# [integrations.aps]
# enabled = true
# Default `trusted_server` uses TS's opaque static renderer route. Set
# `publisher_native` only for a controlled publisher-origin friendly-frame cohort.
# rendering_mode = "trusted_server"
# 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"
# Must be a credential-free https bare origin with a literal host: no path,
# query, fragment, `user:pass@` or wildcard. Targets are built by appending a
# rooted path to this value, so anything beyond an origin corrupts them.
# upstream_url = "https://tags.example.com"
# Tag ids the `gtag/js` path may serve from your own origin, in addition to
# `container_id`. A request naming any other tag id is redirected to the
# upstream instead, so this origin never serves a container you did not
# choose. The visitor loads that tag from the upstream directly, which a
# `script-src` that does not list the upstream origin will block.
#
# Set this if your pages load gtag with a measurement id separate from the
# container above (a GA4 `G-`, Ads `AW-` or Merchant Center `MC-` id). A tag
# that is missing here also loses the ad-blocker resilience this integration
# provides. Find the ids by grepping your rendered HTML for `gtag/js?id=`.
# allowed_tag_ids = ["G-EXAMPLE1", "AW-000000", "MC-EXAMPLE1"]
# 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"