scan

free scan · public files only · result by email

Three scores from the files you already publish, and the three findings to fix first.

Enter a domain. We fetch ads.txt and app-ads.txt, pull sellers.json for every seller you list, read /.well-known/adagents.json, check robots.txt and llms.txt for the AI crawlers, and detect Prebid.js on your homepage. No login, no upload, nothing from your ad server.

Public files only. Read-only, the same way any crawler reads you. Most scans finish in under a minute and the result goes to this address.

sample scan · example.com · illustrative values

GET /ads.txt200212 lines

1google.com, pub-0000000000000000, DIRECT, f08c47fec0942fa0   # DIRECT · sellers.json match · PUBLISHER2ssp-one.example, 11822, DIRECT                               # DIRECT · sellers.json match · PUBLISHER3ssp-two.example, 48213, DIRECT, 0000000000000000             # DIRECT · sellers.json match · BOTH47relay-ads.example, 7781, RESELLER                            # relay-ads.example serves no sellers.json48relay-ads.example, 7781, RESELLER                            # duplicate of line 4791openhop.example, 10442, RESELLER, 0000000000000000           # seller_type=INTERMEDIARY · is_confidential=1130ssp-two.example 48213 DIRECT                                 # malformed · missing separators212# end of file
  • 212 lines
  • 37 DIRECT
  • 173 RESELLER
  • 2 duplicates
  • 1 malformed
  • 31 unverifiable
  • 3 confidential
  • GET /app-ads.txt404
  • GET sellers.json · 41 domains37 found4 return nothing
  • GET /.well-known/adagents.json404
  • GET /robots.txt200Google-Extended disallow / · GPTBot, ClaudeBot, PerplexityBot allow
  • GET /llms.txt404
  • Prebid.jsfound9.14.0 · 14 bidder adapters
Supply-path hygienesample
Agent readinesssample
AI discoverabilitysample

An agent reading example.com today finds no adagents.json.

checks

What we fetch and what we flag

Everything below is fetched over HTTPS from your domain and from the seller domains your ads.txt names. Nothing comes from you.

Files fetched, what is checked in each, and an example flag
FileWhat we checkA flag looks like
/ads.txt and /app-ads.txtLine count. DIRECT versus RESELLER count. Duplicate lines. Malformed lines. RESELLER entries with no matching sellers.json record. Seller domains that return no sellers.json at all. seller_type recorded as PUBLISHER, INTERMEDIARY or BOTH. Entries whose seller is marked is_confidential.9 RESELLER lines point at 4 seller domains that serve no sellers.json
sellers.json, one per seller domain in your ads.txtFetched for every seller domain you list. Each of your lines matched back by seller_id. Type and confidentiality recorded per entry.seller_id 10442 at openhop.example is INTERMEDIARY with is_confidential=1
/.well-known/adagents.jsonPresent or absent. Valid JSON against the AdCP schema; a parse failure is a finding. Number of authorized agents. Agents with no reachable endpoint. Whether your own domain appears as an authorized seller agent.adagents.json returns 404
/robots.txt and /llms.txtRules for GPTBot, ClaudeBot, PerplexityBot, Google-Extended and the rest of a crawler list kept in a config file because it changes monthly. llms.txt present or absent.Google-Extended disallowed on / · llms.txt absent
Prebid.jsDetected on the homepage or not, from one headless fetch. Version string. Number of bidder adapters configured, where pbjs.getConfig or adUnits is readable from page source.Prebid 9.14.0 detected · 14 bidder adapters

Every raw check result is stored, not just the score. If a file is missing, times out, or fails to parse, that check records its own failure and the scan continues.

scores

Three scores, 0 to 100

Every check writes its own result, pass or fail, with the detail that produced it. The three scores are computed from those results and weighted equally for now. Because every raw result is stored, the weights can change later without crawling you again.

Supply-path hygienewarnsample
  • critical under 40
  • warn 40 to 69
  • good 70 and up

Supply-path hygiene

Moves with duplicate and malformed lines, RESELLER entries with no matching sellers.json record, seller domains that publish no sellers.json at all, and sellers marked is_confidential.

openhop.example/sellers.json · the record behind ads.txt line 91
{  "seller_id": "10442",  "seller_type": "INTERMEDIARY",  "is_confidential": 1}
Agent readinesscriticalsample

