# Use JavaScript

> Use Undici for HTTP proxies or SOCKS5 with destination DNS at the proxy.
>
> Web page: https://ports.io/docs/guides/javascript/
> Documentation index: https://ports.io/llms.txt

Use an HTTP client with explicit proxy support for server-side JavaScript. This example uses Undici's `ProxyAgent` for HTTP proxies and `Socks5ProxyAgent` for SOCKS5. You need your assigned proxy URL supplied as `PORTS_PROXY_URL` and the full `rp1_...` key supplied as `PORTS_PROXY_KEY`.

## Install the client

This example uses Undici 8.11.2, which requires Node.js 22.19.0 or later. Its SOCKS5 agent is marked experimental. Check the [Undici installation and compatibility table](https://github.com/nodejs/undici#install) when selecting a version for another runtime.

```sh
npm install undici@8.11.2
```

## Make a request

Save this example as `proxy-request.mjs`. Set `PORTS_PROXY_URL` to your assigned `http://`, `https://`, or `socks5h://` proxy URL, including its hostname and port, without embedded credentials. Supply the secret through `PORTS_PROXY_KEY`. The destination URL must contain a hostname.

```javascript
import { fetch, ProxyAgent, Socks5ProxyAgent } from "undici";

const endpoint = process.env.PORTS_PROXY_URL;
const password = process.env.PORTS_PROXY_KEY;
if (!endpoint || !password) {
  throw new Error("Set PORTS_PROXY_URL and PORTS_PROXY_KEY");
}

const username = "v1_rotate";
const uri = new URL(endpoint);
let proxy;
if (uri.protocol === "socks5h:") {
  if (!uri.port) {
    throw new Error("Include the assigned SOCKS proxy port in PORTS_PROXY_URL");
  }
  // This agent sends hostnames to the proxy but accepts socks5: URLs.
  uri.protocol = "socks5:";
  proxy = new Socks5ProxyAgent(uri, {
    username,
    password,
    connectTimeout: 10_000,
  });
} else if (uri.protocol === "http:" || uri.protocol === "https:") {
  const credentials = Buffer.from(`${username}:${password}`).toString("base64");
  proxy = new ProxyAgent({
    uri,
    token: `Basic ${credentials}`,
  });
} else {
  throw new Error("PORTS_PROXY_URL must use http://, https://, or socks5h://");
}

try {
  const response = await fetch("https://example.com/", {
    dispatcher: proxy,
    signal: AbortSignal.timeout(30_000),
  });
  const body = await response.text();
  if (!response.ok) {
    throw new Error(`Destination returned HTTP ${response.status}`);
  }
  console.log(response.status);
  console.log(body);
} finally {
  await proxy.close();
}
```

The agent is passed as the request's dispatcher. The HTTP branch attaches Basic credentials and uses HTTP CONNECT for the HTTPS destination. The SOCKS5 branch sends the routing username and full key in the SOCKS authentication handshake, then requests a tunnel to the destination hostname. Consume the response body and close the agent when it is no longer needed. [Undici ProxyAgent documentation](https://github.com/nodejs/undici/blob/v8.11.2/docs/docs/api/ProxyAgent.md).

## SOCKS5 and remote DNS

Undici's `Socks5ProxyAgent` always sends destination hostnames to the proxy for resolution, but accepts `socks5:` or `socks:` URLs rather than `socks5h:`. The example adapts the configured `socks5h:` scheme for that agent while preserving the hostname, port, and remote-DNS behavior. It rejects plain `socks5://` in the shared application configuration so that the same value remains safe to use with curl or Requests.

Keep the assigned SOCKS port: a standard SOCKS connection does not establish TLS to the proxy. SOCKS5 over TLS requires the assigned TLS endpoint and explicit `proxyTls` options; the example's SOCKS branch uses plaintext TCP to the proxy. TLS verification remains enabled for the HTTPS destination. [Undici Socks5ProxyAgent documentation](https://github.com/nodejs/undici/blob/v8.11.2/docs/docs/api/Socks5ProxyAgent.md).

`AbortSignal.timeout(30_000)` requests cancellation after 30 seconds. Adjust this client setting to your application's needs. [Node.js AbortSignal documentation](https://nodejs.org/api/globals.html#static-method-abortsignaltimeoutdelay).

Keep proxy authentication in the agent configuration. Do not put the proxy secret into a destination `Authorization` header or log the proxy URL or credentials; Base64 encoding in the HTTP branch is reversible.

## Select the route

Change the username before constructing the agent:

```javascript
const username = "v1_rotate_countries_US";
// Or: "v1_sticky_session_job-42_countries_US"
// Or: "v1_fixed_session_job-42_countries_US"
```

See [routing](https://ports.io/docs/reference/username-reference.md) and [sessions](https://ports.io/docs/reference/sessions.md) for the meaning of these policies.

## Understand connection reuse

An HTTP or SOCKS5 agent can reuse its connection to a destination. The proxy selects an exit when a new tunnel opens. Reusing one tunnel with `v1_rotate` does not rotate the exit for every application request. [Undici connection behavior](https://github.com/nodejs/undici/blob/v8.11.2/docs/docs/api/ProxyAgent.md).

Browser JavaScript does not accept an Undici dispatcher. Keep the proxy secret in your application's server-side configuration.
