Important
Auctioneer is under heavy development and is not yet stable. We are not accepting outside contributions or pull requests at this time. This notice will be updated when the project is ready for external contributions.
IAB Tech Lab repository. This is a fresh-history import. Historical plans and evidence are retained; see repository import for their status.
An OpenRTB 2.6 auction engine written in Rust, usable as a standalone server or a library for in-binary integration. Built on the EdgeZero framework, its standalone adapters target Axum (native), Cloudflare Workers, Fastly Compute@Edge, and Spin (Fermyon). Target support is not deployment qualification. Direct Trusted Server integration is a product goal; see the vision for the distinction from the existing library.
Product vision: vision.md
Architecture overview: docs/architecture.md
Design spec: Master design
Approved roadmap: docs/roadmap.md
Foundations plan: docs/superpowers/plans/2026-05-25-foundations.md
Upstream credit: Prebid and other acknowledgements
| Crate | Purpose |
|---|---|
crates/auctioneer-core |
EdgeZero app, HTTP routes and handlers, host integration, and response serialization |
crates/auctioneer-runtime |
Host-environment seams: Clock + Rng traits with deterministic test impls (FakeClock, SeededRng), Fisher-Yates shuffle, Lemire gen_range |
crates/auctioneer-openrtb |
OpenRTB 2.6 typed model + prepare(req, headers) — the sole construction gate for a NormalizedBidRequest |
crates/auctioneer-config |
Host / account / bidder configuration. Build-time codegen reads bidder-owned bidder.toml manifests, auctioneer.toml, and shared reference data, then emits typed accessors |
crates/auctioneer-adapter-axum |
Axum (native) entry point |
crates/auctioneer-adapter-cloudflare |
Cloudflare Workers (wasm32-unknown-unknown) entry point |
crates/auctioneer-adapter-fastly |
Fastly Compute@Edge (wasm32-wasip1) entry point |
crates/auctioneer-adapter-spin |
Spin / Fermyon (wasm32-wasip2) entry point |
- Foundations and auction core: runtime primitives, typed OpenRTB preparation, generated configuration, and the auction, status, and bidder-info routes are implemented with unit and integration tests.
- GDPR fanout: TCF v2 parsing and legal-basis enforcement, GVL/GCL authenticity and freshness, GDPR scrubs, config overlays (bidder kill switches,
sample_rate, aliases, and accounts), and golden fixtures are implemented. - Bounded fanout and privacy enforcement: strict config resolution, GPP source normalization, independent CCPA/LMT/COPPA and activity decisions, bidder-local projection/scrubs, bounded outbound construction, and measured per-auction reservations are integrated. The verification record records native tests, conformance, linting, and WASM compilation checks, not a physical-OOM guarantee or hosted qualification.
- Signed user sync:
/cookie_sync,/setuid,/getuids, and the preflight use the generated App; issued UID state requires a MAC envelope. Recorded native and Chromium loopback checks do not establish third-party-cookie acceptance or hosted-provider readiness. - Bounded diagnostics: permission-gated capture and sanitized projection into auction
ext.debugare implemented. Local diagnostic and qualification evidence retains explicit provider, resource, and publisher-readiness limitations. - Controlled-native bidder delivery: source registration is generated, and all 14 priority selected flows, including Sharethrough, Rubicon, and APS, are implemented under the approved native contract. Recorded local acceptance is not full-catalog completion or complete worst-case resource certification. New priority publications are native-only and inactive by default; existing guest publications remain unchanged.
Complete resource certification is outstanding; affected guest production
readiness remains blocked. Hosted execution, Trusted Server embedding, and
live publisher acceptance remain separate work.
Production deployment uses EdgeZero's production-deploy tooling;
commands in edgezero.toml are dev/staging-only.
The approved roadmap separates delivered diagnostic hardening and controlled-native priority flows from planned integration and qualification. The next priorities are direct Trusted Server embedding and a selected-bidder publisher pilot, then demand-led bidder expansion. Stored requests/accounts, currency/multibid/auction identity, creative caching, and full video delivery follow. Other shared parity work covers first-party data, floors/adjustments, AMP/native, privacy/transparency, compressed ingress, hooks/modules, metrics/analytics, and browser privacy compatibility. Residual full-catalog migration remains distinct from priority-flow delivery and bidder expansion. These plans do not claim implementation or production readiness.
Diagnostic qualification is a local/staging checkpoint, not a live publisher pilot. Trusted Server embedding owns in-binary integration; publisher-pilot acceptance owns hosted execution and live limited-bidder rollout. Selected banner/display flows need not wait for the full catalog or video, but publisher-specific dependencies and deployment checks still apply; see the pilot requirements.
Install the versions declared in .tool-versions using your
tool manager. The file pins Rust, Node.js, Fastly CLI, Spin, Viceroy, and
Wasmtime to the reviewed EdgeZero toolset. A version declaration does not
install a missing tool or its version-manager plugin.
Rust builds every target; Node.js serves the browser and Worker tooling.
Fastly CLI and Spin package their adapters, and Viceroy runs the local Fastly
guest controls. The pinned Wasmtime is required for selected-source WASIp1/P2
schema execution tests, including the workspace test run. CI installs its
checksum-pinned release before those consumers. Compile/package-only WASM jobs
still do not establish runtime execution. Relevant CI setup reads .tool-versions instead of
maintaining separate Rust, Node.js, Fastly, Spin, or Viceroy version literals.
For the normal edit loop, start with the affected package rather than the workspace. See development loops and test ownership for focused commands, required-feature checks and isolation rules. Retain Cargo's incremental cache; do not routinely clean targets between edits.
cargo check --locked -p auctioneer-bidder --lib
cargo test --locked -p auctioneer-bidder --lib endpoint_builder::tests::Broad native checks (not the complete CI/guest/qualification matrix):
cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warningsThe insecure-bidders cargo feature on auctioneer-config enables
deterministic loopback test bidders:
cargo test --workspace --features auctioneer-config/insecure-bidders
Axum's default cargo test -p auctioneer-adapter-axum --all-targets also runs the
handler-to-socket privacy test. Its test-only dependency enables the loopback
bidder; normal production builds retain the secure defaults. The test sweeps
CCPA and all three disclosure activities independently.
The executable examples in auctioneer.toml cover baked defaults
and pushed runtime overrides. CCPA and LMT enforcement default off; activity
controls default to allow. GDPR enablement does not bypass independent
CCPA, LMT, COPPA, or activity decisions. COPPA has no disable override.
Activity configuration accepts at most 128 rules per activity, 128 combined
name/type entries per rule, and 128 UTF-8 bytes per component name. Runtime
rule arrays replace inherited arrays; rules = [] clears them.
The internal GPP envelope parser supports TCF section 2 and USP section 6 through separate policy modules. Other sections remain opaque; this does not implement US-state policy enforcement. Parser ceilings are:
| Input or work | Ceiling |
|---|---|
| Raw GPP UTF-8 value | 256 KiB |
| Encoded header | 4 KiB |
| Total sections, including unknown/empty sections | 64 |
| Numeric section ID | 1..=65535 |
| Charged decoding operations | 524288 |
Limit violations and invalid ext.prebid.nosale names return 400 before
bidder construction, even when enforcement is disabled. Within-limit format
errors instead use fixed warnings and the documented source-selection rules;
an empty or invalid active TCF section never retries granting legacy consent.
See the privacy enforcement design
for precedence, scrubs, and the remaining acceptance requirements.
[baked.host.resource_limits] defines independent max_outbound_raw_bytes
and max_outbound_request_bytes ceilings for raw and transport-encoded bidder
bodies. Set the same fields under [runtime.auction] for pushed overrides.
Both default to 256 KiB, accept 1 KiB through 16 MiB, and are clamped
to the installed boot envelope. An oversized bidder request is a bidder-local
code-5 refusal; exceeding an auction's prepaid resource allowance instead
returns fixed 503 overloaded\n. The latter never changes consent selection.
Provision usersync_cookie_keyring in the default EdgeZero secret store before
serving UID routes. See key provisioning and rotation.
Unsigned/tampered cookies are rejected; unavailable keys return 503 without
cookie writes. A valid signature protects issued state, not ownership of the
public callback's supplied UID or an authorization/consent grant.
The example auctioneer.toml uses
https://sync.example.test only as a demonstration callback base. Set
baked.host.user_sync.external_url (or its runtime.user_sync override)
to the public HTTPS origin and optional base path that actually reaches
this deployment, for example https://sync.publisher.example/auctioneer.
The default redirect template then builds callbacks under that base path.
Do not derive the callback from request Host, Origin, or forwarded
headers. Baked changes require a rebuild; runtime changes require a config
push and take effect on a subsequent request. Invalid effective sync config
is rejected rather than replaced by permissive defaults.
host_cookie.cookie_name and family identify a separate host cookie to
import; Auctioneer's writable UID cookie is always named uids. Configure an
optional cookie domain, positive ttl_days (default 90), and optional
opt-out cookie name and value together. max_cookie_size_bytes = 0
disables only the logical eviction threshold, not the hard Set-Cookie cap.
Account cookie_sync settings select default/cooperative limits and can
replace host priority groups, including with an empty list. A missing or
empty account selects baked/default policy; a supplied account ID selects
its named override when present. runtime.bidders.<name>.usersync_enabled
can disable sync independently of auction participation, but cannot create
a syncer absent from the baked bidder metadata.
Cross-origin JavaScript access is off by default. Add exact
scheme/host/port origins to user_sync.allowed_origins, without paths or
wildcards, and send browser requests with credentials when cookies are
needed. Allowed application responses use credentialed CORS and
Vary: Origin; OPTIONS /cookie_sync permits POST with Content-Type.
Pre-config/admission/framework failures cannot promise CORS headers.
Auctioneer-owned sync responses use Cache-Control: no-store. The uids
cookie uses Path=/ and an expiry; Domain is optional. The current
Chrome/CriOS 67+ user-agent rule adds Secure and SameSite=None.
Browser acceptance, especially in third-party contexts, is not guaranteed
by a successful server response and needs real-browser validation.
| Sync surface | Current hard limit |
|---|---|
POST /cookie_sync |
32 KiB body and 4,096 JSON nodes; compressed bodies rejected |
GET /setuid, GET /getuids |
32 KiB encoded query, at most 32 parameters; adapter request-target profiles allow 33 KiB, subject to provider limits |
| Cookie decode | Current profiles admit 16 KiB of request headers; codec ceilings are 64 header fields, 32 KiB header/encoded value, 24 KiB decoded value, and 4,096 JSON nodes |
| Selection/config | 256 requested or catalog names, 128 UTF-8 bytes per name, 32 priority groups, 256 priority entries |
| Output | 32 KiB per sync URL, 256 KiB response body, 4 KiB complete signed Set-Cookie field value |
These are resource ceilings, not a promise that every legal browser or
provider request is admitted. User sync does not migrate the full upstream bidder
catalog and does not feed stored buyeruid values into auction bidder
requests; /getuids exposes the stored map to clients only. See the
user sync design
for endpoint ordering and intentional reference differences.
Routes are wired in auctioneer-core; the commands below are the Cargo/framework
entry points for the adapter shells.
Run them from the workspace root.
| Adapter | Local dev |
|---|---|
| Axum | cargo run -p auctioneer-adapter-axum |
| Cloudflare Workers | wrangler dev --cwd crates/auctioneer-adapter-cloudflare |
| Fastly Compute@Edge | fastly compute serve |
| Spin | spin up --from crates/auctioneer-adapter-spin |
GET /_auctioneer/health/gvl reports GVL archive health (archive age,
bundled vendor-list versions, and the rolling unavailable-lookup
counter). The handler is fail-closed: it answers 401 unless the adapter
boot installed an explicit access policy — either a bearer token
(AUCTIONEER__RUNTIME__HEALTH_GVL_TOKEN on Axum / Cloudflare; the platform
secret store on Fastly / Spin) or the machine-checkable
allow_unauthenticated_health = true opt-in.
Deployments that opt in to serving /_auctioneer/* without a token MUST
restrict the /_auctioneer/* path prefix at the ingress layer. That
restriction is an L7 (HTTP-path) rule — an L3/L4 network policy such as
Kubernetes NetworkPolicy cannot match an HTTP path and does NOT
satisfy it. Per-platform recipes (Cloudflare Access, Fastly VCL,
Kubernetes ingress HTTPRoute + AuthorizationPolicy, nginx
auth_request for standalone Axum) live in
docs/deployment/restrict-operational-endpoints.md.
Copyright 2026 IAB Technology Laboratory, Inc.
Auctioneer is licensed under the Apache License 2.0, matching IAB Tech Lab Trusted Server's license. Third-party copyrights and attribution remain in NOTICE and the source-specific notices; the project copyright does not replace them.
Auctioneer builds on EdgeZero and the IAB Tech Lab OpenRTB specification.
Auctioneer credits Prebid.org and the Prebid Server contributors for the selected bidder implementations ported and adapted to Rust, bidder metadata, parameter schemas, auction/privacy/user-sync reference behavior, and captured test fixtures. Additional bidder reference material comes from the Stackpop fork of Prebid Server. GPP reference fixtures also use Prebid's go-gpp; this fixture reference is not a Go runtime dependency.
Auctioneer's Rust adaptations, policy decisions and extensions differ from these upstream projects. Attribution does not imply complete behavioral parity, certification, affiliation or endorsement.
The NOTICE records upstream credit and the retained Prebid Server
copyright notice. The unchanged
shared reference license
remains with the bidder source witnesses. The patched schema compiler retains
its MIT license. The patched
regex-automata retains its MIT or
Apache-2.0 license alternatives.
Other third-party materials retain their own licenses and notices.
Reference-derived bidders' bidder.toml files record their immutable source
revisions and intentional differences. Attribution and shared license notices
belong here, not in a new license file in every bidder folder. Existing
byte-pinned reference captures are consolidated with their integrity readers under the
asset migration plan;
their duplication is not the convention for new bidders.