Supply · 24 Feb 2026

ads.txt, app-ads.txt, sellers.json, and schain, explained

Four records answer four different questions. Buyers use them together before they spend on an impression.

Colleagues reviewing paperwork at a shared desk
Authorization files are public paperwork. The bid request is the receipt for one impression.

Programmatic advertising lets many companies sell the same publisher’s ad space. That is useful, and it is also how fake inventory slips in. A buyer needs a simple way to ask: who is allowed to sell this, who is that seller, and who actually touched this request?

The industry answered with four pieces that only work as a set: ads.txt, app-ads.txt, sellers.json, and the OpenRTB SupplyChain object, usually called schain.

The problem these files solve

Imagine a shop that says “only these three wholesalers may sell our goods.” A buyer who meets a fourth wholesaler should walk away. ads.txt is that public list for a website. app-ads.txt is the same list for a mobile or CTV app.

A list of names is not enough. The buyer also needs to know whether “seller 12345” is the publisher or a reseller, and which companies stood between the publisher and the DSP on this particular impression. sellers.json and schain cover those two questions.

ads.txt: who may sell this website

The publisher hosts a text file at the root of the site, for example example.com/ads.txt. Each line names an advertising system, the publisher’s account ID inside that system, and the relationship:

  • DIRECT — the system pays the publisher (or the publisher’s contracted manager) for this inventory.
  • RESELLER — the system is authorized, but it is not the publisher’s direct payee for that line.

If a bid request claims to sell example.com through an exchange that is not in that file, a careful DSP treats the request as unauthorized. That check is the original defense against domain spoofing: someone pretending to sell a site they do not represent.

app-ads.txt: the same idea for apps and CTV

Apps do not have a website root in the same way. The developer puts the app’s store listing next to a developer domain, and hosts app-ads.txt on that domain. DSPs that buy in-app or connected-TV inventory look there before they bid.

A missing or stale app-ads.txt file is a common reason good app inventory gets no bids. The app can be real, the users can be real, and the request still fails the authorization check.

sellers.json: who each seller ID actually is

ads.txt says which systems are allowed. It does not introduce the company behind an account number. Each SSP or exchange publishes sellers.json on its own domain. Every seller account gets:

  • a seller_id that should match the ID in ads.txt and in schain
  • a seller_type: PUBLISHER, INTERMEDIARY, or BOTH
  • a name and domain, unless the seller is marked confidential

Buyers cache this file. They do not need the publisher’s legal name repeated inside every bid request. They look it up.

schain: the path this one request took

ads.txt and sellers.json are standing disclosures. source.schain travels inside the bid request and lists every advertising system that handled this impression, in order. Each node has three fields worth remembering:

  • asi — the advertising system’s domain. That domain should host a sellers.json file.
  • sid — the seller ID inside that system.
  • hp — 1 if this node is paid for the impression, 0 if it only passed the request through.

schain.complete should be 1 when the chain goes all the way back to the publisher. A complete flag on an incomplete list is a warning, not a comfort.

How a buyer checks one request

  1. Read the publisher domain or app from the bid request.
  2. Open that publisher’s ads.txt or app-ads.txt and confirm the selling system and seller ID are listed.
  3. Walk each schain node. For every asi + sid, confirm the pair exists in that system’s sellers.json.
  4. Count hops. A short, identified path is easier to price than a long chain of intermediaries.

A node whose seller ID is missing from sellers.json is usually a fabricated hop. A paid node that never appears in the publisher’s ads.txt is unauthorized for that sale, even if some other company in the chain looks familiar.

What publishers and SSPs should publish

  • Keep ads.txt or app-ads.txt current when you add or drop an SSP. Old reseller lines keep authorizing paths you no longer want.
  • Use one seller ID per commercial relationship. Reusing an ID for two companies makes the file meaningless.
  • Publish sellers.json on the exchange domain, over HTTPS, and match seller types to how you actually pay.
  • Send a complete schain on every OpenRTB request, including app and CTV.

FAQ

Is a RESELLER line always bad?

No. Resale is allowed when the publisher authorized it. Buyers still prefer fewer hops, because each hop can add a fee and another place for the request to be misdescribed.

Does schain replace ads.txt?

No. schain says who touched this request. ads.txt says who was allowed to sell. Buyers need both.

Where does this sit in OpenRTB?

In OpenRTB 2.6 the SupplyChain object lives on source.schain. Older 2.5 integrations often send it as an extension with the same node fields.

← All posts · Supply path optimization · What is SPO? · What is OpenRTB?