// docs
Documentation
Complete reference for @codepenguin/adsense-simulator — a lightweight browser-only tool that mirrors the AdSense runtime for development and testing.
Overview
The simulator reproduces key AdSense runtime behaviors entirely in the browser with no external network requests. It detects .adsbygoogle slots, intercepts the adsbygoogle.push() queue, renders mock ads with real debug metadata, and handles SPA navigation and bfcache restoration automatically.
Installation
npm
CDN
data-remove-google-ads="true" attribute — never a query string parameter.Quick Start
Import in your development entry point:
Then use standard AdSense markup. The simulator handles the rest:
The simulator renders a mock ad showing: client, slot, size, and format.
Data Attributes
| Attribute | Required | Description |
|---|---|---|
| data-ad-client | Yes | AdSense publisher ID (e.g. ca-pub-demo) |
| data-ad-slot | Yes | Ad slot ID |
| data-ad-format | No | "auto" for responsive, omit for fixed |
| data-ad-layout | No | "in-article" or "in-feed" for layout ads |
| data-full-width-responsive | No | "true" to use fluid full-width sizing |
| data-remove-google-ads | No | "true" on the CDN <script> tag to block real AdSense |
Ad Sizes
All 12 standard IAB sizes supported:
| Size | Name |
|---|---|
| 970×250 | Billboard |
| 970×90 | Large Leaderboard |
| 728×90 | Leaderboard |
| 468×60 | Banner |
| 336×280 | Large Rectangle |
| 300×600 | Half Page |
| 300×250 | Medium Rectangle |
| 320×100 | Large Mobile Banner |
| 320×50 | Mobile Banner |
| 234×60 | Half Banner |
| 160×600 | Wide Skyscraper |
| 120×600 | Skyscraper |
Fixed slots: set explicit width and height in the inline style. The simulator uses those dimensions directly.
Responsive Ads
Set data-ad-format="auto" to let the simulator pick the best size based on container width:
| Container width | Chosen size |
|---|---|
| < 400px | 320×50 (Mobile Banner) |
| < 600px | 300×250 (Medium Rectangle) |
| < 900px | 728×90 (Leaderboard) |
| < 1100px | 970×90 (Large Leaderboard) |
| ≥ 1100px | 970×250 (Billboard) |
Ad Layouts
Layout ads use fluid dimensions relative to their container width:
| data-ad-layout | Height formula |
|---|---|
| in-article | containerWidth × 0.35 |
| in-feed | containerWidth × 0.30 |
Queue API
The simulator installs its own window.adsbygoogle array with a custom push() interceptor. Calling (adsbygoogle = window.adsbygoogle || []).push() drains the queue and triggers a slot scan.
Internal flow:
Dynamic Insertion
A MutationObserver watches document.documentElement (not document.body) so it survives full body replacements by SPA frameworks. Slots inserted via JavaScript are detected and rendered automatically without any extra .push() call.
The observer also watches attribute mutations — frameworks that insert the shell <ins> first and set data-ad-client / data-ad-slot during hydration are handled correctly.
SPA Navigation
The simulator patches history.pushState and history.replaceState and listens for the popstate event. On every route change it runs a full reinit cycle:
pushState / replaceState — reinit is immediate because the framework mounts content synchronously.
popstate (back/forward) — reinit is deferred with multiple rAF + setTimeout passes because the browser fires the event before the framework restores the DOM.
bfcache Support
The pageshow event with event.persisted === true is the only reliable signal for back-forward cache restoration (popstate may not fire). The simulator listens for it and runs the same deferred reinit path.
Script Blocking
Add data-remove-google-ads="true" to the CDN script tag to activate all 4 blocking layers:
| Layer | Mechanism | What it stops |
|---|---|---|
| 1 | document.createElement patch | Intercepts src assignment — browser never fetches |
| 3 | MutationObserver fallback | Catches innerHTML injection + pre-existing scripts |
| 4 | window.adsbygoogle property trap | Prevents real AdSense replacing the simulator queue |
Layer numbers match the source code comments — Layer 2 is intentionally absent (reserved for future use).
CSP Recommendation
The MutationObserver blocker is best-effort — it fires asynchronously, leaving a small window where the browser may have started fetching adsbygoogle.js. For guaranteed blocking at the network level, add a Content Security Policy to your dev server:
Click Simulation
Clicking any rendered mock ad opens a new tab with a debug page showing full ad metadata:
| Field | Value |
|---|---|
| client | data-ad-client value |
| slot | data-ad-slot value |
| size | Rendered width×height |
| format | fixed / auto / fluid |
| containerWidth | Parent element offsetWidth |
| page | window.location.pathname |
| timestamp | Date/time of click |
Console Output
When the simulator initialises you will see:
If real AdSense is blocked:
Slot validation errors (missing attributes):
Known Limitations
The slotScanner retries up to 5 times over 2 seconds for slots missing data-ad-client or data-ad-slot — after that the slot is marked as errored and skipped.
Not Replicated
The simulator does not replicate Google's ad network infrastructure. The following are intentionally excluded:
- Real ads or advertiser content
- Auction and bidding logic
- Advertiser targeting
- Revenue tracking
- Fraud detection
- AdSense account validation
These systems run exclusively on Google's servers and cannot be replicated client-side.