Your community site is almost certainly losing ad revenue in two completely different ways, and most site owners only ever hear about one of them.
The first leak is invisible: unauthorized resellers quietly selling your ad inventory through the programmatic supply chain, skimming margin before a single dollar reaches you, because your site never published a file that tells ad exchanges who is actually allowed to sell your space. That file is called ads.txt, and a huge share of small and mid-size publishers either don’t have one, have a broken one, or haven’t touched it since the day a developer copy-pasted it from a tutorial.
The second leak is the one everyone already knows about: a meaningful slice of your logged-in members, often your most engaged, most technical members, are running an ad blocker and never see your ads at all. No impression, no revenue, no error message telling you it happened.
Both leaks matter more on a community site than on a typical blog, because community sites have something a blog doesn’t: logged-in, returning, habitual visitors who generate far more pageviews per person, and who skew toward exactly the demographic most likely to install a blocker. If you’re running display ads, AdSense, or a self-serve advertiser portal like WB Ad Manager on top of BuddyPress, see our roundup of WordPress ad management plugins if you haven’t picked a tool yet, this is worth fixing properly rather than guessing.
This guide covers what ads.txt actually is, how to set it up correctly on WordPress, the mistakes that quietly break it, real current ad-blocker adoption numbers, and why first-party, direct-sold ads tend to survive ad blockers better than third-party programmatic tags.
Table of Contents
- What Is ads.txt (and app-ads.txt)?
- How to Set Up ads.txt Correctly on WordPress
- Common ads.txt Mistakes That Cost You Money
- Real Ad-Blocker Adoption Numbers, and What They Mean for a Community Site
- Why Direct-Sold, First-Party Ads Survive Blockers Better
- A Real-World Scenario
- FAQs
- Conclusion
What Is ads.txt (and app-ads.txt)?
ads.txt stands for Authorized Digital Sellers. It’s an IAB Tech Lab standard, created by the OpenRTB Working Group, that lets a publisher publicly declare exactly which companies are allowed to sell their ad inventory. app-ads.txt is the same idea applied to mobile apps instead of websites, hosted on the domain listed in the app’s store listing.
Before ads.txt existed, a fraudulent operator could spin up a fake version of your site’s inventory, sell “your” ad space through a programmatic exchange, and pocket the money, while the buyer had no reliable way to confirm they were actually buying placements on your domain. This is called domain spoofing, and it’s a real, widely documented chunk of programmatic ad fraud. ads.txt doesn’t eliminate fraud by itself, but it gives exchanges and buyers a machine-readable way to verify authorization before a bid clears, and most major exchanges (Google Ad Manager / AdSense among them) now simply won’t serve certain unauthorized inventory, or discount it, when a site’s ads.txt doesn’t list the seller.
The file itself is boring on purpose. It’s a plain text file, one line per authorized seller, with four comma-separated fields:
- Domain, the ad system’s domain (e.g.
google.com) - Publisher account ID, your unique seller ID with that ad system
- Relationship type,
DIRECTif you have a direct account with that system,RESELLERif they’re authorized to resell on your behalf through an intermediary - Certification authority ID (optional), the TAG-ID or similar certification for that seller, when applicable
A real line looks like this:
google.com, pub-0000000000000000, DIRECT, f08c47fec0942fa0
Later revisions of the spec (1.1 and 1.0.3) added a few optional variables, OWNERDOMAIN, MANAGERDOMAIN, and INVENTORYDOMAIN, mainly to handle sites with multiple owned domains or sites managed by a separate commercial entity. Most single-site WordPress publishers never need these, but it’s worth knowing they exist if your community spans several domains or you work with a management company.
How to Set Up ads.txt Correctly on WordPress
The single most important rule: ads.txt must be served from your bare root domain, https://yourcommunity.com/ads.txt, not from a subfolder, not from /wp-content/, not from a CDN path that doesn’t mirror the root. Crawlers check the root and only the root. A perfectly correct file sitting at the wrong URL is functionally the same as not having one.
There are two reliable ways to get it there on a WordPress install.
Method 1: A Static File at the Root (preferred when your host allows it)
- Create a plain
.txtfile named exactlyads.txt(lowercase, no capital letters, no trailing characters). - Add one line per authorized ad system, pulling the exact account ID and relationship type from each network’s own ads.txt snippet, AdSense, any header-bidding partner, and WB Ad Manager’s AdSense placements if you’re running them, all need their own line.
- Upload it via FTP or your host’s File Manager directly into the web root, the same folder that contains
wp-config.php, notwp-content. - Confirm it loads at
yourdomain.com/ads.txtin a private browser tab, with no redirect and no WordPress theme wrapping it.
A static file is the cleanest option because it’s served directly by the web server, bypasses WordPress entirely, loads fast, and can’t be broken by a plugin conflict or a caching layer misbehaving.
Method 2: Plugin-Managed ads.txt (when root upload isn’t possible)
Some managed WordPress hosts lock down root-level file uploads, and some multisite or subdomain setups make a single static file impractical. In that case, a small dedicated ads.txt plugin (several exist, free, single-purpose) intercepts the request for /ads.txt and serves content you manage from inside wp-admin, without ever needing FTP access. This is slightly slower than a static file because WordPress has to bootstrap to answer the request, but it’s reliable and lets non-technical site owners update it without touching a server.
Either way, treat ads.txt as a living file, not a set-and-forget task. Every time you add, drop, or change an ad network, header-bidding partner, or the ad-serving configuration inside a tool like WB Ad Manager, update the file the same day. A stale ads.txt that’s missing a currently-active seller is almost as damaging as having none, it tells exchanges that seller isn’t authorized, when they actually are, and you lose bids you should be winning.
Multisite and Subdomains
If your community runs on a subdomain structure (forum.example.com, shop.example.com) and serves ads from more than one of them, each subdomain that serves ads typically needs its own ads.txt at its own root, unless you’re explicitly using the OWNERDOMAIN/MANAGERDOMAIN fields to consolidate authorization under one canonical domain. Don’t assume the root domain’s file automatically covers every subdomain, verify with each ad network’s documentation.
Common ads.txt Mistakes That Cost You Money
Most of the damage isn’t from never having a file. It’s from having one that’s silently wrong.
- Wrong location. Placed in a subdirectory, behind a CDN path that doesn’t mirror root, or only reachable via
www.when exchanges check the bare domain (or vice versa). - Stale entries. You switched ad networks or added header bidding a year ago and never updated the file, so currently active sellers aren’t listed, and inactive ones still are.
- DIRECT vs RESELLER confusion. Listing a reseller relationship as DIRECT (or the reverse) misrepresents the supply chain and can get inventory flagged or devalued by buyers running compliance checks.
- Duplicate or conflicting lines. Copy-pasting snippets from multiple partners’ documentation without deduping often produces two different account IDs for the same ad system.
- Blocked by robots.txt or a security plugin. ads.txt must be publicly crawlable by bots. A firewall rule or robots.txt directive that blocks bot traffic to text files can inadvertently hide it.
- Caching the old version indefinitely. A CDN or page cache serving a cached ads.txt from months ago after you’ve updated the source file. Set a short cache TTL specifically for this path, or purge it manually after every edit.
- Wrong account ID copy-pasted from the wrong network’s dashboard, easy to do when managing several ad accounts at once, and it silently invalidates that whole line.
- Treating app-ads.txt as optional if your community also has a companion mobile app serving ads, it needs its own file on the domain your app store listing points to, following the same rules.
A free ads.txt validator (IAB Tech Lab and several ad tech vendors publish them) will catch most of these in under a minute. Run one after every change, not just once at setup.
Real Ad-Blocker Adoption Numbers, and What They Mean for a Community Site
Ad-blocker adoption isn’t a fringe habit anymore, and the trend line has been steadily up, not down.
Per GWI data reported via DataReportal, roughly 29.5% of internet users worldwide used an ad blocker as of Q2 2025, around 1.77 billion people. In the United States specifically, GWI/DataReportal put usage at about 32.5% of internet users. Blockthrough, which measures differently (device-level rather than survey-based), reports a somewhat lower but still substantial 27% on desktop and 22% on mobile, tablet, and connected TV combined. The exact number moves depending on methodology, but every credible source agrees on the direction: adoption has grown steadily, from roughly 764 million global users in Q1 2020 to the 1.77 billion figure in Q2 2025.
There’s also a demographic skew worth knowing if you run a niche community: GWI data shows men use ad blockers more consistently than women across most age brackets, with adoption among males aged 25-34 reaching roughly 34.5%, against 28.3% for women in the same bracket. If your community’s core demographic leans toward tech, gaming, development, finance, or other traditionally male-skewing hobbyist niches, common territory for BuddyPress communities, your real blocker rate is plausibly higher than the global average, not lower.
Why does this matter more for a community site than a general blog? Three structural reasons:
- Pageviews per visitor are higher. A logged-in member browsing activity feeds, groups, forums, and profiles generates far more pageviews in a session than a one-time blog reader. Every one of those pageviews is a potential blocked impression, and the multiplier effect is larger than on a site where most traffic is single-pageview search visits.
- Your most valuable members are your most likely blockers. Power users, moderators, top contributors, the people who return daily, tend to be more technically sophisticated than a casual visitor, which correlates with blocker adoption. You’re disproportionately losing impressions from exactly the audience segment generating the most pageviews.
- Logged-in sessions are long. Ad-blocker extensions, once installed, apply to every page for the rest of that browsing session (and usually every session after, since it’s a persistent browser extension). There’s no “the blocker wore off” recovery the way there might be with a dismissed cookie banner.
None of this means display advertising on a community site is a lost cause. It means the inventory you can’t reliably monetize through third-party programmatic tags is a real, measurable fraction, likely higher than the global average for most niche communities, and the fix isn’t “block the blocker,” it’s shifting a meaningful share of your inventory to a format that blockers are structurally less effective against. The same logic applies if you’re running sponsorship slots on a niche directory built on WordPress: direct-sold listings monetize the blocker-heavy segment of your traffic that programmatic banners never will.
Why Direct-Sold, First-Party Ads Survive Blockers Better
Most consumer ad blockers work off filter lists (EasyList and similar) that target known third-party ad-serving domains, known tracking scripts, and common ad-container naming patterns, class names like ad, advertisement, banner-ad, iframe sources pointing at known ad-exchange domains, and so on. A third-party programmatic tag loading creative from an external ad server is exactly the pattern these lists are built to catch, and they catch it reliably.
A direct-sold, first-party-rendered placement looks structurally different to a filter list. When an advertiser buys a placement through a self-serve advertiser portal, the model WB Ad Manager‘s Pro advertiser portal uses, the creative is typically stored and served from your own domain, rendered inside your own templates, without a third-party ad-server call in the middle. There’s no known ad-exchange domain for a blocklist to flag, because there’s no exchange in the request path at all. That doesn’t make the placement invisible to every blocker forever (a sufficiently generic class name like class="ad-banner" can still get caught by generic pattern rules), but it removes the single biggest, most reliable signal blockers use, and it’s why native, in-feed, first-party placements consistently report higher real-world viewability than third-party banner tags on blocker-heavy audiences.
Practically, that gives you two levers on a community site running something like WB Ad Manager, and the honest answer is you’ll likely want both:
- Programmatic / AdSense placements fill inventory automatically, including on pages and times you’d never sell manually, and they still need a correct, current ads.txt to avoid the reseller-fraud leak covered above.
- Direct-sold, first-party placements, sponsorships, a classifieds listing, an advertiser-portal banner rendered from your own media library, survive ad-blocker-heavy segments of your audience better, and you keep a larger share of the revenue since there’s no exchange taking a cut.
One honest caveat worth stating plainly: WB Ad Manager itself, as of this writing, doesn’t include a dedicated ads.txt management feature, no built-in generator, validator, or auto-sync for the file. It manages the ad placements, scheduling, geo-targeting, and (in Pro) the advertiser portal and revenue reporting, but ads.txt is a separate, root-level file you’ll still maintain by hand or with a single-purpose ads.txt plugin alongside it. That’s a reasonable division of responsibility, ads.txt is a site-wide authorization file, not really an “ad placement” concern, but don’t assume installing an ad plugin, any ad plugin, automatically handles it for you. None of the mainstream WordPress ad managers currently do this out of the box.
A Real-World Scenario
To make this concrete, here’s a composite, illustrative scenario built from the patterns above rather than a specific site’s audited numbers, the kind of situation that shows up repeatedly on mid-size BuddyPress communities.
A 40,000-member hobbyist community, say, a BuddyPress-powered forum for a technical hobby, runs AdSense through a placement plugin and has never touched ads.txt because “the ads are showing up fine.” They are showing up; that’s not the problem. The problem is invisible: a chunk of their programmatic bids are clearing through unauthorized resellers at a discounted rate, because nothing on their domain tells buyers who’s actually authorized to sell it, so some demand-side platforms apply a trust penalty or skip the inventory entirely rather than risk buying spoofed placements.
Layer on the audience skew: a technical hobbyist community plausibly has blocker adoption well above the ~30% global average, concentrated among the most active members generating the most pageviews. Between the two leaks, some fraction of legitimate bids lost to the missing-ads.txt discount, and roughly a third-plus of logged-in pageviews never rendering a third-party ad at all, it’s entirely plausible for total realized ad revenue to sit meaningfully below what the same traffic and the same ad inventory should be generating, with nothing in Google Analytics or the ad network dashboard flagging either cause directly.
The fix mirrors the two leaks: publish a correct, current ads.txt so legitimate programmatic bids clear at full value, and move a portion of inventory, particularly the highest-traffic logged-in pages, to direct-sold, first-party placements through an advertiser portal, so that revenue doesn’t depend on surviving a blocker at all.
FAQs
Does ads.txt block ad blockers?
No. ads.txt and ad blockers address two completely unrelated problems. ads.txt stops unauthorized resellers from fraudulently selling your inventory in the programmatic supply chain. It has no effect on whether a visitor’s browser extension blocks the ad from rendering.
Do I need ads.txt if I only run AdSense?
Yes. AdSense specifically checks ads.txt and can limit or restrict monetization on domains where it isn’t listed correctly, especially as enforcement has tightened over recent years. “Just AdSense” is still a programmatic relationship that needs declaring.
Can I just copy another site’s ads.txt file?
No. Every line needs your own publisher account ID for each network. Copying another site’s file wholesale either does nothing (wrong IDs mean no match) or, worse, falsely authorizes someone else’s account to claim association with your domain.
Where exactly does the file need to live?
At the bare root of your domain: https://yourdomain.com/ads.txt, publicly accessible, not behind a login, not in a subfolder, not blocked by robots.txt or a firewall rule.
How often should I update it?
Every time you add, remove, or change an ad network, header-bidding partner, or reseller relationship. Also re-validate it after any hosting migration, CDN change, or security-plugin update, since any of those can accidentally break the root path.
What’s the difference between ads.txt and app-ads.txt?
Same standard, same format, different surface. ads.txt covers your website; app-ads.txt covers a companion mobile app, hosted on the domain your app store listing designates as the developer’s website.
Will fixing ads.txt alone recover my full ad-blocker losses?
No, and it’s not meant to. ads.txt only addresses the unauthorized-reseller leak. Ad-blocker-driven impression loss is a separate problem that’s better addressed by shifting some inventory to direct-sold, first-party placements rather than relying entirely on third-party programmatic tags.
Do native or direct-sold ads always bypass ad blockers?
Not always, and no one should claim “always.” They’re structurally harder for blocklists to catch because there’s no third-party ad-server domain in the request, but a generic HTML class name like class="advertisement" can still trigger a generic cosmetic filter. Good markup hygiene still matters.
Does WB Ad Manager handle ads.txt for me?
Not currently. WB Ad Manager manages ad placements, scheduling, geo-targeting, and (in Pro) the self-serve advertiser portal and revenue reporting, but ads.txt is a separate root-level file you maintain yourself or with a dedicated single-purpose ads.txt plugin alongside it.
Is a plugin-managed ads.txt as reliable as a static file?
It’s reliable, but a genuine static file at the server root is generally preferable where your host allows it, since it’s served without WordPress bootstrapping and can’t be affected by a plugin conflict. Use a plugin-managed version when root-level file access genuinely isn’t available.
Summary
Ads.txt and ad blockers aren’t the same problem wearing two names, and treating them as one leads to fixing neither. Ads.txt is a supply-chain authorization file that stops middlemen from skimming programmatic revenue you’re entitled to; it takes an afternoon to set up correctly and almost no ongoing effort beyond keeping it current. Ad-blocker adoption is a structural audience behavior, north of 29% globally and climbing, likely higher on a technically-skewed community, that no text file will solve, and that’s genuinely better addressed by diversifying toward direct-sold, first-party inventory that doesn’t depend on surviving a blocklist.
Run both fixes together: a correct, current ads.txt for the programmatic revenue you’re already supposed to be collecting, and a growing share of direct-sold placements for the audience segment that will never see a third-party tag at all.
Plug the Leak with WB Ad Manager
WB Ad Manager gives your Reign-powered community five ad types and 16+ placements, including native BuddyPress feed and bbPress reply slots, plus geo-targeting, scheduling, and a full REST API, free. Upgrade to Pro for the self-serve advertiser portal with wallet, A/B testing, and a revenue dashboard with geo/device analytics, so you can sell direct placements to local advertisers without chasing invoices by hand.