JavaScript · setup guide

Node.js proxy setup

Node's built-in fetch does not read proxy environment variables by default, so you pass it a dispatcher. For axios the rule is shorter: turn its own proxy option off and give it an agent.
You will need

Residentialresi.proxymonkey.io:8000

ISP or datacenterIP:PORT

CredentialsUSER:PASS

Copy your own from the dashboard, which also lists the host and port for every order. Where it differs from this page, the dashboard is right.

Install

Node.js 18 or newer. The second package pair is only for axios.

terminal
npm i undici
npm i axios https-proxy-agent

Rotating residential

An agent pools connections, and a pooled HTTPS tunnel keeps its exit IP. For a new residential address per request, give each request its own agent and close it afterwards.

rotate.mjs
import { fetch, ProxyAgent } from "undici";

for (let i = 0; i < 3; i++) {
  const dispatcher = new ProxyAgent("http://USER:[email protected]:8000");
  const res = await fetch("https://httpbin.org/ip", { dispatcher });
  console.log((await res.json()).origin);
  await dispatcher.close();
}

A static datacenter or ISP IP

On a static datacenter IP, share one agent so connections are reused. This is the axios version. For an ISP order, use the host and port from your dashboard.

static.mjs
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";

const agent = new HttpsProxyAgent("http://USER:PASS@IP:PORT");

const { data } = await axios.get("https://httpbin.org/ip", {
  httpsAgent: agent,
  proxy: false,
  timeout: 30000,
});
console.log(data.origin);

Keeping one identity

Reusing one agent keeps traffic on a few tunnels, which on the rotating gateway means a few addresses. That is a cheap way to hold an address for a short burst. For an address that holds across new connections, residential supports sticky sessions; the session setting for your account is in the dashboard.

Specific to Node.js

Things worth knowing

Print err.cause

fetch wraps every network failure in TypeError: fetch failed. The useful part, a 407 or a timeout, is on err.cause. Log it.

debug.mjs
try {
  await fetch(url, { dispatcher });
} catch (err) {
  console.error(err.cause ?? err);
}

Cap concurrency yourself

Promise.all over ten thousand URLs opens ten thousand requests at once. Process them in batches, or keep a small pool of workers pulling from a shared queue.

Time out every request

Pass signal: AbortSignal.timeout(30000) to fetch. Without it, a stalled residential exit holds a slot in your pool for minutes.

When it breaks

Common errors and fixes

  • Proxy response (407) !== 200 when HTTP Tunneling on err.cause

    Why
    The gateway rejected the credentials.
    Fix
    Check them against the dashboard and percent-encode special characters with encodeURIComponent.
  • axios returns 400s or EPROTO errors on HTTPS URLs

    Why
    axios's own proxy option does not tunnel HTTPS the way a proxy expects.
    Fix
    Set proxy: false and pass an HttpsProxyAgent as httpsAgent.
  • UND_ERR_CONNECT_TIMEOUT or UND_ERR_HEADERS_TIMEOUT

    Why
    A slow exit or a target holding the connection open.
    Fix
    Set an AbortSignal.timeout and retry. On residential the retry leaves from a different IP.
  • UNABLE_TO_VERIFY_LEAF_SIGNATURE or SELF_SIGNED_CERT_IN_CHAIN

    Why
    The target's certificate chain, or a corporate CA your machine trusts and Node does not.
    Fix
    Add the CA with NODE_EXTRA_CA_CERTS. Never set NODE_TLS_REJECT_UNAUTHORIZED=0 outside a throwaway test.

A failed connection that moved no data is not billed. Retries you send are billed like any other request, and each shows as its own line in your usage log.

The community layer

Node.js still misbehaving?

Paste the error and the few lines that set up the proxy into Discord, with the password taken out. Someone there has seen it before.

Join the Discord

4,200+monkeys in the Discord

  • Help from humans

    Post your error, get an answer. Usually in minutes, usually from someone who has hit the same wall.

  • A status bot that tells on us

    Pool health, incidents and maintenance posted automatically. Including the bad days.

  • Deals and free traffic

    Bonus GB drops, early access to new pools, and the occasional giveaway for a good bug report.

Join the Discord4,200+ monkeys, free to lurk