app-ads.txt, end to end.
The complete reference for the authorized sellers file for apps: what it is, how it is discovered, every field of the syntax, hosting requirements, the mistakes that silently cost fill, and the CTV specifics. Written to be linked to, not summarized past.
Syntax, hosting, mistakes, CTV specifics
01What app-ads.txt is and why it exists
app-ads.txt is an IAB Tech Lab specification: one text file, hosted at the root of a developer's website, listing every ad system authorized to sell that developer's inventory. Each line declares an ad system domain, the publisher's account ID with that system, and whether the relationship is DIRECT or RESELLER.
The file exists to solve inventory spoofing. Before it, a bad actor could send bid requests claiming to be any app, and buyers had no way to check the claim against anything. With app-ads.txt, the buyer's crawler reads the file from the developer's own domain and filters every bid request that names an unauthorized seller path. The enforcement is done by demand platforms checking the file, which is why the file has to be correct: an authorized publisher with a broken file looks identical to a spoofer.
Who enforces it in practice: exchanges, SSPs and DSPs that run app-ads.txt filtering on incoming or outgoing bid requests. Sky Boosts enforces it on all incoming supply, which is documented on theapp-ads.txt management page.
02How the file is discovered
The discovery chain has three links, and a break at any one of them produces the same symptom: the crawler finds nothing, and your inventory is treated as unauthorized.
- The store listing website field. Google Play Console exposes a website field per app; App Store Connect exposes the marketing URL. The crawler starts here. An empty field ends the crawl immediately: there is nothing to fetch, and no fallback exists.
- The crawler fetches that domain. The store listing link must point to a site you control. Social profile URLs (a Facebook page, a Linktree) do not carry your file and are treated as missing. Some crawlers follow one redirect; relying on redirects is fragile and covered in the mistakes list.
- The root file. The crawler fetches
https://that-domain/app-ads.txt. Root means root: not/static/app-ads.txt, not a page rendered by a CMS at that URL with HTML around the content.
The detail that costs fill
Spec-compliant crawlers canonicalize the host: a listing that sayshttps://www.example.com is crawled athttps://example.com/app-ads.txt, because the www prefix is stripped before the fetch path is derived. The failure this invites is the mirror image: a file published only on the www host, with nothing on the apex, means the canonical fetch returns nothing and no fallback exists below the root domain, and not every crawler in the market canonicalizes correctly anyway. Serve the file on both hosts, or redirect one cleanly to the other with a 301, and verify both URLs.
03File syntax
Every authorization line has four fields, comma-separated:
ad-system-domain, publisher-account-id, DIRECT|RESELLER, certification-authority-id
skyboosts.com, 000123, DIRECT, 9f4a1c2b
sample-exchange.com, pub-0000123456789000, DIRECT, f08c47fec0942fa0- Ad system domain. The exchange domain, exactly as it appears in that system's sellers.json. Not your own domain.
- Publisher account ID. The ID the ad system knows you by. Ours is issued at onboarding and visible in the dashboard.
- DIRECT or RESELLER. DIRECT means the publisher controls the account listed. RESELLER means another party sells on the publisher's behalf with permission. Case-insensitive, but consistent is easier to audit.
- Certification authority ID. Optional. An ID from a certification program such as Google's Authorized Sellers program, added as the fourth field where issued.
Beside authorization records, the spec inherits the ads.txt variable declarations, with one app-ads.txt-specific exception:
CONTACT=Jane Doe: licensing@example.com: a human contact for the file. Optional and occasionally useful when a buyer needs to resolve a mismatch with you instead of a ticket queue.SUBDOMAIN=: a web ads.txt directive that the app-ads.txt specification explicitly does not use. The spec's own words: the subdomain directive "is unused in appads.txt files and should be ignored if encountered." A SUBDOMAIN line in an app-ads.txt file has no effect at all, no matter how correct it looks.OWNERDOMAIN=andINVENTORYPARTNERDOMAIN=: variables defined in the newer web ads.txt v1.1 revision, which the app-ads.txt specification now references as its base, so a v1.1-aware crawler can read them, while older v1.0 crawlers ignore them. If your file needs them for a web ads.txt workflow, verify each value against the current ads.txt spec before adding it.
Partitioning note from the spec: one file authorizes sellers for every app that resolves to the developer domain. Sellers cannot be partitioned per app within one file; the spec requires separate developer domains or subdomains for that, and advises against fine-grained control attempts. Multi-level subdomains are canonicalized down to one level: a listing pointing atanother.subdomain.example.com is crawled at subdomain.example.com, with the parent domain's file read only as fallback.
Comments start with # and run to end of line. Blank lines are fine. The file is case-insensitive on DIRECT and RESELLER; domains are matched case-insensitively but should be written lowercase anyway.
04Encoding and hosting requirements
- UTF-8 without BOM. A byte order mark at the start of the file corrupts the first record for crawlers that do not strip it. Re-save as plain UTF-8.
- Content type text/plain. Serve the file with a
text/plainContent-Type. Files served astext/htmlare rejected by stricter crawlers. - Root placement over HTTPS. Serve at
/app-ads.txton HTTPS. HTTP is tolerated by some crawlers as a fallback, but serving HTTPS from the start removes the ambiguity. - robots.txt effects. If robots.txt disallows the crawling agent from
/app-ads.txt, compliant crawlers stop. Do not accidentally blanket-disallow the file. - Redirects. Follow at most one or two. A redirect chain that ends somewhere unrelated to the declared domain fails. A meta-refresh page is not a redirect.
- Availability. The file must return 200 quickly. A 404, an empty body, or a five-second timeout all read as missing.
- No root hosting. If your site builder cannot serve a root-level file, host the file on any static host under your domain, or use a hosting product with a free subdomain, and point the store listing's website field at that domain. What matters is that the store listing resolves to a domain you control that serves the file at its root.
- Declaring no sellers. An empty file is a defined state: if you want an app to have no authorized sellers at all, publish an empty app-ads.txt rather than no file, following the ads.txt guidance for files without records, so verifiers read the declaration instead of a failure.
05Common mistakes, with symptom and fix
- BOM bytes. Symptom: the first line's records are missing from buyer systems while the file looks fine in a browser. Fix: re-save as UTF-8 without BOM.
- Wrong MIME type. Symptom: strict crawlers report the file as missing although the URL works. Fix: serve text/plain.
- Subdirectory placement. Symptom: crawl resolves the domain but finds no file. Fix: move to the domain root.
- Empty website field. Symptom: discovery ends before any fetch. Fix: set the developer website in Play Console and App Store Connect.
- Social profile URL as website. Symptom: the crawler lands somewhere that cannot carry your file. Fix: point the field at a domain you control.
- ID mismatches. Symptom: file is valid, but the demand side reports an unauthorized account. Fix: regenerate the line with the exact account ID the ad system issued; copy-paste errors and old IDs are the usual cause.
- Stale entries. Symptom: an ad system you stopped working with remains authorized, and an audit flags it. Fix: re-issue the file from your current account list.
- Web-only SUBDOMAIN lines. Symptom: a SUBDOMAIN line copied from a web ads.txt guide does nothing in app-ads.txt; the spec instructs crawlers to ignore it, so authorization relying on it never takes effect. Fix: remove the line and authorize every seller directly in the root file.
- Removing the old domain's file too early. Symptom: after changing the developer website to a new domain, some buyers still resolve the old one. Fix: the spec recommends keeping the file on the old domain for an extended period, thirty days where possible, before removing it.
06Verification workflow
- Direct fetch. Open both the www and apex file URLs in a clean browser session. Expect plain text, instantly.
- Headers. Check the Content-Type header with a curl or browser devtools: it should say text/plain.
- Store console status. Confirm the website field in Play Console and App Store Connect matches the domain you just verified, character for character.
- Re-crawl timing. Buyers crawl on their own schedules, commonly daily, with propagation after changes taking up to that cycle. Re-verify the file yourself after every change, and let account-level monitoring watch it continuously.
07sellers.json and schain
Three artifacts chain into one verifiable path. Your app-ads.txt authorizes the ad system for your account ID. The ad system's sellers.json maps that account ID to a legal entity and seller type. The supply chain object on each bid request carries both IDs at auction time, so a buyer can confirm in-line that the request follows the authorized path. A mismatch between any two of the three, a wrong ID in your file, an unlisted account in sellers.json, or a schain node that does not resolve, gives the buyer grounds to filter the request, and most do.
08Multi-platform coverage
One file covers every app that resolves to the same developer domain: Android and iOS apps under one Play Console and one App Store Connect account, TV apps wherever their stores point at the same website. Keep the store website fields identical across stores, publish one file, and the account IDs inside it stay the source of truth for everything the domain covers.
09CTV and OTT specifics
TV platforms expose the developer website in different places: Play Console for Android TV and Google TV builds, the Roku developer portal for channels, the Amazon developer console for Fire TV, and per-store consoles for Samsung and LG. The file requirements are identical to mobile; the difference is bookkeeping, one domain, many stores, and the field is easy to leave empty on a platform where the app already works. Channel operators without a real website publish a minimal site on the domain they control; the file is the point, not the design. Theads.txt for CTV guide covers the per-platform detail.
10Diagnostic path: when fill is mysteriously low
The silent rejection walkthrough, in order of likelihood:
- Fetch the file directly for the app's domain. Anything other than found and valid is the answer.
- If you started from the store listing's website field, compare the domain it resolves to against the domain you believe carries the file. A www versus apex split shows up here.
- Verify the account ID in the line against the ID in your dashboard for the ad system that reports low fill. A single transposed digit is invisible to the eye and fatal to the crawl.
- Check whether the low fill is one buyer or all buyers. One buyer indicates their crawl is stale; ask for a re-crawl with the file URL attached.
- Check robots.txt on the domain for rules that catch the file.
- If everything above is clean, the gap is probably not app-ads.txt: read the discrepancy guidance before blaming the file.
11FAQ
Crawl frequency is set by each buyer, and daily is the common pattern. Treat one cycle as the propagation window after any change, then confirm with the checker instead of assuming the change landed.
Yes. The file authorizes ad systems for the developer, with account IDs per line. Every app whose store listing resolves to that domain is covered by the same file.
No. The file is per developer domain, not per store or platform. What differs is where each store exposes the website field.
Yes. Any domain you control works, including a minimal company site. The file must sit at that domain root, and the store listing website field must point there.
Crawlers hold the last known good copy for a period, but policies differ and some systems shorten it. A down file is a revenue risk with no upside; host it like it is production infrastructure, because it is.
The last app-ads.txt reference you will need.
Stop managing the file by hand. Account-level monitoring crawls, validates and alerts, and the network enforces authorized selling on your behalf.
Checker · generator · guide · monitoring