Extensions for JavaScript HTTP libraries to support sending and receiving custom proxy headers during HTTPS CONNECT tunneling.
When making HTTPS requests through a proxy, the connection is established via a CONNECT tunnel. During this process:
Sending headers to the proxy - Most JavaScript HTTP libraries don't provide a way to send custom headers (like
X-ProxyMesh-Country) to the proxy server during the CONNECT handshake.Receiving headers from the proxy - The proxy's response headers from the CONNECT request are typically discarded, making it impossible to read custom headers (like
X-ProxyMesh-IP) that the proxy sends back.
This library solves both problems for popular JavaScript HTTP libraries.
| Library | Subpath export | Notes |
|---|---|---|
| axios | javascript-proxy-headers/axios | Widely used client |
| node-fetch | javascript-proxy-headers/node-fetch | Fetch API on Node |
| got | javascript-proxy-headers/got | Ergonomic API |
| undici | javascript-proxy-headers/undici | Node’s fast HTTP stack |
| superagent | javascript-proxy-headers/superagent | Chaining API |
| ky | javascript-proxy-headers/ky | Tiny fetch wrapper |
| wretch | javascript-proxy-headers/wretch | Fetch wrapper (sets wretch’s global fetch polyfill) |
| make-fetch-happen | javascript-proxy-headers/make-fetch-happen | npm-style fetch (cache, retries, proxy) |
| needle | javascript-proxy-headers/needle | Lean HTTP client |
| typed-rest-client | javascript-proxy-headers/typed-rest-client | Azure / DevOps–style REST client |
urllib is not integrated yet: it expects an undiciDispatcher, not a Node Agent. See notes/urllib-integration-deferred.md in this repo for a possible approach.
npm install javascript-proxy-headersThen install the HTTP client(s) you use (for example axios, got, ky, wretch, make-fetch-happen, needle, or typed-rest-client). Each is an optional peer dependency.
Note: This package has no runtime dependencies by default—install only the adapters you need.
import{createProxyAxios}from'javascript-proxy-headers/axios';constclient=createProxyAxios({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitclient.get('https://httpbin.org/ip');// Proxy headers are merged into response.headersconsole.log(response.headers['x-proxymesh-ip']);import{proxyFetch}from'javascript-proxy-headers/node-fetch';constresponse=awaitproxyFetch('https://httpbin.org/ip',{proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});// Proxy headers available on responseconsole.log(response.proxyHeaders.get('x-proxymesh-ip'));import{createProxyGot}from'javascript-proxy-headers/got';constclient=createProxyGot({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitclient('https://httpbin.org/ip');console.log(response.headers['x-proxymesh-ip']);import{request}from'javascript-proxy-headers/undici';const{ statusCode, headers, body, proxyHeaders }=awaitrequest('https://httpbin.org/ip',{proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});console.log(proxyHeaders.get('x-proxymesh-ip'));Uses a custom fetch built from node-fetch + ProxyHeadersAgent (ky.create({ fetch })).
import{createProxyKy}from'javascript-proxy-headers/ky';constapi=awaitcreateProxyKy({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitapi('https://httpbin.org/ip');console.log(response.proxyHeaders.get('x-proxymesh-ip'));Registers the same custom fetch as wretch’s fetch polyfill. Use the normal wretch chain (for example .get().res()).
import{createProxyWretch}from'javascript-proxy-headers/wretch';constwretch=awaitcreateProxyWretch({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitwretch('https://httpbin.org/ip').get().res();console.log(response.proxyHeaders.get('x-proxymesh-ip'));Passes a ProxyHeadersAgent as agent; @npmcli/agent uses it as-is when set.
import{createProxyMakeFetchHappen}from'javascript-proxy-headers/make-fetch-happen';constfetch=createProxyMakeFetchHappen({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitfetch('https://httpbin.org/ip');console.log(response.proxyHeaders.get('x-proxymesh-ip'));import{proxyNeedleGet}from'javascript-proxy-headers/needle';constres=awaitproxyNeedleGet('https://httpbin.org/ip',{proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});// CONNECT response headers merged onto res.headers where missingconsole.log(res.headers['x-proxymesh-ip']);Uses a subclass of HttpClient that routes HTTPS through ProxyHeadersAgent (no tunnel agent).
import{createProxyRestClient}from'javascript-proxy-headers/typed-rest-client';constclient=createProxyRestClient({userAgent: 'my-app',proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});awaitclient.get('https://httpbin.org/ip');console.log(client.proxyAgent.lastProxyHeaders?.get('x-proxymesh-ip'));For direct control, use the core ProxyHeadersAgent:
import{ProxyHeadersAgent}from'javascript-proxy-headers';importhttpsfrom'https';constagent=newProxyHeadersAgent('http://proxy.example.com:8080',{proxyHeaders: {'X-ProxyMesh-Country': 'US'},onProxyConnect: (headers)=>{console.log('Proxy IP:',headers.get('x-proxymesh-ip'));}});https.get('https://httpbin.org/ip',{ agent },(res)=>{// Handle response});Integration tests need a real proxy (set PROXY_URL or HTTPS_PROXY):
export PROXY_URL='http://user:pass@proxy.example.com:8080'
npm test# all adapters (see package.json "test")
node run_tests.js -v # same harness from repo root
npm run test:ts # same checks via tsx + TypeScript harness
npm run test:types # `tsc --noEmit` only (no network)# Limit modules
node test/test_proxy_headers.js -v axios kyVerbose (-v) prints captured header values. See test/test_proxy_headers.js --help.
- Node.js >= 18.0.0
- One or more supported HTTP libraries
- python-proxy-headers - Same functionality for Python
- proxy-examples - Example code for using proxies
Created by ProxyMesh to help our customers use custom headers to control proxy behavior. Works with any proxy that supports custom headers.
MIT License