Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

A Puppeteer script cannot grant a website permission to read a cross-origin response. CORS is enforced by the browser context running the page, so the durable fix is usually to configure the API server’s response headers—or, if you do not control that server, make the request through a proxy you operate. First identify the failing request and whether it is credentialed or triggers an OPTIONS preflight; then choose a fix that matches those details.

What Puppeteer’s CORS error means

Cross-Origin Resource Sharing (CORS) is a browser security mechanism. When code running on one origin—for example, https://app.example—tries to read a response from another origin, the browser checks whether the server permits that access. A page can display an error even if the network request reached the server: the browser may refuse to expose the response to page JavaScript because the response does not authorize the page’s origin.

This distinction matters in Puppeteer because a script can control Chromium, but it cannot use page-level request options to grant permission on behalf of a remote server. Adding Access-Control-Allow-Origin to an outgoing request does not fix a missing response header. That permission must come from the server receiving the request.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Also distinguish a request made by page JavaScript from one made directly by your Node.js process. CORS is a browser rule; a Node-side HTTP client does not enforce it in the same way. Moving a request from the page to Node may be appropriate for a server-side workflow, but it changes where the request runs and requires you to handle authentication, authorization, and safe access yourself.

Diagnose the exact failing request

  1. Reproduce it with Chromium’s DevTools open. Inspect the Console and Network panels while the page runs. Record the request URL, the page’s origin, method, status, request headers, response headers, and any console explanation.
  2. Look for an OPTIONS request. A browser may send a preflight before the actual request. If the OPTIONS request fails or its response omits a required permission, changing only the eventual GET or POST response will not solve the problem.
  3. Check the response, not just the request. Find whether Access-Control-Allow-Origin is present and whether its value matches the requesting origin and credential policy.
  4. Check the request shape. Note the method, custom headers, and content type. Non-simple methods, custom headers, or non-safelisted content types commonly cause a preflight.
  5. Check credentials. Determine whether cookies or other credentials are sent. Credentialed reads require an explicit origin rather than *.

Use the browser’s reported reason to narrow the fault: a missing or mismatched allow-origin response, an OPTIONS response that does not allow the requested method or headers, and a wildcard origin combined with credentials are different problems and need different server policies.

Fix the server’s CORS response

If you control the API, configure its CORS policy at the server, gateway, or reverse proxy that produces the response. Allow only the origins that need access. The correct methods and headers depend on the actual request; do not copy a broad policy without checking the application’s requirements.

Public endpoint without credentials

For an endpoint intentionally readable by any origin without credentials, the response can use:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Access-Control-Allow-Origin: *

This does not make a private or credentialed endpoint safe to expose. Use it only when the endpoint is meant to be public and the request does not require a credentialed browser read.

Allowlisted application with credentials

For an approved application origin that sends credentials, return that specific origin and the credentials permission:

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

The server must emit the actual approved origin, not *, for a credentialed read. If the server chooses the response origin dynamically from an allowlist, Vary: Origin tells caches that the response can differ according to the incoming origin. Do not blindly reflect every supplied origin; validate it against an explicit allowlist.

Preflighted requests

When the browser sends an OPTIONS preflight, the server must answer it with permission covering the real request. The preflight response needs the appropriate Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers values. Include the method and request headers the browser is asking to use, and ensure the eventual response also has the applicable CORS headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not assume the browser will accept a successful HTTP status alone. A server can return an OPTIONS response successfully and still fail CORS if the required allow-origin, method, or header values are absent or do not match.

Make the request simpler when the API contract allows

A request that avoids a preflight can be easier to support, but simplifying the request does not bypass the server’s allow-origin policy. If page JavaScript still needs to read a cross-origin response, the server must authorize that origin. Remove a custom header or use a different method or content type only if doing so is valid for the API and does not weaken its security or change the operation.

For example, removing an unnecessary custom header may avoid one common preflight trigger. It will not help if the server still omits Access-Control-Allow-Origin, and it is not a substitute for sending required authentication or content-type information.

What Puppeteer can and cannot change

Puppeteer has useful request-level controls, but they shape what the browser sends or how the script handles requests. They do not make the remote server expose a response that its CORS policy withholds.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Add an outgoing header

page.setExtraHTTPHeaders() adds headers to requests initiated by that page. For example, set an API key if the target API requires one:

await page.setExtraHTTPHeaders({
  "x-api-key": process.env.API_KEY,
});

Puppeteer’s documentation states that these extra headers are sent with every request the page initiates. Because this can affect requests beyond the one API call, avoid placing a sensitive credential in a page-wide header unless it is appropriate for every request the page makes. Adding Access-Control-Allow-Origin here is not a fix: that header is a server response permission, not a client-side grant.

Intercept, continue, abort, or respond to requests

