Better Ads Monitor
CNC Media Group

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.

24
Sites
20
Standards
789
Weekly Tests
8
Triplets

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.

6
Desktop Standards
10
Mobile Standards
4
Video & Nav Standards
Chrome Ad Filtering — When Chrome detects repeated Better Ads violations, it blocks all ads on the site, including the publisher's own inventory. A single non-compliant placement can trigger total ad revenue loss.

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.

CriticalChrome will block all ads

#1 / #5
Pop-up Ads
Ads that pop up and block the main content, displayed within the content area of the page.
DesktopMobilepopup-ads
critical
#2 / #11
Auto-playing Video with Sound
Video ads that auto-play with sound without user interaction to initiate audio.
DesktopMobileautoplay-video
critical
#9
Ad Density
Ads occupying more than 30% (mobile) or 50% (desktop) of the vertical page height.
DesktopMobilead-density
critical
#7
Ad Density + Sticky Video
Pages with ad density exceeding 30% combined with a sticky video player. Stricter threshold.
Desktopad-density-sticky-video
critical
#18
Non-skippable Video Interstitials
Full-screen video interstitial ads that cannot be skipped by the user.
Mobile Appnonskippable-video-interstitials
critical
#20
Long Pre-roll Ads
Pre-roll video ads longer than 31s without a skip option, or skip button appearing after 6s.
Videopre-roll-ads
critical

HighLikely to trigger filtering

#3
Prestitial Ads with Countdown
Full-page ads with a countdown timer appearing before content loads.
Desktopprestitial-countdown
high
#6
Prestitial Ads
Full-page ads that appear before page content is displayed, blocking access.
Desktopprestitial-ads
high
#4 / #12
Large Sticky Ads
Ads that stick to the edge of a page and cover more than 30% of the screen.
DesktopMobilesticky-ads
high
#10
Flashing Animated Ads
Ads with rapidly flashing animations (more than 3 flashes/sec). Seizure hazard.
Mobileflashing-ads
high
#11
Postitial Ads with Countdown
Full-page ads with countdown appearing when navigating away from a page.
Mobilepostitial-countdown
high
#13
Full-screen Scrollover Ads
Ads that take over the full screen as the user scrolls, covering >30% of viewport.
Mobilescrollover-ads
high
#24
Navigation Interstitial Ads
Interstitial ads appearing during page-to-page navigation within the site.
Navigationinterstitial-ads
high
#16
Interruptive Interstitials
Interstitial ads that interrupt the user's experience on mobile web or app.
Mobile Appinterruptive-interstitials
high
#17
Interruptive Video Interstitials
Video interstitial ads that interrupt the user's content consumption.
Mobile Appinterruptive-video-interstitials
high
#19
Page-load Video Interstitials
Video interstitial ads that play during page load, before user sees content.
Mobile Apppageload-video-interstitials
high
#21
Mid-roll Ads
Ads inserted in the middle of video content that interrupt viewing.
Videomid-roll-ads
high

MediumMay contribute to filtering

#14
Sticky Pop-out Video Ads
Video ads that pop out and stick to the viewport when scrolled past their original position.
Mobilesticky-popout-video
medium
#15
Sticky Video + Large Inline Ad
Combination of a sticky video player with a large inline ad, creating excessive coverage.
Mobilesticky-video-inline-ad
medium
#22
Large Display Overlay Ads
Overlay ads covering more than 20% of a video player, obstructing viewing.
Videodisplay-overlay-ads
medium

Measurement Thresholds

Specific numeric thresholds that determine pass/fail for each measurement.

MeasurementDeviceWarningViolationUnit
Ad DensityDesktop45%50%% of vertical page height
Ad DensityMobile25%30%% of vertical page height
Ad Density + Sticky VideoDesktop30%% of vertical page height
Sticky Ad HeightAll30%% of viewport height
Flashing AnimationMobile>3flashes per second
Scrollover AdsMobile30%% of viewport
Pre-Roll SkipVideo>31sseconds without skip
Skip Button DelayVideo>6sseconds until skip
Display OverlayVideo20%% of video player area
Autoplay DetectionAll5smonitoring window
Warning thresholds are reported but do not constitute violations. They serve as early indicators that a page is approaching the boundary.

System Architecture

End-to-end flow from test execution through reporting and monitoring.

PLAYWRIGHT TEST RUNNER Desktop 1920 x 1080 6 standards Chrome Win10 Mobile 390 x 844 10 standards Safari iOS 18 Video Pre/Mid-roll 3 standards Overlay detect Navigation Page-to-page 1 standard Interstitials Consent Handler → Ad Detector → Density Calculator → Metrics consent-handler.ts • ad-detector.ts • density-calculator.ts REPORTERS summary • opensearch • slack • html OpenSearch Index + Screenshots Grafana 6 Dashboards Slack #ad-monitor Reports HTML + PDF + JSON GitLab CI • Daily 06:00 (sentinel) • Weekly Mon 04:00 (full) • Weekly Wed 04:00 (competitors)
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.

