# Node fetch / axios

For plain HTTP calls in Node (without a headless browser), two stacks dominate.

## Modern: `undici` (built-in fetch)

Node 18+ ships `fetch` from `undici`. For HTTP-CONNECT proxies you need `undici`'s `ProxyAgent`:

```bash
npm i undici
```

```js
import { fetch, ProxyAgent } from "undici";

const agent = new ProxyAgent(
  "http://helo_s1a2b3c4d5e-type-res-region-us:PASSWORD@gate.helodata.io:7777"
);

const res = await fetch("https://ipv4.icanhazip.com", { dispatcher: agent });
console.log((await res.text()).trim());
console.log("Exit IP:", res.headers.get("x-helodata-exit-ip"));
```

For ISP, swap the URL to `http://helo_s1a2b3c4d5e:PASSWORD@198.51.100.42:8000`.

## SOCKS5 with undici

```bash
npm i socks-proxy-agent
```

```js
import { SocksProxyAgent } from "socks-proxy-agent";
import { fetch } from "undici";

const agent = new SocksProxyAgent(
  "socks5://helo_s1a2b3c4d5e-type-res-region-us:PASSWORD@gate.helodata.io:7777"
);
const res = await fetch("https://ipv4.icanhazip.com", { dispatcher: agent });
```

## axios

```bash
npm i axios https-proxy-agent
```

```js
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";

const agent = new HttpsProxyAgent(
  "http://helo_s1a2b3c4d5e-type-res-region-us:PASSWORD@gate.helodata.io:7777"
);

const res = await axios.get("https://ipv4.icanhazip.com", {
  httpAgent: agent,
  httpsAgent: agent,
  proxy: false,                            // disable axios's own proxy resolution
});
console.log(res.data.trim());
```

> Set `proxy: false` on the axios call — otherwise axios will second-guess your agent using its own `env`-based proxy logic.

## ISP rotation

```js
import fs from "node:fs";
import { fetch, ProxyAgent } from "undici";

const lines = fs.readFileSync("isp.txt", "utf8").trim().split("\n");
let i = 0;

async function fetchOne(url) {
  const [ip, port, user, pass] = lines[i++ % lines.length].split(":");
  const agent = new ProxyAgent(`http://${user}:${pass}@${ip}:${port}`);
  return fetch(url, { dispatcher: agent });
}
```

## Sticky sessions (residential)

```js
import crypto from "node:crypto";

function sessionUrl(country = "us") {
  const sid = crypto.randomBytes(4).toString("hex");
  const user = `helo_s1a2b3c4d5e-type-res-region-${country}-session-${sid}-sesstime-10`;
  return `http://${user}:PASSWORD@gate.helodata.io:7777`;
}
```

## Verify

```js
const ip = (await (await fetch("https://ipv4.icanhazip.com", { dispatcher: agent })).text()).trim();
console.log(ip);
```

## Common pitfalls

* **`HTTP_PROXY` envvar mode in `undici`** — pre-1.x undici didn't honor env vars. Use `ProxyAgent` explicitly.
* **axios + `proxy: { host, port }`** — that syntax does **not** use HTTP-CONNECT, it tries a request-rewrite that breaks HTTPS. Always use an `httpAgent`/`httpsAgent`.
* **Connection reuse** — `undici.Agent` (the default dispatcher) pools connections; if you mint a new `ProxyAgent` per request you lose the pool. For ISP, share one agent per IP.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.helodata.com/integrations/scraping-tools/node-fetch.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
