Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →In modern Node.js, send custom request headers by passing a headers object to fetch(). For lower-level control, pass headers to http.request() or call req.setHeader() before the request is sent. Header names are case-insensitive, existing values are replaced when set again, and arrays are used when a protocol requires repeated values.
Send headers with the built-in fetch API
Node.js includes a web-standard fetch API. Put authentication, tracing, content negotiation, and other metadata in the request options:
const token = process.env.API_TOKEN;
const traceId = crypto.randomUUID();
const response = await fetch('https://api.example.com/data', {
headers: {
Authorization: `Bearer ${token}`,
'X-Trace-Id': traceId,
Accept: 'application/json'
}
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status} ${response.statusText}`);
}
const data = await response.json();
console.log(data);
In an ES module, import the UUID helper when needed:
import crypto from 'node:crypto';
If your project uses CommonJS, use const crypto = require('node:crypto');. The headers option accepts a plain object or a Headers instance.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →#1 Best Overall
POST, PUT, and JSON bodies
The header mechanism is the same for every HTTP method. Add method, serialize the body, and identify its media type:
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.API_TOKEN}`,
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: JSON.stringify({ name: 'Ada', role: 'admin' })
});
const text = await response.text();
console.log(response.status, text);
Do not put a JavaScript object directly in body; convert JSON with JSON.stringify(). Keep tokens out of source control and avoid logging the complete headers object.
Using a Headers instance
const headers = new Headers({
Authorization: `Bearer ${process.env.API_TOKEN}`,
Accept: 'application/json'
});
headers.set('X-Client-Version', '2');
const response = await fetch('https://api.example.com/data', { headers });
Headers normalizes names and provides methods such as set(), append(), get(), and has(). Whether a repeated value is valid depends on the header’s protocol rules; do not use repetition merely to work around a typo.
Use node:http when you need lower-level control
The node:http module exposes the request stream and callback events. Supply a headers object in the options:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
import http from 'node:http';
const token = process.env.API_TOKEN;
const req = http.request('http://localhost:3000/resource', {
method: 'GET',
headers: {
Authorization: `Bearer ${token}`,
'X-Trace-Id': 'trace-123',
Accept: 'application/json'
}
}, (res) => {
let body = '';
res.setEncoding('utf8');
res.on('data', chunk => { body += chunk; });
res.on('end', () => {
console.log(res.statusCode, body);
});
});
req.on('error', console.error);
req.end();
Always finish a request. Calling req.end() sends a request with no body; for a body, write it before ending.
Rank #2
Set a header after creating the request
import http from 'node:http';
const req = http.request('http://localhost:3000/resource', (res) => {
res.pipe(process.stdout);
});
req.setHeader('X-Trace-Id', 'trace-123');
req.setHeader('Authorization', `Bearer ${process.env.API_TOKEN}`);
req.end();
request.setHeader(name, value) sets one outgoing value. If the same header already exists, the new value replaces it. Configure every header before the request is sent; changing a queued header after headers have been flushed is too late.
Repeated headers, cookies, and replacement rules
Node treats ordinary header-name lookup case-insensitively. Content-Type, content-type, and CONTENT-TYPE identify the same header. Setting a name again replaces its value rather than creating an accidental duplicate.
When a protocol explicitly allows multiple values with the same name, pass an array of strings:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsreq.setHeader('Cookie', [
'type=ninja',
'language=javascript'
]);
Use this pattern only for headers whose wire format supports repetition. Combining values with commas is not interchangeable for every header, and multiple Authorization values are normally invalid.
Inspect headers before they leave a node:http request
Lower-level requests provide methods that make configuration errors visible:
Rank #3
import http from 'node:http';
const req = http.request('http://localhost:3000/resource', {
headers: { 'X-Debug': 'one' }
}, res => {
res.resume();
});
console.log(req.getHeaders());
console.log(req.getHeaderNames());
console.log(req.getHeader('x-debug'));
console.log(req.hasHeader('X-Debug'));
console.log(req.getRawHeaderNames());
req.end();
getHeaders() returns the queued values, while getHeaderNames() lists ordinary names. getRawHeaderNames() preserves the casing used when each name was set. Ordinary lookup remains case-insensitive.
This inspection proves what Node queued, not necessarily what a proxy forwarded or what the destination accepted. For fetch, confirm receipt at a server you control or with a controlled request-inspection endpoint. Never print bearer tokens, cookies, or other secrets in production logs.
Choosing fetch or node:http
| Need | fetch | node:http |
|---|---|---|
| Simple promise-based request | Compact, web-standard API | Requires callbacks and stream handling |
| Direct request-stream control | Higher-level abstraction | Explicit request methods and events |
| Repeated values | Uses the Headers abstraction and protocol handling |
Arrays explicitly send multiple values with one name |
| Client-side header inspection | Usually verify at the server or network boundary | getHeaders(), getHeaderNames(), hasHeader(), and related methods |
| Portability | Follows the web Fetch API shape | Specific to Node’s HTTP stack |
Use fetch for most new application and service code. Choose node:http when you need stream-level behavior, callback events, or explicit inspection of queued headers.
Header values, encoding, and security limits
- Header values are converted for network transmission. Invalid characters in a string can cause Node to throw.
- Do not place newlines or untrusted raw text in a header value; validate user-controlled input before constructing headers.
- For UTF-8 filename parameters, use the standards-based encoding required by the relevant protocol rather than inserting arbitrary Unicode into a legacy parameter.
- Request headers describe what your client sends. They are different from response headers:
req.setHeader()configures an outgoing request, while a Node server usesres.setHeader()for its response. - Authentication headers do not override TLS requirements. Send credentials over HTTPS and avoid exposing them in error messages, URLs, or debug output.
Common failures and fixes
The server says the header is missing
- Check that the header is inside the
headersoption, not beside it. - With
node:http, callsetHeader()beforereq.end()and before any operation that flushes the request. - Inspect
req.getHeaders(), then verify at the receiving server. A redirect, reverse proxy, or gateway may alter what arrives.
A second value did not appear
Calling setHeader() twice replaces the first value. Use an array only when the protocol permits repeated fields, such as multiple cookies.
Authentication fails despite a token
- Use the scheme expected by the API, commonly
Authorization: Bearer TOKEN. - Confirm the token is not undefined because an environment variable was absent.
- Check that a redirect or proxy is not removing credentials when crossing origins. Follow the API’s redirect and authentication rules rather than blindly forwarding secrets.
Node throws an invalid-header error
Inspect the value for control characters, accidental line breaks, or unvalidated user input. Header values must be valid for HTTP transmission.
Rank #4
The request hangs
Ensure req.end() is called, consume or resume the response stream, and attach an error listener. With fetch, set an appropriate timeout strategy for your application and handle rejected promises.
The response body is empty or truncated
For node:http, wait for the end event or pipe the response. For JSON with fetch, call response.json() only after checking that the server returned a compatible body and status.
Test a custom header with a tiny local server
A local receiver lets you distinguish client configuration from a remote gateway problem:
import http from 'node:http';
const server = http.createServer((req, res) => {
console.log(req.headers);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ received: req.headers['x-trace-id'] ?? null }));
});
server.listen(3000, () => console.log('Listening on http://localhost:3000'));
Run the server, send the earlier request to http://localhost:3000/resource, and check the printed lower-case key. Node’s incoming-header object uses normalized names, so casing in the original source is not a reliable way to test whether a field arrived.
Performance and reliability considerations
- Keep a single, reusable header-construction function so authentication and tracing rules are consistent across calls.
- Do not create large diagnostic headers; intermediaries impose size limits and may reject requests before your application sees them.
- Use connection reuse and an appropriate HTTP client strategy for high-volume workloads, but treat retries carefully: replaying a request with an expired token or a non-idempotent body can create a second side effect.
- Log status, request identifiers, and timing, not secret header values. Correlate failures with a trace ID that is safe to record.
- Test through the same proxy, load balancer, or service mesh used in production when header behavior matters; local success does not prove an intermediary will preserve every field.
Or skip the browser setup
If your goal is to send headers while capturing a page rather than to build an HTTP client, ScreenshotNeo accepts custom headers directly in one screenshot request. It also removes cookie-consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Its MCP server gives Claude, Cursor, and other MCP clients screenshot, page-info, and PDF tools.
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 reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchHere is the Node.js call (see the ScreenshotNeo documentation for all parameters):
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', buffer));
The same endpoint can be called with cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Or Python:
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)
ScreenshotNeo includes 1,000 screenshots a month free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Can I use lowercase header names?
Yes. HTTP header names are case-insensitive, and Node’s ordinary lookup treats different casing as the same name.
Does setting a header twice append it?
No. The later value replaces the earlier one. Use an array only when repeated fields are valid for the protocol.
Why can a header visible in Node still be absent at the API?
Node may have queued it correctly while a redirect, proxy, gateway, or destination policy changes or rejects it. Verify at the receiving boundary.
Frequently Asked Questions
Should new Node.js code use fetch or node:http for custom headers?
Use the built-in fetch API for most requests. Choose node:http when you need direct request-stream control, callback events, or detailed inspection of queued headers.
How do I send multiple Cookie headers?
With node:http, pass an array such as req.setHeader('Cookie', ['type=ninja', 'language=javascript']), provided the target protocol accepts repeated values.
Can I change headers after calling req.end()?
No. Configure headers before the request is sent; after they are flushed, changing the queued value is too late.
Recommended Free Tools
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.

