Node.js has no proxy setting you can just switch on: fetch and http ignore HTTP_PROXY unless you tell them otherwise. This guide shows the reliable way for each client: fetch with undici's ProxyAgent, axios with https-proxy-agent, SOCKS5 with socks-proxy-agent, proxies from environment variables, rotating and sticky IPs, and the errors you will see. Every script runs as is.
npm install
export FUSION_USER="your_username"
export FUSION_PASS="your_password"- fetch with a proxy
- axios with a proxy
- SOCKS5 proxy
- Proxy from environment variables
- Rotating and sticky IPs
- Errors and fixes
Node's built-in fetch runs on undici. Pass a ProxyAgent as the dispatcher:
import { fetch, ProxyAgent } from 'undici';
const dispatcher = new ProxyAgent({
uri: 'http://resi.fusionproxy.net:12286',
token: 'Basic ' + Buffer.from(`${USERNAME}:${PASSWORD}`).toString('base64'),
});
const res = await fetch('https://ipinfo.io/json', { dispatcher, signal: AbortSignal.timeout(30000) });
console.log(await res.json());- The
tokenis theProxy-Authorizationheader, so the credentials go to the proxy and never to the website. - Import
fetchfrom theundicipackage together withProxyAgent. Mixing the globalfetchwith aProxyAgentfrom a different undici version can fail with confusing errors. AbortSignal.timeout()stops a request through a dead proxy instead of waiting forever.
Script: 01_fetch_proxy.mjs
axios has a proxy option, but it does not open a CONNECT tunnel for HTTPS websites. Use an agent and set proxy: false:
import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';
const agent = new HttpsProxyAgent(`http://${encodeURIComponent(USERNAME)}:${encodeURIComponent(PASSWORD)}@resi.fusionproxy.net:12286`);
const client = axios.create({ httpsAgent: agent, httpAgent: agent, proxy: false, timeout: 30000 });
const { data } = await client.get('https://ipinfo.io/json');encodeURIComponent keeps @, : or / in a password from breaking the URL. The same agent works with node:https, got and most libraries that accept an agent.
Script: 02_axios_proxy.mjs
import { SocksProxyAgent } from 'socks-proxy-agent';
const agent = new SocksProxyAgent(`socks5h://${encodeURIComponent(USERNAME)}:${encodeURIComponent(PASSWORD)}@resi.fusionproxy.net:5390`);
const { data } = await axios.get('https://ipinfo.io/json', { httpsAgent: agent, httpAgent: agent, proxy: false });Use socks5h:// so the proxy resolves the host name and the DNS lookup does not leak from your machine.
Script: 03_socks5_proxy.mjs
undici's EnvHttpProxyAgent reads HTTP_PROXY, HTTPS_PROXY and NO_PROXY (upper or lower case). Make it the global dispatcher and every fetch uses it:
import { EnvHttpProxyAgent, fetch, setGlobalDispatcher } from 'undici';
setGlobalDispatcher(new EnvHttpProxyAgent());
await fetch('https://ipinfo.io/json'); // goes through HTTPS_PROXYexport HTTPS_PROXY="http://USERNAME:[email protected]:12286"
export NO_PROXY="localhost,127.0.0.1"
node 04_env_proxy.mjsundici 6 prints a warning that EnvHttpProxyAgent is experimental; it works, but pin your undici version.
Script: 04_env_proxy.mjs
A rotating residential gateway gives each new connection a new IP. Options in the username pick the country or keep one IP for a while:
const rotating = `${USERNAME}-country-us`; // new US IP per connection
const sticky = `${USERNAME}-country-us-sessid-4821937-sessTime-600s`; // one US IP for 10 minutesAgents keep connections open and reuse them, and a reused connection keeps its IP. Create a new agent when you want a new IP, and reuse one agent with a sticky username when you want to keep it. 05_rotating_sticky.mjs prints three rotating IPs and three identical sticky ones. The username format is in the endpoint generator guide.
| Error | Meaning | Fix |
|---|---|---|
Proxy response (407) !== 200 when HTTP Tunneling |
The proxy rejected the credentials | Check the username and password; encode special characters |
ECONNREFUSED / UND_ERR_CONNECT_TIMEOUT |
The proxy does not answer on that host and port | Wrong port, proxy down or blocked by a firewall |
timeout of 30000ms exceeded (axios) / TimeoutError (fetch) |
No answer in time | Retry with a new connection; on a rotating gateway that is a new IP |
self-signed certificate / unable to verify the first certificate |
Something in the path replaced the website's certificate | Do not set rejectUnauthorized: false; a proxy that does this reads your traffic |
403 or 429 from the website |
The site blocks or rate-limits the IP | Slow down, use normal headers, use a residential IP in the right country |
To test proxies without code, use the online proxy checker or the proxy-checker CLI.
No proxy yet? Fusion Proxy residential proxies start at $2.95/GB, with a free trial.
- puppeteer-proxy and playwright-proxy: proxies in headless browsers
- python-requests-proxy: the same in Python
- curl-proxy: proxies with cURL
MIT, see LICENSE.