ScreenshotNeo

BlogHow-to

How to Use a Proxy with node-fetch

Configure HTTP or HTTPS proxies in node-fetch with an explicit agent, environment-safe credentials, troubleshooting steps, and modern Node alternatives.

By the ScreenshotNeo team1 October 20266 min read

To send a node-fetch request through a proxy, create a proxy-capable Node.js agent and pass it through the request’s agent option. Setting HTTP_PROXY or HTTPS_PROXY alone does not configure node-fetch.

The common implementation uses https-proxy-agent:

const fetch = require('node-fetch');
const { HttpsProxyAgent } = require('https-proxy-agent');

const proxyUrl = process.env.HTTPS_PROXY;
if (!proxyUrl) throw new Error('Set HTTPS_PROXY first');

const agent = new HttpsProxyAgent(proxyUrl);

(async () => {
  const response = await fetch('https://example.com', { agent });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  console.log(await response.text());
})();

Install compatible package versions first, and check the installed agent package documentation because constructor names and import forms can change:

npm install node-fetch https-proxy-agent

The node-fetch README documents agent as accepting an Agent instance or a function that returns an Agent. See the node-fetch options documentation and the https-proxy-agent documentation for the versions in your project.

How the node-fetch proxy option works

node-fetch delegates socket creation to Node’s HTTP agents. The agent option is therefore the integration point:

Setting What it controls
agent An Agent instance, or a function that selects one for a URL
HTTP_PROXY/HTTPS_PROXY Environment values that your own code may read; node-fetch does not automatically read them
NO_PROXY Only effective if the agent or runtime implements bypass matching

Use an HTTPS-capable agent when the destination is HTTPS. For mixed redirect chains, provide an agent function so the destination protocol can determine which agent to use.

Complete CommonJS example with proxy authentication

Keep credentials in deployment secrets rather than source control. A proxy URL can contain encoded credentials, for example http://user:password@proxy.example:8080; URL-encode reserved characters in usernames and passwords.

const fetch = require('node-fetch');
const { HttpsProxyAgent } = require('https-proxy-agent');

function required(name) {
  const value = process.env[name];
  if (!value) throw new Error(`Missing ${name}`);
  return value;
}

const target = process.argv[2] || 'https://example.com';
const proxy = required('HTTPS_PROXY');
const agent = new HttpsProxyAgent(proxy);

(async () => {
  try {
    const response = await fetch(target, {
      agent,
      headers: { 'user-agent': 'proxy-check/1.0' },
      timeout: 30000
    });

    console.log('status:', response.status);
    console.log('via proxy body:', (await response.text()).slice(0, 500));
  } catch (error) {
    console.error('request failed:', error.message);
    process.exitCode = 1;
  }
})();

Run it with:

HTTPS_PROXY='http://proxy.example:8080' node request.js https://example.com

ES modules and protocol-aware agents

For an ESM project, use the package’s ESM exports supported by your installed versions:

import fetch from 'node-fetch';
import { HttpsProxyAgent } from 'https-proxy-agent';

const proxy = process.env.HTTPS_PROXY;
if (!proxy) throw new Error('Set HTTPS_PROXY');

const agent = new HttpsProxyAgent(proxy);
const response = await fetch('https://example.com', { agent });
console.log(await response.text());

If requests may redirect between HTTP and HTTPS, select an agent from the request URL. The exact HTTP-agent class depends on the proxy and destination protocols supported by your chosen package:

import fetch from 'node-fetch';
import { HttpProxyAgent } from 'http-proxy-agent';
import { HttpsProxyAgent } from 'https-proxy-agent';

const httpAgent = new HttpProxyAgent(process.env.HTTP_PROXY);
const httpsAgent = new HttpsProxyAgent(process.env.HTTPS_PROXY);

const agent = ({ protocol }) => protocol === 'http:' ? httpAgent : httpsAgent;
const response = await fetch('https://example.com', { agent });
console.log(response.status);

Confirm the constructors and supported URL forms against the versions installed in your lockfile before copying this pattern.

Why HTTP_PROXY is ignored by node-fetch

node-fetch does not automatically begin using HTTP_PROXY or HTTPS_PROXY when those variables exist. Read the variable yourself, construct an agent, and pass { agent }. A wrapper may add environment support, but check its maintenance and compatibility before adopting it.

