Docs

What RTBlint checks

RTBlint is a structural and semantic linter, not a schema-only check. It parses the JSON, walks the object tree against the canonical OpenRTB catalog for the version you target, and reports anything that does not belong, sits in the wrong place, or has the wrong type.

JSON well-formedness

The payload must parse as a JSON object. A syntax error or a non-object root is reported first, and no field rules run until it is fixed.

Required fields

Fields the specification marks as required must be present. A bid request needs an id and at least one impression; an impression needs a media type object.

Undefined fields

Every object is walked against the canonical OpenRTB catalog for the selected version. A field that is not defined there is flagged so typos and invented keys do not slip through as ext-like noise.

Type mismatches

A field declared as a string, integer, array, or object must carry that type. A string where an integer belongs, or an object where an array belongs, is reported with the path that tripped it.

Deprecated, moved, and removed paths

Versioned status is tracked per snapshot. A deprecated field still parses but warns; a moved field points at its new path (for example regs.ext.gdpr to regs.gdpr); a removed field is an error in versions that dropped it.

Enum values

Fields constrained to a documented set of integer or string values are checked against that set, so an out-of-range enum is caught rather than passed downstream.

Semantic rules

A narrow set of cross-field rules runs beyond per-field structure: mutually exclusive fields, media-type requirements on an impression, and conditional requirements such as fields that only apply to skippable video.

Supply-chain resolution (CLI, opt-in)

With --resolve --cache, each SupplyChain payment hop is checked against that domain's sellers.json, and the first payment hop against the publisher's ads.txt or app-ads.txt. The cache is a local directory; nothing is fetched. The WASM tester and npm package stay offline.

NDJSON stream (CLI)

--batch lints one payload per line from a captured bid stream. --summary ranks rule ids by how often they fired, so a million-line dump answers which defects dominate rather than printing every finding.

Exchange profiles

--profile google-ab applies Google Authorized Buyers' documented protocol extras: at=3 (FIXED_PRICE) is a valid auction type, and each Imp must carry ext.billing_id. --profile prebid-server applies Prebid Server /openrtb2/auction extras: each Imp must name a bidder or stored request, wseat/bseat are refused, stored-request objects need id, and native request asset ids are optional. --profile xandr requires ext.appnexus.seller_member_id and video.ext.appnexus.context. --profile magnite requires Magnite xAPI identity fields. Orthogonal to --dialect. Unknown profile ids are rejected. Business policy (floors, blocklists, bid adjustments) is not encoded.

Nested specs

OpenRTB parks whole protocols in strings and ext objects. Native Ads 1.2 markup in imp.native.request and native bid.adm is walked for assets, ids, and subtypes, and paired against the request when one is supplied. GPP headers are decoded and compared to gpp_sid; TCF 2 shape is checked on user.consent. ${AUCTION_*} macros are scanned on nurl, burl, lurl, and adm. EID source/uids/id are required; device.sua is walked as UserAgent. imp.ext.skadn and bid.ext.skadn follow the IAB SKAdNetwork community extension. VAST inside adm is still a document-root sniff.

What it does not do yet

The current core validates OpenRTB 2.x and 3.0 bid requests and bid responses, including AdCOM 1.0 domain objects on 3.0. Nested specs cover Native Ads 1.2 markup, GPP/TCF string shape, OpenRTB macros, EID/SUA, and SKAdNetwork extensions. VAST inside bid.adm is still a document-root sniff, not a full vastlint pass. Exchange profiles cover documented protocol extras (Google Authorized Buyers, Prebid Server, Xandr, Magnite), not business policy. Native Go/Python bindings are still on the roadmap. Passing RTBlint also does not guarantee a bid: exchanges, bidders, and private deals impose their own requirements on top of the specification.

Each finding carries a stable id and a path. See the rule reference for the full list, or OpenRTB versions for how snapshots change the result.