Find bugs in your ad stack
Bids arrive too late, targeting goes wrong, consent gets lost, ads fail to deliver, and often nothing on the page shows it. AdLinter traces the ad flow in a real browser and shows where it breaks.
-
- pbjs auctionInit 2 ad units
- pbjs bidRequested 8 bidders
- pbjs auctionInit same 2 units, +37 ms
AuctionPrebid started a second auction for the same two ad units 37 ms after the first, so eight bidders got duplicate requests.
-
- pbjs auctionInit one slot
- GET /gampad/ads auction still open
- pbjs auctionEnd 676 ms after the request
Ad server17 of 19 ad requests were sent before their header auction ended, and 8 bids came back too late to be included.
-
- __tcfapi useractioncomplete purpose 1 granted
- pbjs auctionInit
- POST /openrtb2/auction no regs, no user
ConsentAfter the visitor accepted, a Prebid Server bid request went out with no regs or user object, so it carried no consent string.
-
- slotRenderEnded creative rendered
- slot height 90 → 250 px
- layout-shift 0.081, content moved 160 px
PageThe slot grew from 90 to 250 px as the creative rendered, and the content below it moved 160 px down.
-
- GET /gampad/ads Prebid line item served
- pbjs bidWon pubmatic
- ads.txt no line for the winning seller account
Ad serverThe winning bid came through the publisher’s own PubMatic account, which is missing from the site’s ads.txt.
-
- __tcfapi gdprApplies: true
- sync doubleclick.net gdpr=0
- sync criteo.com gdpr=0
ConsentCookie syncs to Google and Criteo sent gdpr=0 while the page’s CMP reported that GDPR applies.
What happens during a scan
From a single web address, AdLinter reconstructs the ad flow and turns it into findings backed by evidence, in minutes.
-
Provide a web address
AdLinter only needs a publicly accessible page. No tag, integration or code changes.
-
The page runs in a real browser
AdLinter accepts consent, scrolls the page and waits for ad refreshes while recording the requests, events and consent signals behind each ad.
-
AdLinter reconstructs the ad flow
It connects what happened across consent, bidding, ad serving and rendering, then uses rules and heuristics to find where the actual flow diverged from the expected one, and AI to check each finding.
-
Review the findings
Each finding explains what happened, why it matters, and the requests, events and timestamps that prove it. The scan and analysis take about 3 minutes.
Examples from live sites
Findings from live publisher sites.
-
Header bidding
Ad requests sent before the header auction ended
On an Indian news site, 17 of the page’s 19 ad requests went to the ad server 270 to 676 ms before the header auction for their slot had finished. Eight bids arrived after the request had left and never reached the ad server.
0 msAd request sent 676 ms +676 msAuction ends17 of 19 requests early · 8 bids too late -
Header bidding
Two configured bidders missing from the Prebid build
On a French news site, two bidders were in the Prebid config but had no adapter or alias registered in the site’s Prebid build. Prebid never built a bid request for either, and logged the same warning six times for each.
Trying to make a request for bidder that does not exist: adagio_s2s×6
Trying to make a request for bidder that does not exist: gravity-apn_s2s×6
-
Header bidding
A duplicate Prebid auction for the same ad units
On a US sports site, Prebid opened a second auction for the same two ad units 37 ms after the first, before the first had finished. Eight bidders were asked for both units in each auction, so all 16 bid requests went out twice.
-
No consent string after the visitor accepted
On a large music site, a bid request to The Trade Desk’s Prebid Server went out after the visitor accepted consent, with no GDPR flag and no consent string.
POST openads.adsrvr.org/
openrtb2/ auction { "imp": [ … ], "ext": { "prebid": … }, "regs" missing "user" missing } -
Cookie syncs sent gdpr=0 for a visitor in the EEA
On a Polish web portal, three cookie syncs to Google and Criteo carried gdpr=0, while the page’s own CMP reported that GDPR applies.
doubleclick.net syncgdpr=0
criteo.com syncgdpr=0
CMPgdprApplies: true
The checks
Each check looks for one specific failure. Checks are grouped by where in the ad flow the failure happens.
Consent
- Ad requests sent before the visitor makes a consent choice
- ID cookies set and cookie syncs sent before the visitor makes a consent choice
- Bid requests that drop the consent string
- Consent macros such as
${GDPR_CONSENT_XXXX}sent unexpanded - User IDs sent to vendors without consent
gdpr=0sent for visitors in the EEA
Header bidding
- Winning bids that never reach the ad server
- Ad requests sent before the auction ends
- Bids that arrive after the timeout
- Bidders that are set up but can’t bid
- The same bidder called both client side and through Prebid Server
- Overlapping auctions for the same ad units
- Bids above the top price granularity bucket
- Price floors that reject every bid
Delivery and refresh
- Ad requests that error out or never complete
- Slots left empty although Prebid had a bid
- Refreshes while the slot is out of view
- Refreshes that resend targeting keys from an earlier auction
- Refreshes of slots already removed from the page
- Ads rendered into slots with zero size
- Slots that never come into view
Supply chain
- Bid requests naming a seller account ads.txt doesn’t list
- Winning bids from a seller account ads.txt doesn’t list
Page experience
- Ads that cause layout shift when they render
- Ads over the browser’s heavy ad limit
- Ad code that blocks the main thread
- Ads that play sound, open popups or redirect
- GPT or Prebid loaded twice
Questions
What does AdLinter detect?
AdLinter looks for problems across consent, header bidding, ad serving and rendering. These include late bids, targeting mismatches, lost or excluded demand, consent propagation issues, incorrect refresh behavior, slots left empty despite a bid, delivery failures and supply chain problems.
Do I need to install anything?
No. AdLinter only needs a publicly accessible web address. No tag, SDK, account access or code change is required.
How can AdLinter find problems without access to GAM or our internal systems?
AdLinter observes what actually happens in the browser: network requests, consent signals, header bidding and ad server events, slot behavior, rendering and timing. It connects these signals to reconstruct the ad flow and identify where things went wrong.
How do I know the findings are real?
Every finding is based on evidence captured during the scan. AdLinter shows the relevant requests, events and timestamps so you can verify what happened yourself. If the available evidence cannot support a claim with sufficient confidence, it is not reported as a finding.
Does AdLinter use AI to decide what is wrong?
No. Deterministic rules and heuristics analyze the collected signals and identify problems across the ad flow. AI then checks each finding, and findings remain based on observable evidence from the scan.
What pages can AdLinter scan?
AdLinter is designed for publicly accessible publisher pages with ads that run in the browser, on desktop or mobile. It can interact with consent banners, scroll the page, observe dynamically loaded ads and wait for ad refreshes. Pages behind authentication, hard paywalls or strong bot protection may not be fully scannable.
What does AdLinter cost?
AdLinter is currently in private beta, so there is no public pricing yet. Request a scan and see what AdLinter finds on your site. If it’s useful, we can talk about continued access from there.
Request a scan
Enter a page URL and we’ll email you the report.
AdLinter is currently in private beta. Reports usually arrive within 24 hours. Please use your work email and a website operated by your organization.
Thanks, we’ve got your request
We’ll email the report to you.