fetch / undici
On Node 18+ pass a dispatcher with a ProxyAgent. Works for both HTTP and HTTPS targets:
undici-fetch.jsjavascript
import { ProxyAgent } from "undici";
const dispatcher = new ProxyAgent(
"http://USER:[email protected]:8080"
);
const r = await fetch("https://api.ipify.org", { dispatcher });
console.log(r.status, await r.text());
On Node ≤ 17 the global
fetch doesn't exist; install undici directly and use request from it, or fall back to node-fetch with https-proxy-agent.axios
axios doesn't support HTTPS-via-HTTP-proxy out of the box on the legacy proxy option — use https-proxy-agent:
axios-proxy.jsjavascript
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent(
"http://USER:[email protected]:8080"
);
const r = await axios.get("https://api.ipify.org", {
httpAgent: agent,
httpsAgent: agent,
proxy: false, // disable axios's built-in proxy handling
timeout: 20000,
});
console.log(r.status, r.data);
proxy: false is critical
Without proxy: false, axios tries to combine its own proxy handler with the agent and you get unpredictable behaviour. Disable axios's handler explicitly when supplying an agent.node-fetch
node-fetch-proxy.jsjavascript
import fetch from "node-fetch";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent(
"http://USER:[email protected]:8080"
);
const r = await fetch("https://api.ipify.org", { agent });
console.log(r.status, await r.text());
got
got-proxy.jsjavascript
import got from "got";
import { HttpsProxyAgent } from "https-proxy-agent";
import { HttpProxyAgent } from "http-proxy-agent";
const proxy = "http://USER:[email protected]:8080";
const r = await got("https://api.ipify.org", {
agent: {
http: new HttpProxyAgent(proxy),
https: new HttpsProxyAgent(proxy),
},
timeout: { request: 20_000 },
});
console.log(r.statusCode, r.body);
Sticky sessions
Append the session token to the username inside the proxy URL. The whole URL embeds in the agent at construction time.
javascript
import { ProxyAgent } from "undici";
import { randomBytes } from "node:crypto";
const session = randomBytes(8).toString("hex");
const proxy = `http://USER-session-${session}:[email protected]:8080`;
const dispatcher = new ProxyAgent(proxy);
// All three calls exit through the same IP for the session lifetime.
await fetch("https://target.com/login", { method: "POST", dispatcher });
await fetch("https://target.com/dashboard", { dispatcher });
await fetch("https://target.com/checkout", { dispatcher });
Common pitfalls
- Wrong protocol in the proxy URL — even for HTTPS targets the proxy URL stays
http://. The CONNECT method handles the tunnel. - Forgetting
proxy: falsein axios when supplying an agent — axios will try to do both and produce weird hangs or 502s. - Missing
httpAgentorhttpsAgent— set both, even if you only call HTTPS targets. Some libraries fall through tohttpAgentfor the initial connection. - Per-request agent re-creation — keep a single agent for the lifetime of the worker. Re-creating it per request defeats keep-alive and tanks throughput.
For deeper trouble, the error reference walks through every status code we emit.