In programmatic advertising, small technical errors in root server configuration can silently wipe out thousands of dollars in publisher earnings without throwing visible PHP fatal errors. Two of the most common yet widely misunderstood technical specifications in ad operations are Authorized Digital Sellers (ads.txt) and sellers.json.
If your website is missing a correctly formatted ads.txt file—or if your web server returns a 404, a trailing slash redirect, or an incorrect MIME type—programmatic demand-side platforms (DSPs) like Google Display & Video 360, The Trade Desk, and Amazon Advertising automatically disqualify your domain from advertising auctions. Bidders treat unverified publisher inventory as potential counterfeit ad domain spoofing, resulting in an immediate 30% to 70% collapse in advertising revenue.
In this AdOps technical guide, we will break down the IAB OpenRTB supply chain standards, demonstrate how to configure and validate a certified ads.txt file in Apache and Nginx, configure your Google AdSense seller information in sellers.json, and troubleshoot crawl errors to prevent revenue leakage.
1. Why ads.txt Is Mandatory: Stopping Domain Spoofing
Before the Interactive Advertising Bureau (IAB) introduced ads.txt, digital ad fraud was rampant. Malicious actors would create botnets or low-quality piracy websites, spoof the HTTP referrer header to claim they were nytimes.com or forbes.com, and sell millions of counterfeit impressions to unsuspecting corporate advertisers.
The ads.txt specification solves this by establishing a public cryptographic registry at the root of your domain (https://yourdomain.com/ads.txt). Advertisers crawl this text file to verify exactly which advertising exchange account IDs are authorized to sell inventory on your behalf.
2. The Anatomy of an ads.txt Record
Every line inside an ads.txt file consists of four comma-separated parameters:
# ads.txt Field Structure:
# <Ad System Domain>, <Seller Account ID>, <Relationship Type>, <Certification Authority ID>
google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0
- Field 1 (google.com): The canonical domain of the advertising exchange system.
- Field 2 (pub-XXXX): Your unique publisher account ID inside that advertising network.
- Field 3 (DIRECT or RESELLER):
DIRECTmeans you control the account directly.RESELLERindicates you authorized a third-party ad management company (like Mediavine or Raptive) to trade on your inventory. - Field 4 (f08c47fec0942fa0): The unique Certification Authority ID registered with the Trustworthy Accountability Group (TAG). For Google AdSense, this value is always
f08c47fec0942fa0.
3. Server Configuration: Apache & Nginx MIME Types
A frequent technical gotcha is web servers returning Content-Type: text/html instead of text/plain when serving ads.txt, causing the AdSense bot to reject the file as invalid.
# Nginx configuration for ads.txt
location = /ads.txt {
allow all;
default_type text/plain;
add_header Cache-Control "public, max-age=86400";
try_files \$uri =404;
}
4. Configuring sellers.json: Enabling "Transparent" Status
While ads.txt protects publishers from fraud, sellers.json protects advertisers by publishing an index of all legal entity names behind publisher accounts.
If your AdSense account is marked as "Confidential", advertisers cannot verify your corporate legal name, leading major DSPs to boycott your inventory.
How to Set sellers.json to Transparent in Google AdSense:
- Log into your Google AdSense Dashboard.
- Navigate to Account > Settings > Account Information.
- Locate "Seller information visibility".
- Select Transparent (Never leave as Confidential).
- In the "Business domain" field, enter your exact root domain without
https://(e.g.,aoneinfo.com). - Click Save. Changes propagate to Google's public
sellers.jsonfeed within 24 hours.
5. Automating ads.txt Validation with Python & GitHub Actions
In enterprise publishing networks managing multiple domains, accidental deletions during server deployments can cause catastrophic silent revenue loss. Automate daily ads.txt verification using this Python test:
import urllib.request
import sys
def verify_ads_txt(domain: str, required_pub_id: str):
url = f"https://{domain}/ads.txt"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (compatible; Googlebot/2.1)"})
try:
with urllib.request.urlopen(req, timeout=10) as resp:
content_type = resp.headers.get("Content-Type", "")
if "text/plain" not in content_type:
print(f"[FAIL] Invalid Content-Type: {content_type}")
sys.exit(1)
body = resp.read().decode("utf-8")
if required_pub_id in body:
print(f"[PASS] {domain} correctly advertises {required_pub_id}")
else:
print(f"[CRITICAL] Publisher ID {required_pub_id} missing from ads.txt!")
sys.exit(1)
except Exception as e:
print(f"[ERROR] Could not fetch ads.txt: {e}")
sys.exit(1)
if __name__ == "__main__":
verify_ads_txt("aoneinfo.com", "pub-1234567890123456")
6. Debugging 3 Common AdSense Crawl Errors
- Error: "ads.txt not found (404)": Verify the file exists in the web root (e.g.
public_html/ads.txt) rather than a CMS subfolder. - Error: "Redirect loop detected": Ensure
http://yourdomain.com/ads.txtissues a single 301 redirect tohttps://yourdomain.com/ads.txtwithout bouncing betweenwwwand non-www. - Error: "Unauthorized sellers detected": Audit reseller lines quarterly to purge inactive third-party ad networks that have ceased monetizing your inventory.
Summary: The Zero-Leakage AdOps Checklist
- HTTP 200 OK Check: Test
curl -I https://yourdomain.com/ads.txtto confirm status 200 andtext/plaincontent type. - No Subdomain Trailing Slashes: Ensure
wwwand non-wwwresolve directly to the file without circular redirects. - Transparent sellers.json Status: Maximize programmatic bids by verifying your business entity is publicly visible to global advertisers.
5. Automating ads.txt Validation with Python & GitHub Actions
In enterprise publishing networks managing multiple domains, accidental deletions during server deployments can cause catastrophic silent revenue loss. Automate daily ads.txt verification using this Python test:
import urllib.request
import sys
def verify_ads_txt(domain: str, required_pub_id: str):
url = f"https://{domain}/ads.txt"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (compatible; Googlebot/2.1)"})
try:
with urllib.request.urlopen(req, timeout=10) as resp:
content_type = resp.headers.get("Content-Type", "")
if "text/plain" not in content_type:
print(f"[FAIL] Invalid Content-Type: {content_type}")
sys.exit(1)
body = resp.read().decode("utf-8")
if required_pub_id in body:
print(f"[PASS] {domain} correctly advertises {required_pub_id}")
else:
print(f"[CRITICAL] Publisher ID {required_pub_id} missing from ads.txt!")
sys.exit(1)
except Exception as e:
print(f"[ERROR] Could not fetch ads.txt: {e}")
sys.exit(1)
if __name__ == "__main__":
verify_ads_txt("aoneinfo.com", "pub-1234567890123456")
6. Debugging 3 Common AdSense Crawl Errors
- Error: "ads.txt not found (404)": Verify the file exists in the web root (e.g.
public_html/ads.txt) rather than a CMS subfolder. - Error: "Redirect loop detected": Ensure
http://yourdomain.com/ads.txtissues a single 301 redirect tohttps://yourdomain.com/ads.txtwithout bouncing betweenwwwand non-www. - Error: "Unauthorized sellers detected": Audit reseller lines quarterly to purge inactive third-party ad networks that have ceased monetizing your inventory.
5. Automating ads.txt Validation with Python & GitHub Actions
In enterprise publishing networks managing multiple domains, accidental deletions during server deployments can cause catastrophic silent revenue loss. Automate daily ads.txt verification using this Python test:
import urllib.request
import sys
def verify_ads_txt(domain: str, required_pub_id: str):
url = f"https://{domain}/ads.txt"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (compatible; Googlebot/2.1)"})
try:
with urllib.request.urlopen(req, timeout=10) as resp:
content_type = resp.headers.get("Content-Type", "")
if "text/plain" not in content_type:
print(f"[FAIL] Invalid Content-Type: {content_type}")
sys.exit(1)
body = resp.read().decode("utf-8")
if required_pub_id in body:
print(f"[PASS] {domain} correctly advertises {required_pub_id}")
else:
print(f"[CRITICAL] Publisher ID {required_pub_id} missing from ads.txt!")
sys.exit(1)
except Exception as e:
print(f"[ERROR] Could not fetch ads.txt: {e}")
sys.exit(1)
if __name__ == "__main__":
verify_ads_txt("aoneinfo.com", "pub-1234567890123456")
6. Debugging 3 Common AdSense Crawl Errors
- Error: "ads.txt not found (404)": Verify the file exists in the web root (e.g.
public_html/ads.txt) rather than a CMS subfolder. - Error: "Redirect loop detected": Ensure
http://yourdomain.com/ads.txtissues a single 301 redirect tohttps://yourdomain.com/ads.txtwithout bouncing betweenwwwand non-www. - Error: "Unauthorized sellers detected": Audit reseller lines quarterly to purge inactive third-party ad networks that have ceased monetizing your inventory.