ScreenshotNeo

BlogHow-to

How to Schedule Website Screenshots After Dismissing a Popup

Build a scheduled Playwright screenshot that handles a site’s popup deliberately, verifies it is gone, and saves the right page area.

By the ScreenshotNeo team4 October 20269 min read

To schedule a website screenshot after dismissing a popup, write a browser script that opens the page, waits for the specific popup control, chooses the intended action, confirms the popup is gone, and captures the viewport, an element, or the full page. Then configure a scheduler in your environment to run that script at the interval you need. The popup interaction is site-specific; there is no reliable universal selector or universally correct consent choice.

This guide uses Playwright with Node.js for the browser work. The scheduler is a separate part of the system: it starts the script, while Playwright handles the page and image. Choose a scheduler you already operate, and arrange for the generated files to be retained or uploaded to your own storage.

1. Set up a repeatable capture

Decide these details before writing the script:

  • Target: the page URL and the expected popup control.
  • Consent action: accept, reject optional cookies, or open preferences according to your purpose and the site’s choices.
  • Capture area: the visible viewport, one element, or the full scrollable page.
  • Environment: browser, viewport dimensions, and where the output file should go.
  • Schedule and retention: how often the script runs and how long screenshots should be kept.

For repeatable visual comparisons, keep the browser, operating system, viewport, browser settings, and headless mode consistent. Playwright notes that rendering can vary with the operating system, browser version, settings, hardware, power source, and headless mode. See the Playwright screenshot comparison documentation.

2. Install Playwright

Create a project and install Playwright. The following commands use npm and install the Chromium browser that the script launches:

mkdir scheduled-shots
cd scheduled-shots
npm init -y
npm install playwright
npx playwright install chromium

Run the install step in the environment that will execute the scheduled job as well as on your development machine. If your deployment environment needs additional operating-system dependencies, follow Playwright’s installation guidance for that environment.

3. Write the popup-aware capture script

Save this as capture.mjs. Replace the example URL and button name with values that match the page. The accessible role and name are often easier to maintain than a styling class, but inspect the actual page and use a locator that identifies the intended visible control.

import { chromium } from 'playwright';
import { mkdir } from 'node:fs/promises';

const targetUrl = process.env.TARGET_URL ?? 'https://example.com';
const outputDir = process.env.OUTPUT_DIR ?? 'screenshots';
const action = process.env.CONSENT_ACTION ?? 'reject';

await mkdir(outputDir, { recursive: true });
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
  viewport: { width: 1440, height: 1000 },
  // Set locale or timezone here if the page's content depends on them.
});
const page = await context.newPage();

try {
  await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 45_000 });

  // Use the site's real, visible control and the consent choice appropriate
  // for your capture. Change this accessible name to match the target page.
  const consentButtonName = action === 'accept'
    ? 'Accept all'
    : 'Reject optional cookies';
  const consentButton = page.getByRole('button', {
    name: consentButtonName,
    exact: true,
  });

  // Some visits may not show a popup. If it appears, wait briefly for the
  // expected control and activate it. Do not treat absence as proof that a
  // differently named popup was dismissed.
  if (await consentButton.isVisible({ timeout: 3_000 }).catch(() => false)) {
    await consentButton.click();
  }

  // Verify the known consent dialog is gone when it exists. Replace this
  // locator with a site-specific dialog/banner locator if available.
  const consentDialog = page.getByRole('dialog');
  if (await consentDialog.count()) {
    await consentDialog.waitFor({ state: 'hidden', timeout: 10_000 });
  }

  // Wait for a meaningful page condition, not just an arbitrary delay.
  // Replace this heading with a selector that makes sense for the target.
  await page.locator('body').waitFor({ state: 'visible' });

  const stamp = new Date().toISOString().replaceAll(':', '-');
  await page.screenshot({
    path: `${outputDir}/page-${stamp}.png`,
    fullPage: true,
    animations: 'disabled',
  });
} finally {
  await context.close();
  await browser.close();
}

The example treats the popup as optional, but its selector still needs to be correct for the site. If a banner can appear late, identify a stable page or consent condition and wait for that explicitly; a short timeout alone cannot distinguish “no banner” from “banner has not appeared yet.” For pages with a predictable banner, put the expected banner locator into the script and verify its hidden state after clicking.

Run it locally:

TARGET_URL='https://example.com' CONSENT_ACTION='reject' node capture.mjs

4. Choose how much of the page to capture

Playwright supports screenshots of the current viewport, a specific element, and the full page. Pick the smallest capture that answers your use case.

Mode Use it when Example
Viewport You want the visible fold at a fixed window size. await page.screenshot({ path: 'viewport.png' });
Element You are tracking one chart, card, or component. await page.locator('#pricing').screenshot({ path: 'pricing.png' });
Full page You need the full scrollable document. await page.screenshot({ path: 'full.png', fullPage: true });

For element capture, choose a stable selector and wait for the element to be visible before calling screenshot(). For full-page capture, be aware that very long pages can create large images and take longer to render and store. Playwright’s screenshot API also supports output path, type, scale, and screenshot styling options; consult the official screenshot documentation for the current API and CLI details.

5. Handle popup types correctly

In-page banners and modals

Cookie notices, newsletter prompts, and chat panels are usually DOM elements inside the page. Handle a predictable overlay in the normal flow: wait for its actual button, perform the intended action, then verify the overlay is hidden or removed. Do not assume that every site uses the same labels, element roles, or markup.