Agent readiness

Moves with whether /.well-known/adagents.json exists, whether it parses against the AdCP schema, how many of the listed agents have a reachable endpoint, and whether your own domain is listed as an authorized seller agent. If the file is absent, every check in this group fails, which is why the sample reads 0. Prebid.js detection is recorded alongside it, with the version and the bidder adapter count.

/.well-known/adagents.json · a file that exists but authorizes no one
{  "authorized_agents": [  ]}

A 404 and an empty array score the same. An agent finds no authorized seller agent either way.

AI discoverabilitygoodsample

AI discoverability

Moves with what robots.txt says to GPTBot, ClaudeBot, PerplexityBot, Google-Extended and the rest of the crawler list, and with whether llms.txt exists. The score counts which crawlers can read you. Whether to open or close the gate depends on your contracts and your traffic. The report says what the gate says today, so the choice is yours and it is deliberate.

/robots.txt · the rules behind the sample AI discoverability score
User-agent: GPTBotAllow: /
User-agent: ClaudeBotAllow: /
User-agent: PerplexityBotAllow: /
User-agent: Google-ExtendedDisallow: /

Allow lines carry the good tint and Disallow lines the critical tint. The same three colors mark the score bands: critical under 40, warn 40 to 69, good 70 and up.

What lands in your inbox

Subject: Scan result for example.com

Supply-path hygiene 61 · Agent readiness 0 · AI discoverability 74

Top three findings

  1. 31 RESELLER lines cannot be verified. 9 point at 4 seller domains that publish no sellers.json, and 22 have no matching seller_id.
  2. /.well-known/adagents.json is absent. An agent reading your domain finds no authorized seller agent.
  3. robots.txt disallows Google-Extended on /. llms.txt is absent.

Want the full revenue audit? Reply to this email.

One HTML email. No PDF, no portal, no login. The figures are the sample above.

input · one Google Ad Manager export, CSV, daily, 13 months + your Prebid config / output · fixed-format PDF report + readout call

Put a range on the revenue you are not booking.

The scan reads what is public. The audit reads your ad server. You send one Google Ad Manager export and your Prebid config. We send back a fixed-format report and walk through it with you on a call. Every number in it carries the assumption that produced it, as a low and a high.

An abstract network seen from above at night: one bright point at the left branches through a layer of intermediaries to a cluster of endpoints at the right, and a few paths end in empty ground.An abstract network seen from above at night: one bright point at the left branches through a layer of intermediaries to a cluster of endpoints at the right, and a few paths end in empty ground.

Four places revenue hides in a GAM export

Fill and match

Fill rate by ad unit, device and month, with every unit under your own median flagged. Unfilled impressions multiplied by your median eCPM is the unrealized-revenue estimate, and that assumption is printed next to the number. Your fill rate, eCPM by device and reseller count are set against benchmarks being built from weekly scans of 200 publisher domains and from prior audits. Where a benchmark comes from public sources instead, the report says so on the page where it is used.

Demand channel mix

Revenue share and eCPM for open auction, private auction, preferred deal, programmatic guaranteed and header bidding, month by month. Any channel whose share moved more than 10 points in six months is called out with the months it moved.

Supply-path waste

The scan's ads.txt findings crossed with your revenue by bidder and SSP. Resellers earning under 0.5% of revenue are listed as removal candidates. SSPs in your Prebid config but absent from ads.txt, and the reverse, are listed with the revenue at stake.

Prebid configuration

Timeout against norms, flagged under 1000 ms or over 3000 ms. Bidders configured with no revenue in the last 90 days. Price floors present or absent. User ID modules are listed for your review. Enabling them is a judgment call and the report says so.

The Deep tier adds three sections

Agent readiness gap list

Everything the scan checks, plus whether your Prebid setup includes the seller-agent module and whether it is configured, whether an agent in your adagents.json answers an AdCP discovery call, and whether your inventory and first-party signals are described anywhere a machine can read them. Our discovery client is read-only, and a test in the codebase proves it cannot start a transaction. The output is a gap list in the form 'to sell to an agent, you need X, Y and Z', each gap mapped to an action with a rough effort estimate.

Leading indicators

