Better Ads Compliance Monitor
Automated Playwright-based testing of Czech media sites against the Coalition for Better Ads standards, with competitive benchmarking across 8 site triplets.
Compliance Reports
Test results with pass/fail breakdown and competitive analysis.
Evidence Review
SVG reconstructions, rule analysis, and compliance reference designs.
Ad Audit Browser
Per-viewport screenshots with density measurements for every CNC site.
What We Monitor
The Coalition for Better Ads (CBA) defines standards for online advertising that fall below a threshold of consumer acceptability. Google Chrome enforces these by filtering all ads on non-compliant sites. This system automatically tests CNC properties against every applicable standard.
Why It Matters
Revenue Protection
Chrome ad filtering removes all ads from non-compliant sites. For CNC properties dependent on programmatic revenue, a single violation can cascade into domain-wide ad loss.
Competitive Intelligence
Each CNC site is benchmarked against two competitor "twins" in the same vertical. This provides market context — are violations industry-wide or specific to us?
Early Warning
Daily sentinel runs detect violations within 24 hours. Slack alerts escalate critical findings to ad operations before Chrome's own crawler flags the issue.
Compliance Evidence
Every run produces timestamped evidence: screenshots, metrics, violation details. This trail supports compliance reviews and resolves disputes with ad networks.
Better Ads Standards Reference
All 20 standards tested by the system. Severity indicates the likelihood of Chrome triggering its ad blocker.
Critical — Chrome will block all ads
High — Likely to trigger filtering
Medium — May contribute to filtering
Measurement Thresholds
Specific numeric thresholds that determine pass/fail for each measurement.
| Measurement | Device | Warning | Violation | Unit |
|---|---|---|---|---|
| Ad Density | Desktop | 45% | 50% | % of vertical page height |
| Ad Density | Mobile | 25% | 30% | % of vertical page height |
| Ad Density + Sticky Video | Desktop | — | 30% | % of vertical page height |
| Sticky Ad Height | All | — | 30% | % of viewport height |
| Flashing Animation | Mobile | — | >3 | flashes per second |
| Scrollover Ads | Mobile | — | 30% | % of viewport |
| Pre-Roll Skip | Video | — | >31s | seconds without skip |
| Skip Button Delay | Video | — | >6s | seconds until skip |
| Display Overlay | Video | — | 20% | % of video player area |
| Autoplay Detection | All | — | 5s | monitoring window |
System Architecture
End-to-end flow from test execution through reporting and monitoring.
Consent Handler
Handles cookie consent popups across 6 CMP types:
Priority chain: Didomi → CPEx → Seznam TCF → Cookiebot → OneTrust → TCF v2 fallback → button text → iframe search
Ad Detector
Multi-strategy detection: selector matching, IAB size heuristics, text label detection ("Reklama", "Advertisement"), and CNC-specific wrapper classes (.cnc-ads__within). Each element carries a confidence rating: high, medium, or low.
Density Calculator
Pixel-row vertical projection with overlap deduplication. Projects all ad bounding rectangles onto a 1D vertical axis, merges overlapping ranges, and computes total ad height / content height = density %.
Screenshot Infrastructure
Deduplicated: one per site+device+URL (~50–150 per run). PNG→JPEG (quality 70) via Sharp. Indexed in OpenSearch with metadata. Batched bulk push: 20 per _bulk request.
Site Coverage
24 sites in 8 competitive triplets. Each triplet contains one CNC property and two competitor "twins" from the same content vertical.
| Vertical | CNC Site | Competitor 1 | Competitor 2 | CMP Types |
|---|---|---|---|---|
| News / Tabloid | Blesk.cz | Novinky.cz | iDNES.cz | Didomi / Seznam / Didomi |
| Sports | iSport.cz | Sport.cz | sport.idnes.cz | CPEx / Seznam / Didomi |
| Automotive | Auto.cz | auto.idnes.cz | Autoforum.cz | CPEx / Didomi / none |
| Business | E15.cz | ihned.cz | Aktualne.cz | Didomi / Didomi / Didomi |
| Opinion | Reflex.cz | Echo24.cz | Respekt.cz | Didomi / Didomi / Cookiebot |
| Women | proZeny | Prozeny.cz | ona.idnes.cz | Didomi / Seznam / Didomi |
| Video / TV | Blesk TV | CNN Prima | Stream.cz | Didomi / Didomi / Seznam |
| Blog | Opinio.cz | blog.idnes.cz | blog.aktualne.cz | Didomi / Didomi / Didomi |
Test Suites
Sentinel Suite
Risk-weighted subset at 06:00 daily. Focuses on 4 critical standards across all sites, with extended coverage for high-risk properties.
Core: popup, autoplay, sticky, density
High-risk: + prestitial, scrollover, flashing, video
Full Audit
Comprehensive audit of all 20 standards. Monday 04:00 (CNC), Wednesday 04:00 (competitors).
All 20 standards × all sites × 5 URLs
Outputs: compliance report, comparison, PDF brief
Risk Tier Assignment
| Site | Risk | URLs | Specialty Tests | Video | Nav |
|---|---|---|---|---|---|
| Blesk.cz | high | 3 | prestitial, scrollover, flashing, sticky-popout | display-overlay, pre-roll | Yes |
| E15.cz | high | 3 | prestitial, scrollover, flashing | — | Yes |
| iSport.cz | high | 3 | prestitial, scrollover, flashing | — | Yes |
| proZeny | high | 3 | prestitial, scrollover, flashing | — | Yes |
| Reflex, Auto, Opinio, Blesk TV | low | 2 | — | — | No |
Test Methodology
Each test follows a standardized pipeline from page load through violation detection.
Detection Methods by Standard
| Standard | Detection Method | What's Measured |
|---|---|---|
| Pop-up Ads | DOM scan for overlays with z-index > content, positioned fixed/absolute | Overlay presence, size, dismissibility |
| Autoplay Video | Monitor audio context and video elements for 5s after load | Sound playback without user interaction |
| Sticky Ads | Scroll page, detect position:fixed/sticky elements that persist | Element height as % of viewport (>30%) |
| Ad Density | Full-page scan with pixel-row vertical projection, overlap dedup | Total ad height / page height |
| Prestitial | Detect full-page overlays before content renders | Blocking overlay presence, countdown |
| Flashing Ads | Frame-rate analysis over 3-second window | Flash frequency (>3/sec violation) |
| Pre-roll | Detect video ad before content, measure duration + skip | Length (>31s without skip) |
| Nav Interstitial | Click internal links, detect interstitial during navigation | Interstitial presence between pages |
Data Pipeline
Test results flow through multiple reporters into persistent storage and monitoring.
OpenSearch Document Schema
| Field | Type | Description |
|---|---|---|
@timestamp | date | Test execution time (ISO 8601) |
run_id | keyword | Unique run identifier |
site | keyword | Site short name (lowercase) |
device | keyword | desktop / mobile / video / navigation |
standard_code | keyword | Test slug (e.g. ad-density) |
status | keyword | passed / failed / skipped / errored |
ad_density_max | float | Peak ad density percentage |
ad_count | integer | Number of detected ad elements |
sticky_ad_max_pct | float | Largest sticky ad as % of viewport |
suite | keyword | daily / full |
priority_score | integer | 0–100 triage priority (failures only) |
better-ads-compliance (single index). Datasource: UID opensearch-betterads (ID 47). Screenshots stored as Base64 JPEG with doc_type: 'screenshot'.Grafana Dashboards
The v6 dashboard suite provides 4 views for different investigation workflows.
Overview
ad6-overview
"Are we safe right now?" Leadership & QA view with compliance status, trend sparklines, and risk indicators.
Queue
ad6-queue
"What should I investigate first?" Priority-ranked failure queue sorted by severity, recurrence, and site importance.
Case File
ad6-case
"What exactly is this failure?" Deep-dive with screenshot evidence, metrics history, and selector details.
Compare
ad6-compare
"Are we better or worse?" Cross-site and CNC vs. competitor comparisons within triplet groups.
CI/CD Pipeline
| Schedule | Cron | Suite | Sites | Jobs |
|---|---|---|---|---|
| Daily Sentinel | 0 6 * * * | daily | CNC (8 sites) | 4 parallel (desktop, mobile, video, nav) |
| Weekly Deep | 0 4 * * 1 | full | CNC (8 sites) | 4 parallel + report generation |
| Weekly Competitors | 0 4 * * 3 | full | Competitors (16 sites) | 4 parallel + comparison report |
Runner: gitlab-ssh.cnci.tech
Registry: client-monitoring/ad-monitor
Artifacts: results/ directory (7-day retention)
Notifications: Slack #ad-monitor channel
Technology Stack
Project Structure
pw-ad-report/
├── src/
│ ├── config/ sites.ts, devices.ts, standards.ts, thresholds.ts
│ ├── fixtures/ consent-handler.ts (Playwright fixture)
│ ├── reporters/ summary, opensearch, slack, shared
│ ├── utils/ ad-detector, density-calculator, dynamic-urls
│ ├── cli/ verify, audit, PDF brief, weekly report
│ └── types/ TypeScript interfaces
├── tests/
│ ├── desktop/ 7 desktop Better Ads specs
│ ├── mobile/ 7 mobile Better Ads specs
│ ├── video/ pre-roll, mid-roll, display overlay
│ ├── navigation/ interstitial ads
│ └── unit/ density calculator, ad detector
├── grafana/suite/ dashboard builders → JSON → deploy
├── verification/ independent verification (5 methods)
├── results/ JSON, HTML, CSV, screenshots
└── portal/ this portal + report generator