Playwright’s page.addLocatorHandler() can help with genuinely unpredictable overlays, but it is not a background watcher: it runs around actions or auto-waiting assertions. For a popup that predictably appears during navigation, an explicit dismissal step is easier to follow and debug. See Playwright’s Page API documentation.

JavaScript browser dialogs

alert, confirm, prompt, and beforeunload are browser dialogs, not DOM banners. Playwright automatically dismisses these if no dialog listener is installed. If you install a listener, you must accept or dismiss the dialog or the page can stall. For example, to explicitly accept a confirmation dialog:

page.on('dialog', async dialog => {
  await dialog.accept();
});

Use the action appropriate to the application. Do not install a listener that leaves dialogs unresolved, and do not confuse dismissing a JavaScript dialog with handling a consent banner.

6. Schedule the script

Configure your chosen scheduler to invoke the same command you used locally, with the target URL, consent action, and output location set for that environment. The scheduler should run where the browser dependencies are installed and where the output can be persisted.

  1. Choose the cadence and timezone for the schedule.
  2. Set required environment variables or provide configuration securely through the scheduler.
  3. Run the script once manually in the scheduled environment before enabling recurring runs.
  4. Persist the output to durable storage if the execution environment is temporary.
  5. Capture the process exit status and logs so failed runs are visible.
  6. Set retention or cleanup rules for old screenshots so the output directory does not grow indefinitely.

A recurring job can overlap if one capture takes longer than the interval. Prevent concurrent runs for the same target or use distinct output names and an explicit queue. The precise scheduler configuration varies by platform; use the platform’s official documentation for its syntax, timezone rules, retries, and storage behavior.

7. Troubleshooting

Symptom Likely cause Fix
Timeout waiting for the consent button The control label, role, or timing differs on this page, or the popup did not appear. Inspect the rendered page, use the site’s actual control, and make the optional-popup path explicit. Wait for a page-specific condition if the banner appears late.
Click succeeds but the popup remains The locator matched a different control, the site requires another preference step, or the overlay has not finished closing. Target the visible intended button, complete any follow-up choice, then wait for the known overlay to become hidden.
Screenshot still contains a popup The popup is a different overlay, appeared after the check, or is inside a frame. Identify the actual overlay and its frame if applicable; wait for and handle it before capture, then verify its disappearance.
Page is blank or incomplete Navigation completion did not mean the important content was ready, or the site uses client-side loading. Wait for a specific heading, content selector, or other meaningful readiness condition. Avoid relying only on a fixed sleep.
Scheduled run cannot launch Chromium The browser was not installed in that runtime or required system dependencies are missing. Install Playwright’s browser and environment dependencies in the scheduled runtime, and confirm the job uses the expected Node.js version and working directory.
Output disappears after a successful run The scheduler runs on temporary storage or a different working directory. Use an absolute output path and upload or copy the image to durable storage as part of the job.
Images differ between runs Rendering varies by browser, operating system, viewport, content timing, fonts, animation, or remote page changes. Keep the capture environment and viewport consistent, wait on stable content, disable animations where suitable, and account for genuinely changing page content.
Runs pile up or overwrite files The schedule overlaps, or output names are reused. Prevent overlapping runs when needed and include a timestamp or run identifier in each output name.

8. Performance, reliability, and cost

A self-managed Playwright job uses compute and storage in the environment that runs it. Full-page captures and pages with heavy client-side rendering can take longer and produce larger files than viewport captures. Keep the viewport and capture mode no larger than your use case needs, avoid unnecessary waits, and set navigation and action timeouts deliberately.

For reliability, treat each scheduled run as a job with an observable result: record success or failure, retain useful logs, and decide whether the scheduler should retry transient failures. Retries can produce multiple images, so use distinct filenames or an idempotent upload strategy. A screenshot records the state the page reached; it does not guarantee the website displayed correct or fresh content.

Costs depend on the browser runtime, execution frequency, and image retention or transfer in your environment. No scheduler or storage provider is required by Playwright itself. Estimate run volume before choosing infrastructure, especially for frequent captures or many URLs.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. It can capture an image or PDF with one GET request, and its options include scheduled workflows built around your own scheduler, full-page and element capture, and custom wait conditions. See the ScreenshotNeo API documentation.

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 are accepted like a visitor; 60+ known consent platforms, newsletter popups, and chat widgets are removed before the shot. Each step can be turned off.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing. Responses report page verdict and billing status in headers.
  • An MCP server gives AI agents, including Claude and Cursor, tools to take screenshots, get page information, and capture PDFs.
  • The Free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 shots; all features are on every plan.

Sign up for 1,000 free screenshots a month, with no card required.

FAQ

No. Choose the site’s available consent action based on the purpose of the capture. Rejecting optional cookies or opening preferences may be the appropriate choice.

Can one selector dismiss popups on every website?

No. Popup markup and control labels differ by site, so use a locator for the actual page and verify the result.

Does a screenshot scheduler control what the browser does?

No. The scheduler starts the job at a chosen time. The browser script performs navigation, popup handling, and capture.

Why does the same page look different in later screenshots?

The site may have changed, or the browser environment, viewport, timing, or rendering conditions may differ. Keep the environment consistent when comparing images.