Ad Operations

How to Serve a Dynamic ads.txt File Without Breaking Ad Verification

A practical guide to serving ads.txt dynamically from a backend function: correct headers, caching, fallbacks, and how crawlers validate the file.

9 min read
Laptop screen showing server log output while an ads.txt file is being fetched
Crawlers fetch ads.txt as plain text — headers matter more than markup.

ads.txt is a plain-text file at the root of your domain that lists every seller authorized to sell your inventory. Buyers crawl it, and if it fails to parse, your demand quietly drops. Serving it from a database instead of a static file gives you control — but only if you get the transport details right.

Why serve ads.txt dynamically?

A static file means a deploy for every seller change. A dynamic endpoint lets ad ops edit lines in an admin UI, keeps an audit trail, and can sync from an upstream provider on a schedule. The tradeoff is that you now own correctness: the response has to look exactly like a file.

  • Seller lists change weekly; deploys should not gate revenue.
  • Multiple domains can share one source of truth.
  • Every change becomes reviewable instead of a silent commit.

Get the headers right

The single most common failure is returning JSON or HTML. Crawlers expecttext/plainand will reject anything else. Return the raw body, one record per line, ending with a newline.

Content-Type: text/plain; charset=utf-8
Cache-Control: public, max-age=3600
X-Robots-Tag: noindex

google.com, pub-0000000000000000, DIRECT, f08c47fec0942fa0
appnexus.com, 1234, RESELLER

Note noindex: the file is for crawlers that validate inventory, not for search results. Keeping it out of the index avoids thin-content pages competing with your real articles.

Redirects are allowed — within limits

The IAB spec permits a single redirect, and many publishers use it to point/ads.txtat a managed endpoint. Chains of two or more are treated as a failure by most validators, so terminate on the first hop.

Caching without going stale

An hour of cache is a reasonable default: long enough to absorb crawler traffic, short enough that a seller removal takes effect the same day. Pair it with anETagderived from the row set so unchanged responses cost nothing.

Always ship a fallback

If your database read fails, do not return a 500 and do not return an empty file — an empty ads.txt reads as “nobody is authorized” and can suspend monetization. Serve the last known good copy from a static asset instead, and alert separately.

An empty ads.txt is worse than a stale one. Stale loses accuracy; empty loses revenue.

Validate like a crawler

  1. Fetch over HTTPS with no cookies and no custom headers.
  2. Confirm a 200 status and a text/plain content type.
  3. Check for stray HTML, BOM characters, or CRLF inconsistency.
  4. Diff the line count against yesterday to catch silent truncation.

Frequently asked questions

Does a dynamic ads.txt hurt SEO?
No. The file is served as plain text with a noindex hint, so it never competes with your content pages in search results.
How often do buyers re-crawl ads.txt?
Most major buyers refresh at least once every 24 hours, so a one-hour cache is comfortably fresh.
Is more than one redirect allowed?
The IAB spec allows a single redirect. Two or more hops are treated as a validation failure by most crawlers.
What should the endpoint return if the database is down?
The last known good copy from a static asset. Returning an empty body or a 500 can pause monetization.

Key takeaways

Dynamic ads.txt is a transport problem, not a data problem. Return plain text, cache for about an hour, allow at most one redirect, and never let a failure produce an empty body. Do that and buyers cannot tell the difference between your endpoint and a file.

Article tags

  • #ads.txt
  • #programmatic
  • #backend
  • #SEO

Last updated .