Request interception is for controlling request handling, not for overriding a remote server’s browser-enforced CORS policy. When interception is enabled, every intercepted request must be completed by continuing it, aborting it, or responding to it. A minimal continuation handler is:

await page.setRequestInterception(true);
page.on("request", request => {
  if (request.isInterceptResolutionHandled()) return;
  request.continue();
});

Use request.abort() when intentionally blocking a request, or request.respond() when intentionally fulfilling one yourself. If another handler has already resolved an intercepted request, the guard avoids attempting to resolve it again. Interception may help diagnose or shape traffic, but it is not a way to compel an unrelated API to authorize your page’s origin.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use a proxy when you do not control the API

If the remote API does not include the required CORS response header and you cannot change its configuration, the browser-side page cannot repair that server policy. A practical alternative is a server-side proxy that you operate: the page calls your own origin, and your server makes the upstream request.

A proxy moves the cross-origin server request out of the browser’s page context; it does not remove your responsibility to protect the upstream service. Require suitable authentication, enforce an origin and access policy, validate destinations, and avoid reflecting arbitrary incoming origins. Otherwise, a proxy can become an unintended open relay or expose private data. It must also preserve the upstream API’s intended authorization checks rather than treating CORS as authentication.

Why no-cors usually does not fix it

Fetch’s mode: "no-cors" can produce an opaque response: page JavaScript cannot inspect its body or headers. It is useful only when the script does not need to read the response—for example, when a request’s completion is enough for the intended use. If the Puppeteer page needs to parse JSON, examine headers, or inspect the response status, an opaque response does not solve the problem.

Choose the right fix

Situation Appropriate approach
You control the API and the page needs to read its response Configure the server’s CORS response for the required origin, method, headers, and credential policy.
The request triggers OPTIONS Make the preflight response cover the requested origin, method, and headers, as well as the actual response policy.
The endpoint is public and the browser request is non-credentialed A wildcard origin may be appropriate if the API is intentionally public.
The browser sends cookies or other credentials Return an explicit approved origin and the credentials permission; do not use wildcard origin for the credentialed read.
You do not control the upstream API, and the page must read the result Use a proxy you operate with its own authentication, destination validation, and origin policy.
The script does not need to inspect the response no-cors may be suitable if an opaque response meets the actual requirement.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting common CORS failures

The error says the allow-origin header is missing

Inspect the response that Chromium actually received, including redirects and error responses. Add an appropriate Access-Control-Allow-Origin response at the server or gateway that handles that path. A header added to Puppeteer’s outgoing request will not supply it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The allow-origin value does not match

Compare the page origin—including scheme, host, and port—with the server’s returned value. Configure the exact approved origin or a policy appropriate for a public, non-credentialed endpoint. If the value is selected dynamically, make sure the selection uses an allowlist and the response includes Vary: Origin.

The request fails before the GET or POST

Find the OPTIONS request in Network. Configure the server to answer the preflight with the required origin, method, and headers. Check custom headers and content type against what the preflight requested; allowing only the eventual method while leaving OPTIONS unhandled still fails.

The request works without cookies but fails with them

Check whether the server returns Access-Control-Allow-Origin: *. A wildcard is incompatible with a credentialed browser read. Return the approved requesting origin and Access-Control-Allow-Credentials: true, then verify that the browser is actually sending the intended credentials.

The script cannot parse a no-cors response

That is expected for an opaque response. If the page needs the body or headers, use a server configuration that permits the read or route the request through a secured proxy you control.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Requests hang after enabling interception

Check that every intercepted request is completed exactly once. Continue requests you are not changing, abort only those you intend to block, and use a resolution guard if multiple handlers may act on the same request.

Or skip the browser setup

If your goal is to capture a rendered page rather than debug a page’s API call, ScreenshotNeo can return a screenshot or PDF without setting up Puppeteer and Chromium yourself. It is not a fix for an application’s CORS policy or a way to read an API response. Its capture flow can accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, with the outcome reported in response headers. It also has an MCP server with screenshot, page-info, and PDF tools for AI agents; usage starts with 1,000 screenshots per month free without a card, and paid plans start at $5 for 3,000 shots.

For example, capture a rendered page as WebP with one GET request:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options and response details. To try the service, sign up for 1,000 free screenshots a month with no card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

FAQ

Does Puppeteer itself enforce CORS?

CORS is enforced by the browser context running the page. A Node.js request made outside that page is not the same as page JavaScript making a cross-origin browser request.

Can I add Access-Control-Allow-Origin with setExtraHTTPHeaders?

No. That sets an outgoing request header. The relevant permission must be returned by the server in its response.

Can a Puppeteer proxy make the server allow my origin?

A proxy can make an upstream request from your server rather than from the browser page, but it does not change the upstream server’s policy. Your proxy must enforce its own access controls and should not reflect arbitrary origins.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.