Recent Node.js releases also document runtime-level proxy support through NODE_USE_ENV_PROXY=1, --use-env-proxy, and custom proxyEnv settings. This is a Node HTTP-agent capability and is version-dependent; it is not the node-fetch configuration API. See the Node.js HTTP documentation.

node-fetch, native fetch, and Undici: different proxy APIs

Client Proxy configuration Key distinction
node-fetch agent Pass an Agent instance or selector function per request
Native Node fetch Node runtime and Undici behavior Follow the Node version’s documented environment-proxy support
Undici directly ProxyAgent through dispatcher Do not pass an Undici dispatcher as node-fetch’s agent

Undici’s official ProxyAgent documentation describes the dispatcher interface. Native fetch, Undici fetch, and node-fetch are related but their proxy options are not interchangeable.

cURL and Python equivalents

These examples are useful for isolating whether a failure is in the proxy itself or in your Node configuration.

curl --proxy "$HTTPS_PROXY" https://example.com
import os
import requests

proxy = os.environ["HTTPS_PROXY"]
proxies = {"http": proxy, "https": proxy}
r = requests.get("https://example.com", proxies=proxies, timeout=30)
r.raise_for_status()
print(r.text[:500])

Configuration checklist

  1. Confirm the proxy URL includes a scheme such as http:// or https://.
  2. Verify the proxy host, port, username, and password independently.
  3. Use an agent that supports both the proxy protocol and destination protocol.
  4. Pass the agent on every request that should use the proxy.
  5. Define intentional bypass rules for internal hosts; do not assume NO_PROXY is honored.
  6. Check redirects, because a redirect can change the destination protocol.
  7. Keep proxy credentials in environment configuration or a secret manager.

Troubleshooting common errors

Symptom Likely cause Fix
ECONNREFUSED Proxy host or port is unreachable Test the endpoint with cURL and verify network access and port values.
407 Proxy Authentication Required Missing or invalid proxy credentials Put correctly URL-encoded credentials in the proxy URL or use the agent’s documented authentication option.
Request goes directly to the internet agent was omitted, or only an environment variable was set Construct the agent in code and pass { agent }.
TLS or certificate errors Proxy interception certificate is not trusted, or protocol pairing is wrong Use the correct agent, install the organization’s CA as required, and avoid disabling certificate verification.
Works for HTTP but not HTTPS HTTP-only agent used for an HTTPS destination Use an HTTPS-capable agent and verify the proxy supports CONNECT tunneling.
Redirect fails One fixed agent does not suit both protocols Use node-fetch’s agent function and select by destination URL.
TypeError: ... is not a constructor Import syntax does not match installed package version Check the installed package’s README and adapt CommonJS or ESM imports.
Timeouts Proxy queueing, blocked destination, DNS, or overly short timeout Test the destination through the proxy, inspect proxy logs, and set a timeout appropriate for the operation.

Performance, reliability, and cost

A proxy adds a network hop and may add connection setup time. Reuse agents where the package supports keep-alive connections, set explicit timeouts, and avoid creating a new agent for every request. Measure latency from your deployment region through the selected proxy rather than assuming the proxy is faster.

For reliability, distinguish proxy failures from origin failures in logs. Record the target host, status code, elapsed time, and error class without logging credentials. Use retries only for transient connection failures and apply backoff; retrying non-idempotent requests can duplicate work.

There is no requirement to buy a proxy service. An organizational proxy may be sufficient. If you do choose a provider, verify its protocol support, authentication method, geographic coverage, acceptable-use rules, maintenance, and current pricing independently.

Or skip the browser setup

If your goal is a clean image or PDF of a web page rather than making an HTTP request through your own proxy, ScreenshotNeo provides a website screenshot API and MCP server. The API call is:

See the ScreenshotNeo API documentation for parameters and response details.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots each month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Can I use an HTTP proxy for an HTTPS URL?

Yes, when the proxy supports HTTPS tunneling and the selected agent implements that combination. Verify the agent and proxy documentation for your versions.

Should I use a proxy agent function?

Use a function when redirects or mixed HTTP and HTTPS destinations require protocol-specific agents. A single Agent instance is simpler for one known protocol.

Does node-fetch support SOCKS proxies with the same package?

No assumption should be made. Choose an agent package that explicitly supports the SOCKS protocol and confirm its node-fetch integration.

Is a paid proxy service required?

No. An existing company or self-hosted proxy can work. A commercial service is an optional source of proxy endpoints.