Which of your inputs lead daily revenue and eCPM, at what lag from 0 to 60 days, and how strongly. Candidates are ad requests, fill rate, active bidder count, Prebid timeout changes treated as step events, and page views and direct-traffic share if you share analytics. Series are differenced or detrended first. A relationship has to hold in both halves of your date range. One that fails that test is not reported, and the table says it was dropped instead of leaving it out silently. Step changes in revenue or eCPM are listed with whatever else changed in the same window.

format example, not a result
leading signallag (days)strengthholds in both halves?plausible mechanism
ad requests9strongyesmore requests reach auction before eCPM adjusts

Your ad requests lead revenue by about 9 days, consistently. Your reseller changes do not show a measurable effect.

60-day calibration scorecard

Every quantified prediction in the report is recorded at delivery. Sixty days later we score it against a fresh export as a hit, a miss or inconclusive, with the actual number beside the range.

Three rules hold in every report.

  • Every finding cites the numbers that produced it. No finding without a number.
  • Every estimate is a low and a high. Never a point.
  • The appendix lists the methodology, the assumptions, the data coverage, and what we did not look at.

report structure, in bound order

  1. One-page summary · three scores · top five findings by revenue impact · total opportunity range
  2. Supply-path hygiene
  3. Yield
  4. Prebid configuration review
  5. Agent readiness
  6. Leading indicators
  7. Recommended actions in order, with effort and impact
  8. Appendix · methodology · assumptions · data coverage · what we did not look at

Delivered as a PDF to a private Drive folder, with a readout call. No dashboard, no login, nothing to maintain after we leave.

handoff

One export and one config.

Both tiers start with a short intake and a one-page sheet that tells your ad-ops team exactly which Google Ad Manager report to export. You drop the files in a private Drive folder. Nobody from your team logs in to anything.

GAM report

source
Google Ad Manager report export, CSV
dimensions
Date · Ad unit · Advertiser/Order · Demand channel · Device
metrics
Impressions · Ad requests · Matched requests · Unfilled · Revenue · eCPM
grain
daily
history
13 months back, minimum

Prebid config

source
pbjs.getConfig() dump, or the wrapper config file
extracted
bidders · timeout · price granularity · currency · user ID modules · floors
optional
SSP-side revenue exports, one CSV per SSP, reconciled against GAM

Gaps larger than two days and currency mismatches are flagged on ingest, before any analysis runs. Raw files stay in private object storage next to the normalized rows, so every number in the report can be reproduced. Google Ad Manager exports only, for now.

ranges

No finding without a number. No number without a range.

A finding without a number does not go in the report. Each one shows the evidence that produced it, an estimated revenue impact as a low and a high, the effort to fix, and a priority. We do not publish point estimates, because we would be guessing the second digit.

actual, added at day 60
This bar is the unit of the findings table and of the scorecard below.

format example, not a result

Removing the six resellers below 0.5% of revenue should move eCPM by +3% to +7% within 60 days.

A range bar drawn in pale blue pencil on a sheet of heavy paper, a short tick at each end and a hollow circle to the right, with the pencil lying beside itA range bar drawn in pale blue pencil on a sheet of heavy paper, a short tick at each end and a hollow circle to the right, with the pencil lying beside it
format example, not a result
FindingEvidenceImpact (low / high)EffortPriority
Remove 6 resellers under 0.5% of revenue6 of 41 seller domains, 0.3% of 13-month revenue combined; 4 of the 6 are among the 31 unverifiable lineseCPM +3% / +7% within 60 dayslow1
Raise Prebid timeout from 800 mstimeout 800 ms, under the 1000 ms threshold; 3 of 14 configured bidders show no revenue in 90 daysrevenue +1% / +4%low2
Fill under site median on 3 mobile units3 units at 71 to 78% fill against an 86% site median; 4.1M unfilled impressions × $0.92 median eCPM$2.9k / $4.6k per month unrealizedmedium3
scorecard

Sixty days later, we score ourselves.

At delivery, every quantified prediction is written down with its metric, its low and high, and a 60-day window. That record cannot be edited afterward. After 60 days you send a fresh export, and each prediction is scored with the actual number beside the range. Hit means the actual landed inside the range. Miss means it landed outside. Inconclusive means the follow-up data did not cover the window. All three stay on the list. A scorecard that only shows hits is marketing.

