HTTP

Debug Guide

Why Is My Cookie Not Being Sent?

A missing Cookie header usually means the browser rejected the cookie, decided the request was outside its scope, or withheld credentials. Follow the checks in order so you find the first broken condition.

1. Confirm the browser stored the cookie

Start with the response that creates the cookie. In DevTools, open Network, select the response, and inspectSet-Cookie. Then check the browser's Application or Storage panel. A cookie that never reached the cookie store cannot appear on a later request.

Browsers often show a blocked-reason indicator next to a rejected Set-Cookie header. Common causes include an invalid Domain, SameSite=None without Secure, a malformed attribute, or a third-party cookie policy.

curl -i https://api.example.com/session

HTTP/2 200
Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax

2. Match Domain, Path, and Secure to the request URL

For a stored cookie to be sent, every scope rule must match the destination URL:

Do not add a broad Domain or Path merely to make a test pass. Use the narrowest scope that covers the endpoints that actually need the cookie.

3. Determine whether the request is cross-site

SameSite is based on the registrable site and scheme, not only whether two URLs have different origins.app.example.com and api.example.com are cross-origin but normally same-site; an embedded request from customer.example to api.example.com is cross-site.

SameSite valueTypical behavior
StrictWithheld on cross-site requests, including top-level navigations.
LaxWithheld on most cross-site subrequests, but allowed on qualifying top-level navigations.
None; SecureEligible for cross-site use, subject to browser third-party cookie policy.

4. Include credentials on cross-origin fetch requests

Fetch uses same-origin credentials by default. When the API is on another origin, opt in explicitly:

const response = await fetch('https://api.example.com/me', {
  credentials: 'include'
})

The API response must also contain compatible CORS headers:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Vary: Origin

Credentialed requests cannot use Access-Control-Allow-Origin: *. The preflight response, when one is required, and the actual response must both satisfy the browser's CORS checks. Use theCORS Debugger or the preflight checklistto isolate that part of the failure.

5. Check lifetime, prefixes, and browser policy

Fast diagnosis checklist

  1. Confirm the cookie was stored: Inspect the Set-Cookie response and the browser cookie store before debugging the next request.
  2. Check URL scope: Verify that Domain, Path, and Secure match the URL receiving the request.
  3. Check SameSite context: Determine whether the request is same-site or cross-site and choose an appropriate SameSite value.
  4. Check fetch and CORS credentials: For cross-origin requests, include credentials on the client and allow credentials for the exact origin on the server.
  5. Check lifetime and browser policy: Verify expiration, cookie prefixes, storage limits, and third-party cookie restrictions.

Once you identify the mismatched rule, generate a corrected header with theCookie Builder, then verify the result in a fresh browser session.

Frequently Asked Questions

Why is a cookie visible in DevTools but absent from the request?

The cookie can be stored but out of scope for the request. Check its Domain, Path, Secure, SameSite, expiration, and whether the browser classifies the request as third-party.

Does fetch send cookies automatically?

Fetch sends same-origin credentials by default. For a cross-origin request, set credentials to include. The server must also allow credentials and return an exact allowed origin rather than a wildcard.

Why does SameSite=None still fail?

SameSite=None cookies must also use Secure, and Secure cookies require HTTPS except for browser-specific localhost handling. Third-party cookie policies can still block or partition them.

References