How to Capture Product Page Screenshots After Accepting a Newsletter Popup
Dismiss a newsletter popup with its real on-page control, verify it is gone, then capture the product page with Playwright.
To capture a product page after a newsletter popup appears, open the page, use the popup’s actual close or decline control, confirm the overlay is hidden, and then save the screenshot. With Playwright, use a locator that matches the target page’s real markup and accessible name; there is no universal popup selector or timing.
1. Identify the popup and the screenshot you need
First decide whether the popup is an in-page newsletter modal or a browser JavaScript dialog. A newsletter modal is part of the webpage and usually has a close, decline, or “No thanks” control. A JavaScript alert, confirm, or prompt is a separate browser feature and needs its own dialog handler; it is not dismissed by locating an in-page button.
Inspect the target page to find the actual control. Prefer a role and accessible name, such as a button named “No thanks,” when the page exposes one. Otherwise use a stable selector from the page markup. The label and dialog locator in the example below are illustrative, not universal. Use a dismissal control when you want the page without subscribing; do not submit an email address simply to close the overlay.
Choose the capture scope before writing the final step:
| Scope | Use it for | Tradeoff |
|---|---|---|
| Viewport | A conventional view of what is currently on screen | Below-the-fold content is excluded |
| Full page | The whole scrollable product page in one image | Long pages can create very tall images |
| Element | A product image, details panel, or other specific section | Surrounding page context is excluded |
2. Install Playwright
This runnable Node.js example uses Playwright’s Chromium browser. Create a small project and install the package and browser:
mkdir product-capture
cd product-capture
npm init -y
npm install playwright
npx playwright install chromium
Save the following as capture.js. Set PRODUCT_URL to the product page and adapt the popup locator and dialog locator to that page. Run it with PRODUCT_URL="https://example.com/product" node capture.js.
const { chromium } = require('playwright');
async function main() {
const productUrl = process.env.PRODUCT_URL;
if (!productUrl) throw new Error('Set PRODUCT_URL to the product page URL');
const browser = await chromium.launch({ headless: true });
try {
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
await page.goto(productUrl, { waitUntil: 'domcontentloaded', timeout: 60000 });
// Adapt these example locators to the real newsletter popup.
const dismiss = page.getByRole('button', { name: 'No thanks' });
await dismiss.waitFor({ state: 'visible', timeout: 10000 });
await dismiss.click();
// If the site exposes an accessible newsletter dialog, verify it is hidden.
// Adapt the name or use another stable locator if the markup differs.
await page.getByRole('dialog', { name: /newsletter/i })
.waitFor({ state: 'hidden', timeout: 10000 });
// Viewport screenshot. Use fullPage: true for the entire scrollable page.
await page.screenshot({ path: 'product-page.png' });
} finally {
await browser.close();
}
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
The Playwright Page API includes an example of dismissing a newsletter overlay using a “No thanks” button. For a predictable overlay, its guidance is to wait for and dismiss it as part of the normal flow. See the Playwright Page API documentation.
3. Confirm the page state, then capture
The example waits for the dismissal control to appear, clicks it, and waits for the dialog to become hidden. If the page has a close icon instead, locate that control. If it does not expose a dialog role, verify the specific popup container is hidden, or check that the overlay no longer intercepts input before capturing.
Change the screenshot call to match your chosen scope:
// Current viewport only
await page.screenshot({ path: 'product-page.png' });
// Entire scrollable page
await page.screenshot({ path: 'product-page-full.png', fullPage: true });
// One element, using a locator that matches the actual page
await page.locator('[data-product-details]').screenshot({ path: 'product-details.png' });
The selector [data-product-details] is an example; replace it with a selector present on the target page. Playwright supports page screenshots, full-page screenshots, and locator screenshots. See the Playwright screenshots guide.
4. Handle popups that appear inconsistently
If the newsletter popup appears only sometimes, make the dismissal conditional while keeping the sequence easy to understand. For example, wait briefly for the actual control, dismiss it if visible, and then check that the overlay is gone:
const dismiss = page.getByRole('button', { name: 'No thanks' });
if (await dismiss.isVisible({ timeout: 3000 }).catch(() => false)) {
await dismiss.click();
}
const dialog = page.getByRole('dialog', { name: /newsletter/i });
if (await dialog.count()) {
await dialog.waitFor({ state: 'hidden', timeout: 10000 });
}
await page.screenshot({ path: 'product-page.png' });
Adapt this check if the page uses a different container or close action. A locator handler can help with unpredictable overlays, but Playwright cautions that handlers may run between actions and affect mouse or keyboard state. Prefer explicit, self-contained locator actions when practical. Do not let a handler click a control that subscribes the user or otherwise changes account state.
5. Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| “No thanks” times out | The popup has not appeared yet, uses different text, or has a different role | Inspect the live page and use its actual accessible name and role. Wait for the popup’s real trigger condition. |
| Click succeeds but the overlay remains | The click hit a different control, triggered an animation, or the overlay has another layer | Locate the real close/decline control and wait for the correct popup container to be hidden before capture. |
| Dialog locator never matches | The site does not expose the overlay as an accessible dialog or its name differs | Use a stable locator for the actual popup container and verify its hidden state. |
| Screenshot still contains the popup | The screenshot ran before dismissal completed, or a second popup appeared | Wait for the dismissed overlay to be hidden, then check for another visible overlay before saving. |
| Element screenshot reports no matching element | The sample selector is not present on the page | Inspect the product page and replace it with a selector for the desired element. |
| Navigation times out on a busy page | The page keeps loading background requests or third-party resources | Use a less strict navigation milestone such as domcontentloaded, then wait for the specific product content and popup state you need. |
| Browser JavaScript dialog blocks the flow | The page opened an alert, confirm, or prompt, not an in-page newsletter modal |
Handle the browser dialog with Playwright’s dialog event API; do not search for an HTML button to dismiss it. |
6. Reliability, performance, and output considerations
Use a fresh browser context when you need repeatable state. A previously saved cookie or local storage entry may suppress the popup, while a fresh context can cause it to appear again. If you reuse a context, expect the result to depend on the site’s stored state. The site may also show the newsletter prompt after a delay or after scrolling, so wait for the condition that actually triggers it rather than assuming it appears immediately after navigation.
Capture after the page and overlay have reached the intended state. For a product page with delayed images, wait for the relevant image or product content before taking the screenshot. Full-page output can be large and very tall; use viewport or element capture when the full document is not needed. There are no universal performance figures for this workflow: page scripts, network conditions, popup timing, and image loading determine how long each capture takes.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns an image or PDF, and its clean-shot flow accepts consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Only clean shots are billed: bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with the result identified in response headers. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. There are 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000. See the ScreenshotNeo site and 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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
Replace the example URL with the product page you want to capture and provide your API key. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed; an MCP server lets AI agents take screenshots; and 1,000 screenshots a month are free with no card. Get started with a free ScreenshotNeo account.
FAQ
Does closing the newsletter popup subscribe the visitor?
No. Use the page’s close or decline action. Do not submit an email address unless subscribing is the intended task.
Should I capture a full page or just the visible screen?
Use a viewport screenshot for a screen-like view, full-page capture to include content below the fold, or a locator screenshot to isolate one product section.
Can I use one selector on every product page?
No. Popup labels, roles, structure, and timing vary by site. Inspect the page and use its real control and markup.