format example, not a result

  • metric eCPM · predicted +3% / +7% · window 60 d · actual +4.4% · hit
  • metric fill, unit /mobile/article_1 · predicted +5 / +9 pts · window 60 d · actual +1.2 pts · miss
  • metric revenue, header bidding share · predicted +2 / +4 pts · window 60 d · 11 days of data missing · inconclusive

There is no hit rate on this page because none has been earned yet. When five or more audits have been scored, the aggregate goes here, misses included.

predictions recorded 0 · scored 0 · hit 0 · miss 0 · inconclusive 0

A printed sheet of eight ruled rows, each holding a short range bar with a tick at each end; a green dot sits inside the bar on five rows, a red dot sits outside it on two, and one row has no dotA printed sheet of eight ruled rows, each holding a short range bar with a tick at each end; a green dot sits inside the bar on five rows, a red dot sits outside it on two, and one row has no dot
tiers

Rapid or Deep

Fixed fee per tier, quoted on the call. Deep is booked with a 50% deposit.

What the Rapid and Deep tiers include
What each tier includesRapidDeep
InputsOne GAM export and your Prebid configThe same, plus a fresh export at day 60
Supply-path hygiene, crossed with revenue by bidder and SSPincludedincluded
Fill and match, demand channel mixincludedincluded
Prebid configuration reviewincludedincluded
Agent readiness at scan depth, AI discoverabilityincludedincluded
Fixed-format PDF report with the appendix, and a readout callincludedincluded
Agent readiness gap list with the read-only AdCP discovery checknot includedincluded
Leading indicators and step changesnot includedincluded
Predictions recorded at delivery and the 60-day calibration scorecardnot includedincluded
Three report pages fanned on a desk, each with one small chart and wide marginsThree report pages fanned on a desk, each with one small chart and wide margins

Not sure which? Book the call and bring your scan result.

limits

What we do not look at

Ad servers
Any ad server other than Google Ad Manager. Support arrives when a client asks for it.
Your files
We never edit ads.txt, app-ads.txt, adagents.json, robots.txt or a Prebid config. The report recommends, in order, with effort and impact. Your team decides.
Your site
The scan reads public files and loads your homepage once in a headless browser to detect Prebid.js. Nothing is placed, tagged or injected.
Transactions
The AdCP client performs discovery only, and a test proves it.
Real time
There is no monitoring and there are no alerts. A scan is a snapshot with a timestamp.

Every report's appendix repeats this list for that engagement, with the data coverage we actually had.

questions

Questions a yield manager asks

Does the free scan need anything from Google Ad Manager?
No. It reads files anyone can fetch from your domain, plus the scripts your homepage loads, to detect Prebid.js.
What if the scan finds nothing wrong?
Then you get three good scores and three small findings, and we say so. The audit is for publishers whose scan points at money, or who want the numbers behind a decision they already suspect.
Which AI crawlers do you check?
GPTBot, ClaudeBot, PerplexityBot, Google-Extended and others. The list lives in a config file and is updated as new crawlers appear, because it changes monthly.
What do I export for the audit?
One GAM report at daily grain, at least 13 months back, with the dimensions and metrics listed above, plus your Prebid config as a pbjs.getConfig() dump or the wrapper file. The intake sheet says exactly what to request.
What does the audit cost?
A fixed fee per tier, quoted on the call. Deep is booked with a 50% deposit.
Will you change my ads.txt or Prebid config?
No. The report recommends, in order, with effort and impact. Your team makes the changes.
What is the AdCP discovery check?
A read-only call to each agent listed in your adagents.json to see whether it responds. It cannot start a transaction, and a test in the codebase proves that.
What happens to my data?
Raw exports and fetched files are kept in private object storage next to the normalized rows, so every number in the report can be reproduced. The agreement includes a data-partnership clause allowing anonymized, aggregated use for benchmarking. You read it before you sign.
What if a prediction misses?
It is marked miss, with the actual number beside the range, and it stays on your scorecard. The aggregate we publish once five audits are scored includes the misses.
Other ad servers?
Google Ad Manager only for now. Another ad server means one adapter file on our side, so ask.
scan a domain

Start with the scan. Call when it finds something.

Run the free scan first. If the findings are small, you are done, and it cost you an email address. If they point at money, book a call. We will tell you which tier fits and send the sheet that says what to export.

Public files only. Most scans finish in under a minute.

Or book a call about the audit.