<p align="center">
  <a href="https://proxyscrape.com?utm_source=github&utm_medium=repo&utm_campaign=proxyscrape-sdk&utm_content=logo">
    <img src="https://cdn.proxyscrape.com/img/logo/dark_text_logo.svg" alt="ProxyScrape" height="72">
  </a>
</p>

# proxyscrape

> Official ProxyScrape JavaScript / TypeScript SDK. Free proxy list, one-call proxy fetch, and public-IP lookup — one fully-typed client.

<p align="center" id="star-cta-top">
  <b>⭐ If this saves you time, hit the <kbd>★ Star</kbd> button in the top-right — it helps other developers find this repo. ⭐</b>
</p>

[![npm version](https://img.shields.io/npm/v/@proxyscrape_org/sdk.svg)](https://www.npmjs.com/package/@proxyscrape_org/sdk)
[![Downloads](https://img.shields.io/npm/dm/@proxyscrape_org/sdk.svg)](https://www.npmjs.com/package/@proxyscrape_org/sdk)
[![Bundle size](https://img.shields.io/bundlephobia/minzip/@proxyscrape_org/sdk)](https://bundlephobia.com/package/@proxyscrape_org/sdk)
[![Node](https://img.shields.io/node/v/@proxyscrape_org/sdk.svg)](https://www.npmjs.com/package/@proxyscrape_org/sdk)
[![CI](https://github.com/ProxyScrape/proxyscrape-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/ProxyScrape/proxyscrape-sdk/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![Types: TypeScript](https://img.shields.io/badge/types-typescript-blue)](https://www.typescriptlang.org/)
[![ProxyScrape](https://img.shields.io/badge/by-ProxyScrape-1f6feb)](https://proxyscrape.com?utm_source=github&utm_medium=repo&utm_campaign=proxyscrape-sdk&utm_content=brand-badge)

<p align="center">
  <a href="https://proxyscrape.com?utm_source=github&utm_medium=repo&utm_campaign=proxyscrape-sdk&utm_content=trinity-site">Site</a> ·
  <a href="https://www.npmjs.com/package/@proxyscrape_org/sdk">NPM</a> ·
  <a href="https://github.com/ProxyScrape/proxyscrape-sdk">GitHub</a> ·
  <a href="https://docs.proxyscrape.com?utm_source=github&utm_medium=repo&utm_campaign=proxyscrape-sdk&utm_content=trinity-docs">API Docs</a>
</p>

## Install

```bash
npm install @proxyscrape_org/sdk
# or
pnpm add @proxyscrape_org/sdk
# or
yarn add @proxyscrape_org/sdk
```

### Or drop it in a browser without a build step

```html
<script src="https://cdn.jsdelivr.net/npm/@proxyscrape_org/sdk@latest/dist/proxyscrape.min.js"></script>
<script>
  // The IIFE bundle exposes a namespace at `window.ProxyScrape`.
  // Construct the client via `.ProxyScrape`; error classes live alongside it.
  const ps = new ProxyScrape.ProxyScrape();
  ps.proxy({ country: 'us' }).then((p) => console.log(p?.url));

  try { /* ... */ } catch (e) {
    if (e instanceof ProxyScrape.NetworkError) console.warn('Network down');
  }
</script>
```

The minified bundle is ~10 KB and runs identically in modern browsers, Bun, Deno, and any environment with `fetch`.

Node 18+ (uses native `fetch`). Works in Bun, Deno, and modern browsers. Ships ESM + CJS + a minified IIFE bundle, all with types.

## Quick start

```ts
import { ProxyScrape } from '@proxyscrape_org/sdk';

const ps = new ProxyScrape();

// One-liner: give me a working US elite proxy
const p = await ps.proxy({ country: 'us', anonymity: 'elite' });
if (p) console.log(p.url); // → "socks5://1.2.3.4:1080"

// Or a full page with filters + pagination metadata
const { proxies, totalRecords } = await ps.free.list({
  protocol: 'socks5',
  country: 'us',
  anonymity: 'elite',
  minUptimePercent: 70,
  limit: 100,
});

console.log(`${totalRecords} matches; first 3:`);
for (const proxy of proxies.slice(0, 3)) {
  console.log(`${proxy.url}  ${proxy.country}/${proxy.city}  uptime=${proxy.uptimePercent}%`);
}
```

## Verify a proxy actually works

```ts
const before = await ps.getPublicIp();
console.log('Real IP:', before.ip);

const proxy = await ps.proxy({ anonymity: 'elite' });
// ... route a request through proxy.url using your HTTP client of choice ...
// then re-call getPublicIp via that route. If the IP didn't change,
// the proxy is transparent or broken.
```

`getPublicIp()` defaults to [ipinfo.io](https://ipinfo.io)'s free tier (no key needed up to 50k req/month). For production volume, pass an `ipinfoToken` or override the endpoint entirely.

## Stream every match (no manual pagination)

```ts
for await (const p of ps.free.stream({ protocol: 'http', country: 'de' })) {
  console.log(p.url);
  // stop whenever you want — the iterator stops fetching pages on `break`
}
```

## Random pick (for one-off use)

```ts
const p = await ps.free.random({ anonymity: 'elite', country: 'jp' });
if (p) {
  // p.url, p.ip, p.port, p.countryCode, p.anonymity, p.uptimePercent, ...
}
```

## Text / CSV export (no JSON round-trip)

```ts
const txt = await ps.free.listText({ protocol: 'socks5' });
// "socks5://1.2.3.4:1080\nsocks5://5.6.7.8:1080\n..."

const csv = await ps.free.listCsv({ protocol: 'http' });
// "protocol,ip,port,country,...\nhttp,1.2.3.4,8080,US,...\n"
```

## Module surface

The SDK is intentionally namespaced so every ProxyScrape product gets one entry point on the client.

| Surface | What's there |
|---|---|
| `ps.proxy(filters?)` | one-call shortcut for `ps.free.random()` |
| `ps.getPublicIp(opts?)` | IP + geo via ipinfo (default) or ipify |
| `ps.free` | `list`, `stream`, `random`, `listText`, `listCsv` |

More ProxyScrape products will land on the same client over upcoming versions — the namespaced shape means they slot in without breaking the existing API.

## Configuration

```ts
const ps = new ProxyScrape({
  baseUrl: 'https://api.proxyscrape.com/v4', // override for staging / mocks
  timeoutMs: 15_000,                         // per-request, default 30s
  maxRetries: 3,                             // 5xx / 429 / network. Default 3
  userAgent: 'my-app/1.0',                   // appended after our SDK UA
  fetch: customFetch,                        // bring your own (undici, mocks…)
});
```

## Errors

Every error inherits from `ProxyScrapeError`. Discriminate by subclass:

```ts
import { ProxyScrape, RateLimitError, NetworkError } from '@proxyscrape_org/sdk';

try {
  await ps.free.list({ country: 'us' });
} catch (err) {
  if (err instanceof RateLimitError) {
    console.warn(`Backed off too aggressively, retry in ${err.retryAfterSeconds}s`);
  } else if (err instanceof NetworkError) {
    console.error('Network down', err.message);
  } else {
    throw err;
  }
}
```

## Cancellation

Pass any `AbortSignal` to abort mid-flight:

```ts
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 5_000);

const { proxies } = await ps.free.list({ country: 'us' }, { signal: ctrl.signal });
```

## Why one client class

Grouping calls under a namespace like `ps.free.list()` keeps things tidy, and lets tree-shakers drop the modules you don't use (import the module class directly: `import { FreeProxyListClient } from '@proxyscrape_org/sdk'`).

## Privacy &amp; what we transmit

Every API call from this SDK contains exactly what you put in it — no version pings, no client IDs, no `_referrer` query params, no anonymous telemetry. Open your network tab and verify.

`getPublicIp()` reaches out to a third-party (ipinfo.io by default, ipify if you ask for it) — that request goes from your machine directly to the chosen provider. If you'd rather avoid the third-party entirely, point `endpoint` at your own IP-echo service.

## Development

```bash
git clone https://github.com/ProxyScrape/proxyscrape-sdk.git
cd proxyscrape-sdk
npm install

npm run typecheck   # tsc --noEmit
npm run lint        # biome check
npm run test        # vitest run
npm run build       # tsup -> dist/{index.js,index.cjs,index.d.ts}
npm run ci          # all of the above, in order
```

Integration tests that hit the real API are gated by `SDK_RUN_INTEGRATION=1` so default `npm test` stays hermetic.

## Releases

Managed by [changesets](https://github.com/changesets/changesets). Every PR touching `src/` should ship a changeset:

```bash
npm run changeset           # interactive prompt; creates .changeset/<id>.md
git add .changeset
```

The `Release` workflow opens a "Version Packages" PR collecting pending changesets. Merging that PR publishes to npm with provenance.

## License

MIT — see [LICENSE](LICENSE).

## Links

- 🌐 Website: [proxyscrape.com](https://proxyscrape.com?utm_source=github&utm_medium=repo&utm_campaign=proxyscrape-sdk&utm_content=website)
- 📦 npm: [@proxyscrape_org/sdk](https://www.npmjs.com/package/@proxyscrape_org/sdk)
- 📖 API docs: [docs.proxyscrape.com](https://docs.proxyscrape.com?utm_source=github&utm_medium=repo&utm_campaign=proxyscrape-sdk&utm_content=api-docs)
- 🛠 Other free tools (free list mirror, proxy checker, extension): [proxyscrape.com/free-proxy-list](https://proxyscrape.com/free-proxy-list?utm_source=github&utm_medium=repo&utm_campaign=proxyscrape-sdk&utm_content=other-tools)
- 💬 Discord: [discord.gg/scrape](https://discord.gg/scrape)
