Use the headers option when calling fetch() in a web page: fetch(url, { headers: { "X-Client-Version": "1.2.3" } }). This JavaScript runs in a browser, not in Node.js merely because the project uses Node tooling. Browser code can set application headers such as X-Request-Id and, in ordinary cases, Authorization, but the browser controls fields such as Cookie, Host, and Origin. A cross-origin custom header can also cause an OPTIONS CORS preflight that the API must approve.
First identify where the request runs
“Node.js browser request” combines two different environments. A script bundled by a Node-based build tool and executed by a web page is browser code. It is governed by the browser’s CORS policy and forbidden-header rules. A script executed by a Node.js process is server-side JavaScript and uses Node’s networking APIs without the browser’s page security model.
The examples below label the runtime explicitly. Start with browser fetch(), then see XMLHttpRequest and Node.js alternatives.
Add headers with browser fetch()
Pass either a plain object or a Headers instance in the second argument to fetch(). The following GET request sends two application headers and checks both network success and the HTTP status:
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
const response = await fetch("https://api.example.com/items", {
method: "GET",
headers: {
"X-Client-Version": "1.2.3",
"Authorization": "Bearer YOUR_TOKEN",
},
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
console.log(data);
fetch() resolves to a response even for statuses such as 401 or 500, so test response.ok (or inspect response.status) before parsing a successful payload. Network failures and a rejected CORS request reject the promise instead.
POST JSON with custom headers
When sending JSON, declare the media type and serialize the body yourself:
const response = await fetch("https://api.example.com/items", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Request-Id": "abc123",
},
body: JSON.stringify({ name: "Example" }),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const created = await response.json();
A JSON content type and most non-simple custom headers commonly make a cross-origin request non-simple, which leads to a preflight described below.
Build and update a Headers object
A Headers object is useful when conditional code adds or replaces values. Header names are normalized and surrounding whitespace in values is trimmed:
const headers = new Headers();
headers.set("X-Client-Version", "1.2.3");
headers.set("Authorization", "Bearer YOUR_TOKEN");
const response = await fetch("https://api.example.com/items", { headers });
Use headers.set() to replace a value, headers.append() when the protocol intentionally permits multiple values, and headers.has() or headers.get() for inspection.
Rank #2
Set headers with XMLHttpRequest
XMLHttpRequest uses a sequence rather than one options object. Call setRequestHeader() only after open() and before send():
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/items");
xhr.setRequestHeader("X-Client-Version", "1.2.3");
xhr.setRequestHeader("Authorization", "Bearer YOUR_TOKEN");
xhr.onload = () => {
if (xhr.status < 200 || xhr.status >= 300) {
console.error(`HTTP ${xhr.status}`);
return;
}
const data = JSON.parse(xhr.responseText);
console.log(data);
};
xhr.onerror = () => console.error("Network or CORS failure");
xhr.send();
Calling setRequestHeader() repeatedly with the same name appends values rather than silently replacing the earlier value. XHR and Fetch share the same browser restrictions and CORS enforcement; changing APIs does not bypass them.
Why the browser removes or rejects a custom header
Forbidden request headers
Page JavaScript cannot freely control every HTTP field. The browser manages security- and transport-sensitive headers, including Cookie, Host, Origin, Content-Length, Connection, and names beginning with Sec-. Attempts to set such fields are blocked or ignored. There is no alternate spelling or Fetch syntax that grants page code control.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Cookies are attached according to cookie attributes and the request’s credential mode, not by constructing a Cookie header. The browser generates Origin from the requesting context. Likewise, connection framing and content length are calculated by the user agent.
Authorization is allowed, but protect it
An Authorization header can normally be set from browser JavaScript. Treat bearer tokens as secrets: avoid exposing long-lived credentials in URLs, logs, or publicly shipped source, and send them only to the intended origin. If a request is redirected cross-origin, XMLHttpRequest documentation notes that the authorization value may be removed.
Rank #3
How CORS preflight affects custom headers
CORS is enforced by the browser and configured by the server that owns the target resource. A cross-origin request that is not “simple”—for example, one using many custom headers, JSON content type, or a non-simple method—causes the browser to send an OPTIONS preflight first.
What the preflight contains
The browser identifies the requesting origin and asks whether the method and intended headers are permitted. The API must answer with matching CORS response headers, including an Access-Control-Allow-Headers value that lists your custom header (for example, X-Client-Version), plus an allowed method and origin. If the preflight fails, the actual GET or POST is never sent.
What to configure on your server
If you control the API, allow the exact frontend origin, method, and headers your application uses. For credentialed requests, the server must explicitly allow the requesting origin and credentials; a wildcard origin is not valid with credentials. Cookies remain subject to browser cookie policy.
If you do not control the API, changing client-side JavaScript cannot grant permission. Use a server-side proxy that you control, or ask the API owner to update its CORS policy.
Why no-cors is not a fix
mode: "no-cors" is not a workaround for an API that requires custom headers or a readable response. It restricts methods and headers and returns an opaque response whose body and headers are unavailable to JavaScript. You cannot use it to read JSON or verify an API status.
Rank #4
Browser fetch versus XMLHttpRequest
| Concern | fetch() | XMLHttpRequest |
|---|---|---|
| Configuration | One options object containing headers, method, body, and credentials |
Call open(), then setRequestHeader(), then send() |
| Control flow | Promise and async/await |
Load, error, progress, and timeout event handlers |
| Response handling | Read with json(), text(), or another body method |
Read responseText, responseXML, or configured response types |
| Browser restrictions | Forbidden headers and CORS apply | The same forbidden-header and CORS rules apply |
Fetch is the modern Promise-based interface for new code. XHR remains useful when an existing application depends on its event model or progress callbacks.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWhat changes in a Node.js process
Code running in Node.js is not a page request. Node.js documents global fetch as available from v18.0.0 and the global Headers class as no longer experimental from v21.0.0. The browser’s page CORS enforcement and forbidden request-header list should not be assumed to behave identically in Node; use the current Node.js documentation for the HTTP client and version you deploy.
Node.js global fetch example
const response = await fetch("https://api.example.com/items", {
headers: {
"X-Client-Version": "1.2.3",
"Authorization": "Bearer YOUR_TOKEN",
},
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
console.log(data);
This code belongs in a Node.js process (for example, a server, worker, or command-line script), not in a browser page. Keep secrets here rather than embedding them in frontend bundles whenever the architecture permits.
Equivalent command-line and Python requests
curl https://api.example.com/items
-H 'X-Client-Version: 1.2.3'
-H 'Authorization: Bearer YOUR_TOKEN'
import requests
response = requests.get(
"https://api.example.com/items",
headers={
"X-Client-Version": "1.2.3",
"Authorization": "Bearer YOUR_TOKEN",
},
timeout=30,
)
response.raise_for_status()
print(response.json())
These server-side examples can send headers that a browser page cannot. That difference is why a request succeeding in curl or Python does not prove that frontend Fetch will succeed: the browser may preflight it or block a forbidden field.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Debugging checklist
The header is absent in DevTools
- Confirm the code runs after the Fetch call is constructed and that the header name is spelled correctly.
- Check whether the name is browser-forbidden, such as
Origin,Cookie, orHost. Remove it and use the browser’s supported mechanism instead. - Inspect the actual request and any preceding
OPTIONSrequest in the Network panel. A failed preflight means there may be no actual request to inspect.
The console reports a CORS error
- Look at the preflight response and configure the API to allow the exact origin, method, and custom header.
- Do not try
no-corsif your code needs a response body. - If the API is third-party and cannot be configured, call it from your own backend and have the browser call that backend.
The server returns 401 or 403
- Verify the token scheme, spelling, and expiry;
Authorizationusually needs the expectedBearerformat. - Check that a redirect did not move the request to another origin and remove authorization.
- Inspect server authentication logs rather than assuming a browser header was accepted.
The request fails only after adding JSON
Content-Type: application/json can make a cross-origin request require preflight. Add that content type to the server’s allowed headers and ensure OPTIONS is routed without authentication that rejects the preflight.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteOr skip the browser setup
If your goal is a clean image or PDF of a URL rather than an API call from page JavaScript, ScreenshotNeo provides a single HTTP request and an MCP server for AI agents. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.
Use the API documentation at https://screenshotneo.com/docs/ for options such as custom headers, cookies, user agents, waits, blocking rules, full-page capture, PDF output, and signed links. A minimal call is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
There is also an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Sign up for ScreenshotNeo’s free plan.
FAQ
Can JavaScript set the User-Agent header?
Browser page code cannot freely replace browser-controlled networking fields. Set a user agent only in a server-side client or a controlled browser automation environment.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Does adding a custom header always trigger preflight?
No. The browser evaluates the complete method, header set, and content type against the CORS “simple request” rules. Headers outside that safelist commonly require preflight.
Should I put an API key in a frontend header?
Only when the API is designed for a public client credential and its exposure is acceptable. A secret key shipped to a browser can be copied; keep privileged credentials on a server.
Frequently Asked Questions
Can JavaScript set the User-Agent header?
Browser page code cannot freely replace browser-controlled networking fields. Set a user agent only in a server-side client or a controlled browser automation environment.
Does adding a custom header always trigger preflight?
No. The browser evaluates the complete method, header set, and content type against the CORS “simple request” rules. Headers outside that safelist commonly require preflight.
Should I put an API key in a frontend header?
Only when the API is designed for a public client credential and its exposure is acceptable. A secret key shipped to a browser can be copied; keep privileged credentials on a server.
Quick Recap
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.

