skills/page-prep/SKILL.md
Prepare any webpage for clean interaction by detecting and removing disruptive overlays (cookie banners, GDPR consent, modals, popups, newsletter signups, paywalls, login walls). Uses a cached database of 300+ known CMPs (Consent-O-Matic + EasyList) combined with heuristic DOM scanning. Produces portable JS recipes for any browser tool (Playwright, CDP, cmux-browser). ALWAYS use this skill before taking screenshots, scraping content, or automating interaction on any webpage that might have overlays blocking the view or preventing interaction. Triggers on: page prep, clean page, remove overlays, dismiss cookie banner, page blocked, overlay cleanup, consent banner, prepare page, unblock page, clear popups, cookie popup.
npx skillsauth add catalan-adobe/skills page-prepInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Detect and remove overlays (cookie banners, GDPR consent, modals, paywalls, login walls) before screenshots, scraping, or browser automation. Node 22+ required. No npm dependencies.
The mode parameter controls dismiss strategy and verification depth.
Default is thorough. Callers can request quick mode in natural language
("use page-prep in quick mode") or the agent infers from context.
| Mode | Dismiss | Verification | Use case |
|------|---------|--------------|----------|
| thorough (default) | Click-first, hide as fallback | DOM check + viewport screenshot | Persistent sessions, interactive work |
| quick | Hide-only (CSS injection) | DOM check only | Ephemeral sessions, repeated evaluations |
if [[ -n "${CLAUDE_SKILL_DIR:-}" ]]; then
PAGE_PREP_DIR="${CLAUDE_SKILL_DIR}/scripts"
else
PAGE_PREP_DIR="$(dirname "$(command -v overlay-db.js 2>/dev/null || \
find ~/.claude -path "*/page-prep/scripts/overlay-db.js" -type f 2>/dev/null | head -1)")"
fi
Store in PAGE_PREP_DIR and prefix all commands below with
node "$PAGE_PREP_DIR/overlay-db.js".
Resolve PAGE_PREP_DIR using the block above. Verify the path is non-empty
before continuing.
node "$PAGE_PREP_DIR/overlay-db.js" refresh
Downloads and merges Consent-O-Matic rules + EasyList cookie filters into a
local cache (~/.cache/page-prep/). Skips network fetch if cache is less than
7 days old. Run with --force to bypass the age check.
BUNDLE="$(node "$PAGE_PREP_DIR/overlay-db.js" bundle)"
Captures a self-contained JS string (no imports, no external deps) to stdout. The bundled script embeds the full CMP database and heuristic scanner.
Evaluate $BUNDLE in the active page using whichever browser tool is in use
(see Browser Tool Examples). The script runs synchronously and returns a
detection report.
The injection return value is a JSON detection report. Parse it to enumerate
detected overlays. Each overlay has a source field: "cmp-match" (database
match) or "heuristic" (DOM scan).
source: "cmp-match"): the report includes a complete dismiss
recipe with ordered steps. Use it directly.source: "heuristic", dismiss: null): compose a dismiss
sequence yourself — try Escape key, then close buttons, then element removal
(see Agent Fallback).Combine hide and dismiss recipes for all detected overlays into a single
manifest (see Recipe Manifest Format). Include the global scroll_fix if
scroll_locked is true.
Thorough mode (default) — click-first:
dismiss recipe (source: "cmp-match"): execute
the dismiss.steps entries sequentially using the browser tool's click/key
primitives. Clicking sets consent cookies that persist across all tabs in
the same browser session — the overlay will not reappear.dismiss: null (source: "heuristic"): run the
Agent Fallback sequence (see below).scroll_fix if scroll_locked is true.hide.js rule).Quick mode — hide-only:
hide.js rules in one browser_evaluate call.scroll_fix if scroll_locked is true.Use quick mode for ephemeral browser sessions where cookies are lost on close (e.g., repeated evaluations in a polish loop). The detection recipe can be saved and replayed cheaply without re-running the full pipeline.
Verification runs in two layers. The DOM check runs in both modes. The screenshot check runs only in thorough mode.
The detection script catches known CMPs and common heuristic patterns, but it will miss overlays that don't fit those signals — third-party login prompts (Google One Tap, Apple Sign In), custom-built modals, iframes, or elements injected after the initial scan. Accessibility tree snapshots also miss iframes and elements outside the main document tree.
Run this check to find remaining blockers:
JSON.stringify([...document.querySelectorAll('*')].filter(el => {
var s = getComputedStyle(el);
return s.position === 'fixed' && parseInt(s.zIndex, 10) > 1000
&& (el.offsetWidth > 100 || el.offsetHeight > 100);
}).map(el => {
var s = getComputedStyle(el);
return { tag: el.tagName, id: el.id, cls: (el.className || '').slice(0, 50),
z: s.zIndex, w: el.offsetWidth, h: el.offsetHeight };
}))
Evaluate this via the browser tool. It returns all visible position:fixed
elements with z-index > 1000 and non-trivial dimensions. Ignore
legitimate elements (navigation bars, toolbars) and remove the rest:
document.querySelector('<selector>')?.remove().In quick mode, stop here. In thorough mode, continue to Step 9b.
The DOM check misses iframes, Shadow DOM, absolute-positioned overlays,
and <dialog>::backdrop. A viewport screenshot catches what DOM queries
cannot.
position:fixed and are always visible in the viewport
regardless of scroll position.This two-layer verification is the agent's value over the heuristic script alone — the script and DOM check handle the 80% of known patterns fast, the screenshot catches the remaining edge cases that require visual judgment.
For multi-step sessions where new overlays may appear (SPAs, lazy-loaded banners), inject the watch mode snippet after cleanup (see Watch Mode).
// Inject and capture report
const report = await browser_evaluate({
expression: BUNDLE // the string captured from `bundle`
});
node "$CDP_JS" eval "$(node "$PAGE_PREP_DIR/overlay-db.js" bundle)"
cmux browser --surface <ref> eval "$(node "$PAGE_PREP_DIR/overlay-db.js" bundle)"
{
"overlays": [
{
"id": "overlay-0",
"type": "cookie-consent",
"source": "cmp-match", // "cmp-match" | "heuristic"
"cmp": "cookiebot", // CMP name (only for cmp-match)
"selector": "#CybotCookiebotDialog",
"confidence": 1.0,
"hide": ["#CybotCookiebotDialog { display:none!important }"],
"dismiss": [{ "action": "click", "selector": "#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll" }]
},
{
"id": "overlay-1",
"type": "unknown-modal",
"source": "heuristic",
"selector": "div.gdpr-wall",
"confidence": 0.45,
"signals": ["high-z-index", "keyword-match", "scroll-lock-boost"],
"hide": ["div.gdpr-wall { display:none!important }"],
"dismiss": null // agent composes dismiss (see Agent Fallback)
}
],
"scroll_locked": true,
"scroll_fix": "html,body { overflow:auto!important; height:auto!important }"
}
{
"overlays": [
{
"id": "cookiebot",
"hide": {
"css": ["#CybotCookiebotDialog { display: none !important; }"],
"js": "document.querySelector('#CybotCookiebotDialog')?.remove()"
},
"dismiss": {
"steps": [
{ "action": "click", "selector": "#CybotCookiebotDialogBodyButtonAccept" }
],
"js": "/* composed from steps */"
}
}
],
"scroll_fix": "document.body.style.overflow=''"
}
When dismiss is null, attempt in order:
[aria-label*="close" i], [aria-label*="dismiss" i], .close,
button:has(svg), button[class*="close"].document.querySelector('<selector>')?.remove().Consult known patterns for CMP-specific dismiss patterns when the above three steps fail.
Inject after cleanup for pages that load overlays dynamically.
window.__pagePrep = (() => {
let timer = null;
let pending = [];
const MODE = 'hide'; // 'hide' | 'dismiss'
function scan() {
// Re-run heuristic scanner on current DOM
const found = window.__pagePrepScan?.() ?? [];
if (found.length === 0) return;
if (MODE === 'hide') {
found.forEach(o => {
const el = document.querySelector(o.selector);
if (el) el.style.display = 'none';
});
} else {
// 'dismiss' mode — queue for agent
found.forEach(o => {
if (!pending.find(p => p.id === o.id)) pending.push(o);
});
}
}
const observer = new MutationObserver(() => {
clearTimeout(timer);
timer = setTimeout(scan, 500);
});
observer.observe(document.body, { childList: true, subtree: true });
return {
watch: () => observer.observe(document.body, { childList: true, subtree: true }),
stop: () => { observer.disconnect(); clearTimeout(timer); },
pending: () => [...pending],
};
})();
window.__pagePrep.pending()
for the agent to process interactively.window.__pagePrep.stop() when the session is done.refresh --force if detection misses a known CMP — the database may be stale.node "$PAGE_PREP_DIR/overlay-db.js" status to check cache age and entry count.node "$PAGE_PREP_DIR/overlay-db.js" lookup <cmp-name> to check if a CMP is in
the database before injecting.quick mode for ephemeral sessions or repeated evaluations where speed matters.thorough mode (default) when cookies should persist or visual accuracy matters.tools
Reduce a webpage to a structural skeleton with semantic tokens. Two-phase pipeline: Phase 1 injects a browser script that tokenizes content ({TEXT}, {HEADING:n}, {IMAGE:WxH}, {CTA:label}, {LINK:label}, {INPUT:type}, {VIDEO}, {ICON}). Phase 2 applies LLM structural reasoning to collapse repeated patterns ({REPEAT:N}), remove decorative wrappers, strip utility classes, and produce skeleton.html + manifest.json. Use when migrating pages to EDS, analyzing page structure, extracting page blueprints, or preparing input for GenAI block generation. Triggers on: reduce page, page skeleton, page blueprint, extract structure, tokenize page, page reduction, structural skeleton, reduce URL.
tools
Capture a spatial hierarchy of rendered DOM elements from any webpage. Injects a pre-built script via playwright-cli that walks the DOM, detects layout grids, extracts backgrounds, prunes invisible nodes, promotes elements rendered outside their DOM parent (overlays, fixed navs, modals), and tags overlay nodes with occlusion metadata. Returns three outputs: LLM-friendly indented text, structured JSON tree, and a nodeMap mapping positional IDs to CSS selectors with background and overlay data. Use before page decomposition, overlay detection, brand extraction, or any workflow that needs structured page analysis. Triggers on: visual tree, capture tree, page structure, page hierarchy, DOM tree, capture visual, page analysis, extract tree.
tools
Summarize any video by analyzing both audio and visuals. Downloads via yt-dlp, extracts transcript (YouTube captions or Whisper), pulls scene-detected keyframes, and produces a multimodal summary with clickable timestamped YouTube links. Use this skill whenever the user wants to summarize a YouTube video, digest a talk or tutorial, get notes from a video, extract key points from a recording, or says things like "tl;dw", "summarize this video", "what's in this video", or pastes a YouTube URL and asks for a summary. Also triggers for non-YouTube URLs that yt-dlp supports.
development
Design and build web UIs with Adobe Spectrum 2 design system. Applies S2 layout principles, visual hierarchy, spacing, and component composition to produce accessible interfaces. Outputs vanilla CSS with Spectrum tokens (static pages) or Spectrum Web Components (interactive apps). Recommends tier based on complexity. Covers sp-theme setup, side-effect imports, overlay system, form patterns, --mod-* token customization, and 14 critical gotchas. Use for: spectrum 2 web, SWC, sp-button, sp-theme, build UI with spectrum, S2 layout, spectrum application, adobe design system, web component form, spectrum overlay.