8
CNC Properties
16
Competitor Twins
8
Triplet Groups
VerticalCNC SiteCompetitor 1Competitor 2CMP Types
News / TabloidBlesk.czNovinky.cziDNES.czDidomi / Seznam / Didomi
SportsiSport.czSport.czsport.idnes.czCPEx / Seznam / Didomi
AutomotiveAuto.czauto.idnes.czAutoforum.czCPEx / Didomi / none
BusinessE15.czihned.czAktualne.czDidomi / Didomi / Didomi
OpinionReflex.czEcho24.czRespekt.czDidomi / Didomi / Cookiebot
WomenproZenyProzeny.czona.idnes.czDidomi / Seznam / Didomi
Video / TVBlesk TVCNN PrimaStream.czDidomi / Didomi / Seznam
BlogOpinio.czblog.idnes.czblog.aktualne.czDidomi / Didomi / Didomi
Dynamic URL enrichment — Test URLs are refreshed before each run via RSS feeds (CNC) and NavCrawler (competitors), so tests always run against current, real content pages.

Test Suites

Daily

Sentinel Suite

Risk-weighted subset at 06:00 daily. Focuses on 4 critical standards across all sites, with extended coverage for high-risk properties.

~183 tests
~8 min

Core: popup, autoplay, sticky, density
High-risk: + prestitial, scrollover, flashing, video

Weekly

Full Audit

Comprehensive audit of all 20 standards. Monday 04:00 (CNC), Wednesday 04:00 (competitors).

789 tests
~25 min

All 20 standards × all sites × 5 URLs
Outputs: compliance report, comparison, PDF brief

Risk Tier Assignment

SiteRiskURLsSpecialty TestsVideoNav
Blesk.czhigh3prestitial, scrollover, flashing, sticky-popoutdisplay-overlay, pre-rollYes
E15.czhigh3prestitial, scrollover, flashingYes
iSport.czhigh3prestitial, scrollover, flashingYes
proZenyhigh3prestitial, scrollover, flashingYes
Reflex, Auto, Opinio, Blesk TVlow2No

Test Methodology

Each test follows a standardized pipeline from page load through violation detection.

1
Navigate
Load page with device viewport
2
Consent
Handle cookie banner via CMP
3
Stabilize
Wait for ads, suppress overlays
4
Detect
Multi-strategy ad scan
5
Measure
Density, height, timing
6
Report
Metrics + screenshot + index

Detection Methods by Standard

StandardDetection MethodWhat's Measured
Pop-up AdsDOM scan for overlays with z-index > content, positioned fixed/absoluteOverlay presence, size, dismissibility
Autoplay VideoMonitor audio context and video elements for 5s after loadSound playback without user interaction
Sticky AdsScroll page, detect position:fixed/sticky elements that persistElement height as % of viewport (>30%)
Ad DensityFull-page scan with pixel-row vertical projection, overlap dedupTotal ad height / page height
PrestitialDetect full-page overlays before content rendersBlocking overlay presence, countdown
Flashing AdsFrame-rate analysis over 3-second windowFlash frequency (>3/sec violation)
Pre-rollDetect video ad before content, measure duration + skipLength (>31s without skip)
Nav InterstitialClick internal links, detect interstitial during navigationInterstitial presence between pages

Data Pipeline

Test results flow through multiple reporters into persistent storage and monitoring.

OpenSearch Document Schema

FieldTypeDescription
@timestampdateTest execution time (ISO 8601)
run_idkeywordUnique run identifier
sitekeywordSite short name (lowercase)
devicekeyworddesktop / mobile / video / navigation
standard_codekeywordTest slug (e.g. ad-density)
statuskeywordpassed / failed / skipped / errored
ad_density_maxfloatPeak ad density percentage
ad_countintegerNumber of detected ad elements
sticky_ad_max_pctfloatLargest sticky ad as % of viewport
suitekeyworddaily / full
priority_scoreinteger0–100 triage priority (failures only)
Index: 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

ScheduleCronSuiteSitesJobs
Daily Sentinel0 6 * * *dailyCNC (8 sites)4 parallel (desktop, mobile, video, nav)
Weekly Deep0 4 * * 1fullCNC (8 sites)4 parallel + report generation
Weekly Competitors0 4 * * 3fullCompetitors (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

Playwright
Browser automation
TypeScript
Type-safe codebase
OpenSearch
Result storage
Grafana
Dashboards
GitLab CI
Scheduled runs
Slack
Alert notifications
Sharp
Screenshot compression
PDFKit
Compliance briefs
Claude AI
Visual verification

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