How to write and validate an ads.txt file
An ads.txt file is a plain-text list at your domain root naming who is allowed to sell your ad inventory. Each line is four comma-separated fields, the file must be served as text/plain from https://yourdomain.com/ads.txt, and the commonest failure is not a typo — it is a host returning a styled HTML page with a 200 status, which every exchange reads as "no valid records".
- Get the lines from your network. Each ad network publishes the exact line it needs. AdSense shows yours in the account under Sites; managed networks send theirs during setup. Never retype these by hand — copy them.
- Create the file at the domain root. It must live at https://yourdomain.com/ads.txt exactly. Not in a subdirectory, not on a subdomain, and not behind a redirect chain that ends somewhere else.
- Check the response is plain text. Open the URL in a browser and view the raw response. If you see your site's header, navigation or a styled 404 page, the file does not exist as far as any exchange is concerned — regardless of the status code.
- Verify each line parses. Four fields, comma-separated - exchange domain, your publisher ID, DIRECT or RESELLER, and the certification authority ID. A missing comma invalidates that line and only that line, silently.
- Re-check after every theme or plugin change. The file is a static asset in a directory your CMS also writes to. Updates overwrite it, and nothing warns you.
What the file is actually for
Before ads.txt existed, anyone could claim to be selling your inventory. A buyer
seeing "premium news site, $8 CPM" had no way to check whether the seller had
any right to offer it, and domain spoofing was worth billions.
ads.txt fixed that with something almost trivially simple: a public list, at a
known address, of who is allowed to sell you. A buyer fetches
yourdomain.com/ads.txt, sees which sellers you have authorised, and ignores
anyone not on it.
Which means the file is not paperwork. It is the thing that makes your inventory
sellable at all.
The syntax
Each data line is four comma-separated fields:
google.com, pub-0000000000000000, DIRECT, f08c47fec0942fa0
| Field | Meaning |
|---|---|
google.com |
The exchange's domain |
pub-0000… |
Your publisher ID with that exchange |
DIRECT |
Your relationship — see below |
f08c47fec0942fa0 |
The exchange's certification authority ID (optional) |
Lines starting with # are comments. Blank lines are ignored. There are also
variable records like CONTACT= and OWNERDOMAIN=, which are informational and
do not authorise anyone.
The third field is the one worth understanding properly, and it has its own
explanation.
The four ways it goes wrong
HTML served with a 200 status. By a wide margin the most common failure, and
the hardest to notice. Your host has no /ads.txt, so it serves your styled 404
page — but returns HTTP 200 while doing it. Every naive check reports success.
Every exchange parses the body, finds no valid records, and treats your
inventory as unauthorised.
The test is not "does the URL load". It is "is the response plain text
containing the lines I expect".
A missing comma. Field separators are commas, and a line with three fields
where four are expected is discarded — that line only, silently, while the rest
of the file parses fine. You lose one exchange and nothing tells you which.
The file at the wrong address. A subdirectory, a subdomain, or a redirect
chain that lands somewhere else. Exchanges fetch exactly /ads.txt at the root.
A CMS update overwriting it. This is the one that bites established sites
rather than new ones. The file is a static asset sitting in a directory your
theme and plugins also write to. A theme update replaces it, an optimisation
plugin "cleans" it, a migration copies the old version back — and the revenue
drops days before anyone connects the two.
Check it properly
Load https://yourdomain.com/ads.txt and read the raw response, not the
rendered page. You are looking for three things:
- Plain text, not markup
- The lines your networks gave you, byte for byte
- Nothing else that looks like a web page
Do that after every theme change, plugin update and migration — and understand
that "after every change" is a promise nobody keeps for long, which is why this
is worth automating rather than remembering.
Why the checking matters more than the writing
Writing an ads.txt is a ten-minute job you do once. Keeping it correct is
permanent, and the failure mode is uniquely nasty: nothing reports an error.
Your dashboard does not flag it. Your analytics do not change. Ad requests still
fire and ads still render — they just clear at far lower prices because fewer
buyers are permitted to bid.
The first symptom is a revenue number that comes in lower, weeks later, with no
obvious cause.
That gap between "broken" and "noticed" is the entire reason
monitoring this file exists as a product rather than a
checklist item.
Frequently asked
- Where exactly does ads.txt go?
- At the root of the domain serving the ads - https://yourdomain.com/ads.txt. Not a subdirectory, not a subdomain unless that subdomain serves the ads itself. If your site runs on www, both the apex and www should resolve to the same file, which a redirect handles.
- What does each field in a line mean?
- In order - the exchange's domain, your publisher ID with that exchange, your relationship with them (DIRECT if you have the account, RESELLER if someone sells on your behalf), and an optional certification authority ID that identifies the exchange in the IAB's registry.
- How long before a change takes effect?
- Exchanges re-crawl on their own schedules, typically daily. Adding a line takes effect within a day or two. Removing one takes effect just as fast, which is the half people forget.
- Do I need ads.txt if I only run AdSense?
- Yes. AdSense flags a missing ads.txt in the account, and without it your inventory is unauthorised for programmatic buyers even though the AdSense tag still renders. The revenue difference is real and invisible.
- What is app-ads.txt and do I need it?
- It is the same idea for mobile apps, served from the developer website listed in the app store entry. If you have no app, you do not need one.