Puppeteer Cookie SameSite Settings Explained
Set Puppeteer’s SameSite value deliberately: learn when Strict, Lax, None, and Default send a cookie, and how to diagnose missing cross-site cookies.
Set the sameSite property on the cookie object passed to BrowserContext.setCookie(). Use 'Lax' for the common default when a cookie should accompany same-site requests and eligible cross-site top-level safe navigations. Use 'Strict' when it should be sent only for same-site requests. Use 'None' when it must be sent in cross-site contexts, and pair it with secure: true. Puppeteer also accepts 'Default'; omitting the property leaves behavior to the browser. Puppeteer documents the four values, and MDN describes their request behavior.
Set SameSite on a Puppeteer cookie
Here is a runnable JavaScript example for current Puppeteer. Install Puppeteer with npm install puppeteer, save this as cookie.mjs, then run node cookie.mjs. Replace the example URL and value with the cookie’s actual target and test credentials.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
try {
const context = await browser.createBrowserContext();
const page = await context.newPage();
await context.setCookie({
name: 'session',
value: 'example-session-value',
url: 'https://example.test/',
sameSite: 'Lax',
secure: true,
httpOnly: true,
});
await page.goto('https://example.test/', { waitUntil: 'domcontentloaded' });
console.log(await context.cookies('https://example.test/'));
await context.close();
} finally {
await browser.close();
}
The url scopes the cookie to the target site; you can instead use appropriate domain and path fields. Do not specify conflicting scope fields. A cookie’s SameSite policy does not correct a domain, path, expiry, or scheme mismatch. Puppeteer’s CookieData reference lists the cookie fields, including name, value, url, domain, path, expires, secure, httpOnly, sameSite, and browser-supported fields such as partitionKey.
Use the browser context that owns the page
Cookies are stored in a browser context. If you created an isolated context, set the cookie there and create or use the page from that same context. A cookie set on the default context will not automatically appear in a separate context. Browser.setCookie(...cookies) is a shortcut for setting cookies in the default context; BrowserContext has its own setCookie() method.
// Isolated context: set and use the cookie in this context.
const context = await browser.createBrowserContext();
await context.setCookie({
name: 'session',
value: 'example-session-value',
url: 'https://example.test/',
sameSite: 'Lax',
});
const page = await context.newPage();
// Default context shortcut:
await browser.setCookie({
name: 'session',
value: 'example-session-value',
url: 'https://example.test/',
sameSite: 'Lax',
});
What each SameSite value does
| Value | Cross-site behavior | When to choose it |
|---|---|---|
Strict |
Cookie is limited to same-site requests. | Use when the cookie should not accompany requests initiated from another site. |
Lax |
Allows same-site requests and qualifying cross-site top-level navigations using safe methods. Typical cross-site fetches, embedded resources, iframe navigations, and unsafe methods such as POST are excluded. | A practical default for ordinary first-party session behavior when the application needs cookies on inbound link navigation. |
None |
Allows cross-site inclusion as well as same-site requests, subject to Secure and browser privacy policy. | Use only when the application needs a cookie in a cross-site context, such as embedded content. |
Default |
Uses the browser’s default handling. | Use only when relying on browser defaults is intentional; specify a value for predictable behavior. |
| Omitted | Also leaves behavior to the browser. | Explicitly set the intended value when consistency matters. |
For SameSite=None, set secure: true and use HTTPS in normal deployment. Browsers can also restrict third-party cookies independently, so None does not guarantee a third-party cookie will be accepted or sent. MDN notes that Chromium defaults an unspecified SameSite value to Lax, while defaults vary across browsers; see MDN’s third-party cookie guidance.
Choose based on the request Puppeteer will make
- Is the request same-site? SameSite restrictions generally matter at a site boundary. A different origin is not necessarily a different site: origin includes scheme, host, and port, while site comparisons are based on the site boundary and scheme. Check the actual initiating and destination sites, including HTTP versus HTTPS.
- Is it a top-level navigation? A user-like navigation to the cookie’s site can qualify under Lax. A
fetch(), image or script request, or iframe request is not an eligible top-level navigation. - Is the method safe? Lax does not normally include cookies on cross-site POST, PUT, or DELETE requests. Do not depend on browser-specific temporary default behavior to make an unsafe request work.
- Does the use case truly require cross-site inclusion? Choose
Nonewithsecure: true, then account for browser third-party-cookie restrictions and any partitioning requirements. - Is a less permissive setting sufficient? Prefer
StrictorLaxwhen it meets the application’s flow. SameSite is one layer of CSRF protection, not a complete CSRF defense.
Cookie attributes that are separate from SameSite
securerestricts the cookie to secure transport. It is required withsameSite: 'None'.httpOnlyprevents page JavaScript from reading the cookie. It does not decide whether the browser sends it.url,domain, andpathcontrol where the cookie applies. A correct SameSite value cannot make an out-of-scope cookie match a request.expirescontrols expiration; if absent, the cookie is a session cookie. An expired cookie will not be sent regardless of SameSite.partitionKeyis available for partitioned-cookie contexts in supported browsers. It is distinct from SameSite; follow the target application’s cookie design.
For session cookies, consider HttpOnly and Secure for their separate security purposes. SameSite can reduce some CSRF exposure, but it does not replace application-level CSRF protections where needed. See MDN’s cookie security guidance.
Verify whether the cookie was set and sent
- Call
setCookie()before navigation or before triggering the request you want to inspect. - Use the page’s browser context to inspect cookies for the destination URL:
await context.cookies('https://example.test/'). - Check the request in Puppeteer’s request event and inspect its headers. This helps distinguish “cookie was never stored” from “cookie was stored but excluded from this request.”
- Compare the request type, initiator site, method, destination scheme, domain, and path with the cookie’s attributes.
page.on('request', request => {
if (request.url().startsWith('https://example.test/')) {
console.log(request.method(), request.url(), request.headers().cookie ?? '(no cookie header)');
}
});
Do not print real session values in production logs. Use disposable credentials when diagnosing cookie transmission.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Cookie is absent from a cross-site fetch() with Lax. |
Lax permits only qualifying top-level cross-site safe navigations, not typical fetches. | If cross-site transmission is required, use sameSite: 'None' and secure: true; verify third-party cookie policy too. |
Cookie is rejected or absent with SameSite=None. |
The Secure attribute is missing, the context is not secure, or browser third-party-cookie policy blocks it. | Set secure: true, use HTTPS, and check the browser’s cookie policy and diagnostics. |
| Cookie appears in one page but not another. | The pages belong to different browser contexts, or the cookie’s URL/domain/path scope does not match. | Set it through the page’s own context and correct its scope. |
| Cookie appears stored but is not attached to a request. | SameSite, domain, path, expiry, secure transport, or browser privacy rules exclude it. | Inspect the actual request class and each cookie attribute separately. |
| Behavior changes between browser versions. | SameSite was omitted or set to Default, so browser defaults or privacy rules determine behavior. | Set the intended value explicitly and test the target browser configuration. |
setCookie() rejects the cookie data. |
Required fields are missing, scope is invalid or conflicting, or a browser constraint is violated. | Provide name and value, choose a valid URL or domain/path scope, and pair None with Secure. |
Cookie is not visible through document.cookie. |
It may be marked httpOnly: true. |
Inspect via the browser context cookie API or request headers; HttpOnly cookies are intentionally unavailable to page JavaScript. |
Performance, reliability, and cost
Setting a cookie in a browser context is a local browser operation; SameSite itself adds no network round trip. For reliable automation, set cookies in the correct context before the request, use explicit SameSite values, and avoid relying on third-party-cookie behavior that can vary by browser policy. Reuse a browser process when appropriate, but keep user or test sessions isolated in separate contexts so cookies do not leak between jobs. Cookie configuration has no separate Puppeteer fee; infrastructure cost depends on where and how long the browser runs.
Or skip the browser setup
If the task is to capture a page rather than automate that page’s own session-cookie flow, ScreenshotNeo can return a screenshot or PDF from one GET request. Its cookie-banner, popup, and chat-widget cleanup runs before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000. See the ScreenshotNeo API docs.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.test -o shot.webp
Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Should I set SameSite to Lax or None?
Choose Lax unless the cookie must accompany cross-site subresource, iframe, or fetch requests. For those cases, None requires Secure and may still be affected by browser privacy controls.
Does SameSite=None mean the cookie is sent everywhere?
No. Domain, path, expiry, Secure, browser policy, and partitioning can still affect whether it is accepted or included.
Can I read a SameSite cookie in page JavaScript?
SameSite does not determine script access. The separate httpOnly attribute controls whether page JavaScript can read it.
Does Puppeteer’s Browser.setCookie() set cookies for every context?
No. It sets cookies in the default browser context. Use the relevant BrowserContext.setCookie() for an isolated context.


