Fix a Screenshot That Shows a Cookie Banner Despite a Consent Cookie
A consent cookie can exist without applying to the page or matching what the app expects. Check its scope, value, browser context, and test setup.
A consent cookie can exist in a browser and the banner can still appear if the cookie does not apply to the screenshot URL, has the wrong value or attributes, is set in another browser context, is cleared between tests, or is not the state the site’s consent code checks. Check the cookie against the exact page URL, set it in the context that loads the page before navigation, and verify the banner after the app initializes.
A cookie name such as cookieConsent and a value such as accepted are only examples. The target application or consent platform defines the actual name, format, and storage location.
1. Check whether the cookie applies to the screenshot URL
Start with the URL that is actually opened for the screenshot, including its scheme, hostname, and path. A cookie visible in a browser’s general cookie list may be scoped to another host or path.
- Domain: A host-only cookie set by
www.example.comdoes not automatically apply toapp.example.com. A domain cookie may cover subdomains when configured appropriately. - Path: A cookie scoped to
/accountwill not be sent for/pricing. The usual broad path is/, if that matches the application’s intended scope. - Secure: A secure cookie is sent only over HTTPS. A local screenshot opened over HTTP may not receive it.
- SameSite: Cross-site and embedded flows can have different cookie behavior. Match the application’s requirements, especially where third-party or partitioned cookies are involved.
- Name and value: The app may require a particular value or structured payload, not a generic acceptance string.
- Expiry and context: Confirm the cookie has not expired and is present in the browser context used for the capture.
Playwright’s cookie API can inspect cookies affecting a specific URL. Its documentation also describes cookie attributes such as expiry, httpOnly, secure, sameSite, and partition keys. [Playwright BrowserContext cookies]
2. Verify the application’s consent contract
Before changing screenshot code, find out what the site actually reads. Inspect the consent manager configuration, initialization code, or a successful consent flow in the same browser. Determine:
- The exact cookie name and value or serialized payload.
- Whether consent is stored in a cookie, local storage, session storage, or a combination.
- Whether the cookie is first-party or partitioned for an embedded context.
- Whether the app waits for an asynchronous consent script before deciding to display the banner.
Browser automation documentation cannot tell you the consent format for an unidentified site. If the application checks local storage, setting a cookie alone will never suppress the banner. If it expects a region, category selection, or versioned payload, a simple accepted value may also be ignored.
3. Set and inspect a consent cookie with Playwright
Add the cookie to the same browser context that will navigate to and capture the page. Set it before navigation so the app can read it during initialization. Playwright accepts either a url or both domain and path when adding a cookie. [Playwright addCookies]
import { chromium } from 'playwright';
const targetUrl = 'https://www.example.com/pricing';
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
// Replace these example values with the target app's real consent cookie.
await context.addCookies([{
name: 'cookieConsent',
value: 'accepted',
url: 'https://www.example.com/',
secure: true,
sameSite: 'Lax',
}]);
// Inspect cookies that apply to the exact screenshot URL.
const applicableCookies = await context.cookies([targetUrl]);
console.log(applicableCookies);
const page = await context.newPage();
await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
// Wait for the app's consent initialization if it is asynchronous.
// Replace the selector with the actual banner selector for the site.
const banner = page.locator('#cookie-banner');
await banner.waitFor({ state: 'hidden', timeout: 10000 }).catch(async () => {
console.error('Banner is still visible. Inspect cookie scope, value, and app storage.');
console.error('Visible:', await banner.isVisible().catch(() => false));
});
await page.screenshot({ path: 'page.png', fullPage: true });
await browser.close();
The example cookie is intentionally generic and may not work on a real site. Replace its name, value, domain or URL, and attributes with the application’s consent contract. When using a domain and path instead of url, provide both.
For a reliable behavior test, assert that the banner becomes hidden after initialization. A screenshot alone cannot establish that the app recognized consent.
4. Keep consent state in Cypress tests
Cypress clears cookies before each test by default. If a known consent cookie is needed on every visit, set it in beforeEach and check the returned cookie. Cypress recommends restoring known cookie state this way; cy.session() can cache and restore server-created browser state. [Cypress cy.setCookie()] [Cypress cy.session()]
describe('pricing screenshot', () => {
beforeEach(() => {
// Example only: use the exact cookie contract for this application.
cy.setCookie('cookieConsent', 'accepted', {
path: '/',
secure: true,
sameSite: 'Lax',
}).then((cookie) => {
expect(cookie).to.have.property('name', 'cookieConsent');
});
});
it('loads the page with the consent banner dismissed', () => {
cy.visit('https://www.example.com/pricing');
cy.get('#cookie-banner').should('not.be.visible');
cy.screenshot('pricing');
});
});
The domain, path, secure, and sameSite options affect cookie scope and delivery. Use the actual target host and app requirements. If consent is created by a server flow, consider cy.session() to restore that known state. Disabling test isolation can preserve state, but Cypress warns that tests can then affect one another; explicit setup is easier to reason about. [Cypress test isolation]
5. Diagnose in a consistent order
- Log the exact capture URL. Check scheme, host, subdomain, path, and redirects. The final URL may differ from the one passed to the screenshot helper.
- Inspect applicable cookies for that URL. In Playwright, use
context.cookies([targetUrl]). In Cypress, inspect the cookie returned bycy.setCookie()or query it withcy.getCookie(). - Compare attributes and payload. Verify name, value, domain or URL, path, Secure, SameSite, and expiry against a successful consent flow.
- Confirm setup order. Add the cookie before navigation and use the same context for cookie setup, page load, and screenshot.
- Check other storage. Inspect local storage and session storage if the application uses them.
- Wait for consent initialization. If the banner appears briefly and then disappears, wait for the app’s stable state before capturing.
- Assert behavior before capturing. Verify banner visibility and, where possible, the consent state the application reads.
- Stabilize the visual environment. Keep browser version, operating system, viewport, device scale factor, and headless settings consistent when comparing snapshots. Playwright documents that screenshot rendering can vary across environments. [Playwright visual comparisons]
6. Fix common failure modes
| Symptom | Likely cause | Fix |
|---|---|---|
| Cookie appears in a cookie manager, but the page still shows the banner | It is scoped to a different host, path, or scheme | Inspect cookies for the exact final page URL; correct domain or URL and path. |
| Cookie is present before navigation but ignored | The name, value, encoding, or payload does not match the site’s contract | Observe a successful consent flow and reproduce the exact stored state. |
| Cookie works when browsing manually but fails in automation | The manual browser and automation use different contexts or profiles | Seed the cookie in the automation context that opens the page. |
| Consent works once, then the banner returns on the next Cypress test | Cypress test isolation clears cookies | Set the known cookie in each test’s beforeEach, or restore a session with cy.session(). |
| Banner flashes, then disappears | The consent manager initializes asynchronously | Wait for the app’s settled state or assert the banner is hidden before the screenshot. |
| Cookie exists but the banner persists | The app reads local storage, session storage, or another state source | Inspect application initialization and seed the actual storage mechanism. |
| Cookie is not sent on an HTTP development URL | The cookie has the Secure attribute | Use HTTPS for the test or configure an appropriate local test cookie. |
| Screenshot comparison differs despite identical consent setup | Browser or host rendering configuration differs | Pin the browser and keep viewport, device scale factor, operating system, and capture mode consistent. |
7. Masking a banner is not the same as fixing consent
Screenshot-only CSS that hides a banner can be useful when the sole goal is comparing page layout. It does not show that the application recognized consent or that a real visitor would see the banner suppressed. Keep behavior tests separate: set the real consent state and assert the banner’s expected visibility. If a visual baseline intentionally masks the banner, document that choice so the image is not mistaken for proof of consent behavior. Browserless’s example demonstrates dismissing a banner before capture and notes that selectors depend on the banner framework. [Browserless cookie and banner example]
8. Reliability and cost considerations
Cookie setup is deterministic only when the test controls the browser context and reproduces the application’s expected state. Reusing a context can preserve state, but it can also make tests order-dependent; isolated contexts with explicit setup are easier to reproduce. For visual regression, pin the browser environment and wait for consent initialization before capture.
For screenshots of public pages, a hosted capture API can avoid maintaining browser installation and capture code. Check whether the service supports the state and page behavior your task needs. Avoid assuming a generic consent cookie works across unrelated sites: consent payloads are app-specific.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. Make one GET request for a PNG, JPEG, WebP, or PDF; see the ScreenshotNeo API documentation for options.
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);
Cookie banners, newsletter popups, and chat widgets are removed before the shot, and each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are never billed; response headers identify the page verdict and billing status. An MCP server gives AI agents such as Claude and Cursor tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan. See ScreenshotNeo for product details and the docs for API options. Sign up for 1,000 free screenshots a month with no card.
FAQ
Does a consent cookie prove the application accepted consent?
No. It proves only that a cookie exists in a browser store. Check that it applies to the page URL and matches the application’s expected consent state.
Should I disable Cypress test isolation to keep the banner dismissed?
Usually, set or restore the required state explicitly. Disabling isolation can let one test’s changes affect another.
Can I hide the banner with CSS for a screenshot?
Yes, for a visual comparison where masking is intentional. It does not test consent behavior.
Why does the same screenshot code behave differently on another machine?
Browser version, operating system, headless mode, viewport, and rendering configuration can affect screenshots. Keep the environment consistent for visual comparisons.


