Node.js treats both as agents
In Node.js you attach proxies through agents (undici ProxyAgent, https-proxy-agent, socks-proxy-agent). Webshare and Geonode are identical from Node's point of view; only the URL changes. Provider guides: Webshare with Node.js and Geonode with Node.js.
A proxy factory
Keep provider logic in one module:
import { ProxyAgent } from "undici";
const providers = {
webshareDC: () => nextFromList(WEBSHARE_LIST), // direct list entries
webshareRes: (s) => `http://${WS_USER}-${s ?? "rotate"}:${WS_PASS}@p.webshare.io:80`,
geonodeRes: (s) => geonodeUrl({ session: s }), // build from Geonode's documented format
};
const cache = new Map();
export function agentFor(name, session) {
const url = providers[name](session);
if (!cache.has(url)) cache.set(url, new ProxyAgent(url));
return cache.get(url);
}Callers ask for agentFor("geonodeRes", sid) and never see URLs. Switching a domain between providers is a config change.
axios and got
Both providers work with https-proxy-agent for axios and got:
import { HttpsProxyAgent } from "https-proxy-agent";
const httpsAgent = new HttpsProxyAgent(url);
await axios.get(target, { httpsAgent, proxy: false });Sessions and rotation
| Need | Webshare | Geonode |
|---|---|---|
| New IP per request | Rotate suffix, or rotate list entries | Rotating gateway |
| Sticky flow | Session suffix | Session ID with lifetime up to 24 hours |
| Fixed IP | Datacenter or static residential entry | ISP proxy |
Remember that undici and other agents keep connections alive; reusing a connection to a gateway can keep the same exit IP. Create new agents (or disable keep-alive) when you need a fresh IP per request.
Concurrency
Use p-limit or a queue to cap concurrency. Keep Webshare traffic under your plan's thread limit, and ramp up residential gateway concurrency on either provider while watching error rates.
Proxy tip: If you need managed scraping rather than raw proxies, Geonode also sells a Scraper API with a free monthly allowance, which Webshare doesn't offer. More in using Geonode with Node.js.
Choosing per job
| Node.js job | Better fit |
|---|---|
| API polling and lenient scraping | Webshare datacenter list |
| Protected sites | Geonode residential, test Webshare |
| Long-lived integrations needing a fixed IP | Either provider's static IPs |
| Server-side rendering of hard pages | Geonode Scraper API |
Verdict
Node.js doesn't favour either provider. Build a small factory, test both, and route by job.
Failover between providers
async function fetchWithFailover(url, opts = {}) {
for (const name of ["webshareDC", "geonodeRes"]) {
try {
const res = await fetch(url, { dispatcher: agentFor(name, opts.session), signal: AbortSignal.timeout(30000) });
if (res.ok) return res;
} catch {}
}
throw new Error(`all providers failed for ${url}`);
}Try the cheaper provider first and fall back to the more robust one. Log which provider served each request so you can tune the order per domain.
Per-domain preferences
Keep a small map of domain to preferred provider, learned from success rates. Start with defaults (datacenter first), and promote domains to residential when failures persist.
Budget tip: Many teams end up using both: Webshare for cheap per-IP datacenter and static residential lists, Geonode for per-GB residential traffic that doesn't expire. Start with using Webshare with Node.js.
Serverless considerations
In serverless functions, reuse agents across invocations where the runtime allows, set short timeouts, and remember that outbound IPs change, so prefer credentials over IP allowlisting for both providers.
A real-world example
A Node.js API that enriches company records fetches public websites on demand. It tries a Webshare datacenter agent first with a 10-second timeout and falls back to a Geonode residential agent on block or timeout. Logs show 85% of requests succeed on the first try, so residential traffic stays modest. Agents are cached per provider and session, and closed after an idle period to avoid socket leaks.
Before you commit to any provider, it helps to see the wider market: our guide to the best proxies in 2026 compares proxy types by job, and cheap proxies explains how to keep costs down without buying IPs that get blocked.
Key takeaways
- Node.js uses agents for both providers: undici,
https-proxy-agentorsocks-proxy-agent. - A proxy factory hides provider differences from the rest of your code.
- Try the cheaper route first and fail over to the more robust one.
- Keep-alive can pin a gateway exit IP; create new agents for fresh IPs.
- Cache and close agents to avoid socket leaks.
FAQ
Does Node's built-in fetch work with both providers?
Yes, through undici's ProxyAgent passed as the dispatcher option.
How do I use SOCKS5 with either in Node.js?
Use socks-proxy-agent with a socks5h:// URL.
Why is my IP the same on every request?
Keep-alive is reusing the gateway connection, or you're using a session. Use new agents or rotating mode.
Which agent library works with both providers?
undici's ProxyAgent for fetch, and https-proxy-agent for axios and got.
Can I use both in a serverless function?
Yes, with credentials from environment variables and short timeouts.
How do I measure each provider's performance in Node.js?
Log provider, status, latency and bytes per request, and aggregate daily.
Editorial note: Proxy providers change their pools, features and prices often, so treat any figures here as typical ranges at the time of writing and confirm current terms with the provider before you buy.