How to Capture a Webpage Screenshot After Dismissing a Cookie Banner with an AI Agent
Use an AI agent to inspect a page, make an intentional cookie choice, verify the banner is gone, and capture the viewport, an element, or the full page.
To capture a webpage after dismissing its cookie banner with an AI agent, have the agent inspect the page, identify the site’s actual consent control, choose the intended consent action, confirm the overlay has disappeared, and then take the screenshot. Treat banner interaction and capture as separate steps: a click alone does not prove the page is ready or that the correct control was used.
This guide uses Playwright. The same sequence applies whether an agent drives a local browser or connects to a hosted browser: inspect current state, act on an observed control, verify the result, and capture the required scope. Cookie controls vary by site, so there is no reliable universal selector. [Browserless cookie-consent example]
1. Set up a browser the agent can control
For a local Node.js project, install Playwright and its Chromium browser:
npm install playwright
npx playwright install chromium
Save the script below as capture-after-consent.mjs. It opens a page, prints an accessibility snapshot for inspection, and provides a small set of agent actions through environment variables. The agent must choose the consent action and the observed button name; the script does not guess or automatically accept cookies.
2. Inspect, choose, verify, and capture
import { chromium } from 'playwright';
const targetUrl = process.env.TARGET_URL;
const action = process.env.CONSENT_ACTION; // accept, reject, or preferences
const controlName = process.env.CONSENT_CONTROL; // observed accessible name
const captureMode = process.env.CAPTURE_MODE ?? 'full'; // full, viewport, element
const elementSelector = process.env.ELEMENT_SELECTOR;
if (!targetUrl) throw new Error('Set TARGET_URL to the page URL.');
if (!['accept', 'reject', 'preferences', undefined].includes(action)) {
throw new Error('CONSENT_ACTION must be accept, reject, or preferences.');
}
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
try {
await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 45_000 });
// Let the page render its consent UI, then inspect before interacting.
await page.waitForTimeout(500);
console.log('URL:', page.url());
console.log('Snapshot:\n', await page.locator('body').ariaSnapshot());
if (action) {
if (!controlName) throw new Error('Set CONSENT_CONTROL to the observed button name.');
const control = page.getByRole('button', { name: controlName, exact: true });
await control.waitFor({ state: 'visible', timeout: 10_000 });
await control.click();
// Verify the chosen control is no longer visible. If a preference dialog
// remains open, inspect again and make the next intentional choice.
await control.waitFor({ state: 'hidden', timeout: 10_000 });
}
// For a known banner, replace this check with its observed locator. Do not
// infer success merely because the button click returned.
const bannerText = process.env.BANNER_TEXT;
if (bannerText) {
await page.getByText(bannerText, { exact: false }).waitFor({ state: 'hidden', timeout: 10_000 });
}
if (captureMode === 'element') {
if (!elementSelector) throw new Error('Set ELEMENT_SELECTOR for element capture.');
await page.locator(elementSelector).screenshot({ path: 'capture.png' });
} else if (captureMode === 'viewport') {
await page.screenshot({ path: 'capture.png' });
} else if (captureMode === 'full') {
await page.screenshot({ path: 'capture.png', fullPage: true });
} else {
throw new Error('CAPTURE_MODE must be full, viewport, or element.');
}
console.log('Saved capture.png');
} finally {
await browser.close();
}
Run an inspection pass first. It prints the current page URL and a semantic snapshot, which an agent can use to identify the visible choices:
TARGET_URL='https://example.com' node capture-after-consent.mjs
Then run again with an explicit action and the exact accessible name observed in the snapshot. For example, if the page exposes a button named “Reject optional cookies” and that is the appropriate choice for your task:
TARGET_URL='https://example.com' \
CONSENT_ACTION=reject \
CONSENT_CONTROL='Reject optional cookies' \
CAPTURE_MODE=full \
node capture-after-consent.mjs
Set BANNER_TEXT to distinctive text that disappears with the banner when the agent has identified it. A generic body-text check can be ambiguous on some sites; for reliable verification, use the specific banner container locator found during inspection and wait for that locator to become hidden.
3. Make the consent choice intentional
“Dismiss” describes the visual result, not the consent decision. When a site offers separate controls, choose the one that matches the task: accept, reject, or open preferences and configure them. Do not silently substitute acceptance just to make a screenshot possible. A preference dialog can require more than one interaction; take a fresh snapshot after each state change and verify the final overlay is gone.
Prefer locators based on the page state the agent actually observed, such as an accessible button name. Avoid baking in a selector copied from another site. Browserless’s example specifically notes that cookie banners rarely share a single standard attribute, so its example selectors require adaptation to each target. [Browserless example]
4. Choose what to capture
| Mode | Use it when | Playwright option |
|---|---|---|
| Viewport | You need what is visible at the current scroll position. | page.screenshot({ path: 'capture.png' }) |
| Full page | You need the page’s full scrollable content. | page.screenshot({ path: 'capture.png', fullPage: true }) |
| Element | You need a specific card, article, chart, or other region. | page.locator(selector).screenshot({ path: 'capture.png' }) |
Playwright MCP describes viewport, element, and full-page capture, and distinguishes snapshots used to interact with page structure from screenshots used for visual inspection. [Playwright MCP screenshots] Full-page capture can produce a tall image and may expose lazy-loading behavior; if content appears missing, scroll through the page before capturing and wait for required images or content to load.
5. Handle iframes, changing pages, and retries
Banner inside an iframe
Some consent interfaces are embedded in a frame. A page-level role locator will not cross into a frame. Inspect the frames, then locate the observed control inside the relevant frame:
for (const frame of page.frames()) {
console.log('Frame:', frame.url());
console.log(await frame.locator('body').ariaSnapshot().catch(() => '(no accessible body)'));
}
const consentFrame = page.frameLocator('iframe[title="Privacy choices"]');
await consentFrame.getByRole('button', { name: 'Reject optional cookies', exact: true }).click();
Use a frame selector grounded in the actual page, such as an observed title or source URL. If the frame is recreated after navigation or a preference choice, inspect again and create a fresh frame locator. Playwright supports frame-aware interaction through its page and frame APIs. [Playwright Page API]
Click failed or the page changed
- Take a fresh snapshot and check the current URL and visible controls.
- Confirm the target is a visible button or link and that its accessible name still matches.
- Check whether the banner moved into a frame or opened a second preference panel.
- Reacquire the locator from the current state and try once more; do not reuse a stale element handle.
Playwright recommends explicitly waiting for and dismissing a predictable overlay in the normal flow instead of relying on a locator handler. [Playwright Page API]
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Button locator times out | The accessible name differs, the banner has not rendered, or the control is inside a frame. | Inspect a new snapshot, wait for the observed control, and check frames before choosing a locator. |
| Click succeeds but the overlay remains | The control opened preferences, changed only one layer, or the page requires another choice. | Snapshot the new state, take the next intentional action, and wait for the banner container to become hidden. |
| Banner text check never resolves | The supplied text still appears elsewhere on the page or does not uniquely identify the overlay. | Use the observed consent container locator rather than matching broad page text. |
| Screenshot still contains the banner | Capture happened before the interface finished its transition, or a second overlay appeared. | Wait for the specific overlay to be hidden, inspect again, and only then capture. |
| Element screenshot fails | The selector matches nothing, matches multiple nodes, or the target is not visible. | Use a selector from the current page, check count and visibility, then capture the intended element. |
| Full-page image omits content | Content or images load only after scrolling, or the page updates asynchronously. | Scroll through the relevant sections, wait for expected content, and capture after it settles. |
| Navigation times out | The site keeps network connections open or loads slowly. | Use domcontentloaded or another appropriate readiness condition, then wait explicitly for the content needed in the shot. |
7. Reliability, performance, and cost choices
A local Playwright browser gives the automation direct control over the browser and page state, while a hosted browser connection can be useful when browser provisioning and running captures at scale need to be managed as a service. Browserless documents a hosted cookie-consent workflow, but the available research does not establish a price, latency, reliability, or service-level comparison; check current provider terms for your workload. [Browserless cookie-consent example]
For more reliable captures, use explicit waits for the particular control and overlay instead of long fixed delays. Keep the browser open until the screenshot is written, set a navigation timeout suitable for the target, and capture only after the intended page state is verified. For repeated jobs, reuse a browser process where appropriate, isolate page contexts when cookies or state must not leak between jobs, and record the URL, chosen action, capture scope, and failure stage. No general success rate or performance benchmark is established by the cited sources.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. It accepts one GET request with a URL and returns a PNG, JPEG, WebP, or PDF. For a direct screenshot call, see the ScreenshotNeo API docs.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
- Cookie banners, newsletter popups, and chat widgets are removed before the shot.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed; response headers report the page verdict and billing status.
- An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
- 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 screenshots.
Sign up free for 1,000 screenshots a month, with no card required.
FAQ
Does dismissing a cookie banner always mean accepting cookies?
No. Choose the site’s accept, reject, or preference action that matches the task. Removing the overlay alone does not establish which consent choice was made.
Should an agent use a screenshot to find the button?
Use a semantic snapshot to identify and interact with controls; use a screenshot when the agent needs visual inspection. This separation is described in the Playwright MCP screenshot guidance.
Is there a selector that works for every consent banner?
No universal selector is established by the cited documentation. Inspect each page and ground the locator in its actual controls.
Can the same workflow capture a PDF?
Playwright has PDF support in its page API for supported browser configurations; ScreenshotNeo’s API also returns PDFs. Choose the output format and capture scope before automating the final step.


