Referer or a session Cookie, pass a headers object as part of the third argument to get or post.
What happens when you pass headers
As soon as you pass a non-emptyheaders object, the SDK automatically sets custom_headers=true on the request for you, so you don’t need to add that yourself. This enables your custom headers for the target request while ZenRows continues to manage browser-fingerprinting headers automatically.
Headers you can and can’t override
Not every header can be customized. ZenRows always manages browser-fingerprinting headers itself to keep success rates high and avoid anti-bot detection, even whencustom_headers is enabled:
| Header | Customizable? |
|---|---|
Referer | Yes |
Cookie | Yes |
Authorization | Yes |
| Most other headers | Yes, once custom_headers=true is set |
User-Agent | No, always managed by ZenRows |
Sec-Ch-Ua, Sec-Ch-Ua-Mobile, Sec-Ch-Ua-Platform | No |
Accept-Encoding, Accept-Language | No |
Sec-Fetch-Mode, Sec-Fetch-Site, Sec-Fetch-User, Sec-Fetch-Dest | No |
Connection, Upgrade-Insecure-Requests, Cache-Control | No |
The SDK does send its own
User-Agent (zenrows/<version> node) as part of the HTTP request it makes to ZenRows’ API endpoint. This identifies the request as coming from the Node.js SDK for ZenRows’ own logging, it is not the header ZenRows sends to the target website. If you pass a User-Agent key in headers, it replaces this value on the request to ZenRows’ API, but that still has no bearing on what the target site receives.Combining with request parameters
The config object andheaders are independent arguments, so you can use both together:
If a request keeps failing after you add custom headers, try removing them first to confirm whether they’re the cause. ZenRows’ defaults are usually the safer starting point.
Troubleshooting
- Success rate drops after adding custom headers: Remove your custom
headersfirst to confirm whether they’re the cause; ZenRows’ defaults are usually the safer starting point. - Header doesn’t seem to reach the target site: Confirm you’re using the
headersargument (forwarded to the target) and not accidentally modifying the config object meant for ZenRows itself. - Cookies aren’t persisting across requests: Each SDK call is a separate, stateless request. Pass the
Cookieheader explicitly on every call if you need to maintain a session. custom_headersshows up unexpectedly in requests: This is set automatically whenever you pass a non-emptyheadersobject; it’s not something you need to remove.
Pricing
Custom headers don’t change the cost multiplier on their own. Cost still depends onjs_render and premium_proxy:
| Configuration | Cost multiplier vs. basic |
|---|---|
| Basic request | 1x |
js_render: true | 5x |
premium_proxy: true | 10x |
js_render: true + premium_proxy: true | 25x |
FAQ (Frequently Asked Questions)
Do I need to set custom_headers myself?
Do I need to set custom_headers myself?
No. Passing a non-empty
headers object to get or post sets custom_headers=true automatically.Can I override the User-Agent sent to the target site?
Can I override the User-Agent sent to the target site?
No.
User-Agent is one of several browser-fingerprinting headers ZenRows always manages for the request to the target, regardless of what you pass in headers. See the table above for the full list.Can I set headers meant for ZenRows itself (like an API version header)?
Can I set headers meant for ZenRows itself (like an API version header)?
No.
headers is forwarded to the target website, not to ZenRows’ API. ZenRows-specific options belong in the config object (the second argument).