> ## Documentation Index
> Fetch the complete documentation index at: https://docs.surfsky.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Proxies

> Choose a Surfsky proxy pool or your own connection, target a location, and route or block domains.

Every Surfsky browser needs an outbound connection. By default it uses a Surfsky proxy pool: premium when the account has it, shared otherwise. The premium pool has over 100 million residential and mobile IPs, with targeting by country, region, city, ASN, or coordinates.

You can also supply an HTTP, HTTPS, SOCKS5, SSH, Shadowsocks, OpenVPN, or WireGuard connection. See [using your own proxies](#using-your-own-proxies).

## Quick start

This starts a one-time browser using your account's default available pool:

```bash theme={null}
curl -X POST "$SURFSKY_API_BASE_URL/profiles/one_time" \
  -H "X-Cloud-Api-Token: $SURFSKY_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

Set your [credentials](/quickstart#credentials) first. If no pool is available, supply a proxy URL:

```json theme={null}
{"proxy": "socks5://user:pass@proxy.example.com:1080"}
```

Use the returned `internal_uuid` to [stop the session](/sessions#stop-a-session) when the job finishes.

<span id="default-behavior" />

<span id="proxy-options-comparison" />

## Choosing the tier

| Selection           | Behavior                                                                                                          |
| ------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `"tier": "shared"`  | Use shared proxies if enabled for the account. Only country targeting is supported. Recommended for testing only. |
| `"tier": "premium"` | Use premium proxies if enabled and configured. Supports the targeting and session options below.                  |
| Omit `tier`         | Prefer premium when it is enabled and usable; otherwise select shared if available.                               |
| Supply a proxy URL  | Use that connection instead of selecting a Surfsky pool.                                                          |

An explicitly requested tier is not replaced with the other tier. Specify `tier` when the choice matters to your workload.

```json theme={null}
{"proxy": {"tier": "shared", "country": "us"}}
```

```json theme={null}
{"proxy": {"tier": "premium", "country": "us", "region": "texas"}}
```

Omitting `proxy` on a persistent profile's start keeps its stored proxy. An explicit start override applies to that run; it does not update the saved profile. See [changing a profile's proxy](/sessions#change-the-proxy).

`timezone`, `languages`, and `geolocation` follow the exit IP unless the profile pins them. See [fields that follow the IP](/fingerprints#matching-the-proxy).

<span id="country-targeting" />

<span id="shared-proxies-default" />

## Shared proxies

Shared proxies support an optional two-letter `country`. Use [List shared countries](/api-reference/proxies/list-shared-countries) to see current availability.

If the requested country has no healthy shared proxy, the API returns `shared_pool_country_unavailable`. Select another country or omit country targeting if any location is acceptable.

Do not send `region`, `city`, `asn`, `pool`, `type`, coordinates, or session options with `tier: "shared"`; those combinations are rejected.

Shared IPs are also used by other sessions, so the shared tier is recommended for testing only. Run production on premium or your own proxy. Check the account's allowance through [shared quota](/api-reference/proxies/get-shared-quota) and usage through [shared traffic stats](/api-reference/proxies/get-shared-traffic-stats).

<span id="performance-metrics" />

<span id="pricing" />

<span id="proxy-features" />

<span id="residential-ips" />

<span id="setup-process" />

<span id="using-surfsky-proxies" />

## Surfsky proxies

Use `tier: "premium"` to request premium targeting. Access depends on your account configuration; check the dashboard or [contact support](mailto:hello@surfsky.io) if it is unavailable.

<Warning>
  Set a location that fits your job. A request without targeting draws peers worldwide, so the exit
  IP can sit far from the target site and add latency to every page load.
</Warning>

<span id="available-locations" />

<span id="how-it-works" />

### Location targeting

Choose one location mode:

| Mode                 | Fields                             | Rules                                                                                      |
| -------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------ |
| Country and locality | `country`, `region`, `city`, `asn` | `region` requires `country`; `city` requires `region`; `asn` requires `country`.           |
| Geographic pool      | `pool`                             | A region such as `europe`; cannot be combined with country, locality, ASN, or coordinates. |
| Coordinates          | `lat`, `lon`                       | Supply both. Cannot be combined with the other location modes.                             |

`pool` selects a geographic region, not a pricing tier. Use `tier` for `shared` or `premium`.

```json theme={null}
{"proxy": {"tier": "premium", "country": "us", "region": "texas", "city": "dallas"}}
```

```json theme={null}
{"proxy": {"tier": "premium", "pool": "europe"}}
```

```json theme={null}
{"proxy": {"tier": "premium", "lat": 48.8584, "lon": 2.2945}}
```

Use the lookup endpoints instead of guessing provider-specific names:

| Lookup           | Endpoint                                                                               |
| ---------------- | -------------------------------------------------------------------------------------- |
| Countries        | [GET /proxies/countries](/api-reference/proxies/list-premium-countries)                |
| Regions          | [GET /proxies/regions/\{country}](/api-reference/proxies/list-premium-regions)         |
| Cities           | [GET /proxies/cities/\{country}/\{region}](/api-reference/proxies/list-premium-cities) |
| ASNs             | [GET /proxies/asns/\{country}](/api-reference/proxies/list-premium-asns)               |
| Geographic pools | [GET /proxies/pools](/api-reference/proxies/list-proxy-pools)                          |

Set `type` to `residential` or `mobile` when your job needs a particular connection type. Requests without `type` use residential. More restrictive targeting can reduce the number of available peers.

<span id="monitor-usage" />

<span id="rotation-control" />

### Session control

| Field             | Meaning                                                               |
| ----------------- | --------------------------------------------------------------------- |
| `session_minutes` | Requested sticky session duration, in minutes.                        |
| `unique_ip`       | Request an IP that is not assigned to another of your proxy sessions. |
| `keep_asn`        | Request that replacement peers remain on the same ASN.                |
| `keep_ip`         | Fail instead of changing to another IP when the current peer is lost. |

A sticky duration cannot keep an offline peer connected. Use `keep_ip` when changing IP is less acceptable than failing the job.

```json theme={null}
{
  "proxy": {
    "tier": "premium",
    "country": "us",
    "session_minutes": 60,
    "keep_ip": true
  }
}
```

Check [premium quota](/api-reference/proxies/get-premium-quota) and [traffic stats](/api-reference/proxies/get-premium-traffic-stats) for your account. Current pricing and allowances are shown in the dashboard.

<span id="shadowsocks-methods" />

<span id="supported-formats" />

<span id="using-your-own-proxy" />

## Using your own proxies

Send a proxy URL in `proxy`, or a VPN configuration in its own field:

| Connection  | Request field | Format                                           |
| ----------- | ------------- | ------------------------------------------------ |
| HTTP        | `proxy`       | `http://username:password@host:port`             |
| HTTPS       | `proxy`       | `https://username:password@host:port`            |
| SOCKS5      | `proxy`       | `socks5://username:password@host:port`           |
| SSH         | `proxy`       | `ssh://username:password@host:port`              |
| Shadowsocks | `proxy`       | `ss://method:password@host:port`                 |
| OpenVPN     | `open_vpn`    | [Configuration object](#openvpn-configuration)   |
| WireGuard   | `wireguard`   | [Configuration object](#wireguard-configuration) |

URL-encode reserved characters in credentials, or omit credentials if the proxy does not require them. Shadowsocks takes your provider's encryption method in place of the username. SSH requires a password; key files are not supported.

Surfsky treats an `https://` URL as an HTTP proxy. Browser traffic is tunneled through it, but the connection to the proxy itself is not TLS-wrapped.

<Info>
  UDP is carried end to end on a SOCKS5 proxy that supports UDP ASSOCIATE, and on OpenVPN and
  WireGuard. HTTP/3 and QUIC, WebRTC, and UDP DNS all travel inside the tunnel. Surfsky probes the
  proxy at start and uses what it supports.
</Info>

**DNS and UDP.** By default the proxy resolves domain names, so DNS does not leave the tunnel. HTTP, HTTPS, SSH, Shadowsocks, and SOCKS5 proxies without UDP support carry TCP only. The browser's UDP traffic is rejected on these connections, and QUIC and HTTP/3 fall back to TCP. A custom `fingerprint.dns` resolver is queried outside the tunnel on such a connection, so pair one with a UDP-capable SOCKS5 proxy.

### OpenVPN configuration

Use `open_vpn` with the complete configuration file contents as a JSON string. Add `username` and `password` when your VPN requires them:

```json theme={null}
{
  "open_vpn": {
    "config": "CONTENTS_OF_YOUR_OVPN_FILE",
    "username": "vpn_user",
    "password": "vpn_password"
  }
}
```

The placeholder must be replaced with a real configuration, including any required certificates.

<span id="generating-wireguard-keys" />

<span id="peer-parameters" />

<span id="wireguard-parameters" />

### WireGuard configuration

```json theme={null}
{
  "wireguard": {
    "private_key": "BASE64_PRIVATE_KEY",
    "address": ["10.0.0.2/32"],
    "peers": [{
      "public_key": "BASE64_PEER_PUBLIC_KEY",
      "endpoint": "vpn.example.com:51820",
      "allowed_ips": ["0.0.0.0/0", "::/0"]
    }]
  }
}
```

Supply keys and addresses from your WireGuard configuration. Optional fields include interface `mtu` and peer `pre_shared_key` and `persistent_keepalive_interval`. See the [start request schema](/api-reference/profiles/start-one-time-session) for their types and defaults.

Use only one of `proxy`, `open_vpn`, or `wireguard` in a request.

<span id="parameters" />

<span id="pattern-format" />

## Proxy blacklist

Block unneeded ad, analytics, or tracking domains to reduce downloads. Requests to blocked domains do not reach the proxy or consume metered proxy traffic.

Block domains with `proxy_blacklist` in the start request:

```json theme={null}
{
  "proxy_blacklist": ["*.doubleclick.net", "analytics.google.com", "*.facebook.net"]
}
```

Use `*` for a wildcard. Include the root domain separately if your rule also needs to block it. Start with domains you know are unnecessary and compare the page before and after blocking. Blocking a login provider, challenge script, or API host can prevent the page from working.

An entry that parses as an IP address or CIDR range is not blocked. Those addresses are excluded from the tunnel and connect directly from the container, outside your proxy. Use domain patterns to block. The list applies to proxy and WireGuard sessions; an OpenVPN session ignores it.

For resource types such as images or fonts, use [SDK resource blocking](/speed-optimization#block-unneeded-resources).

<span id="domain-matching-rules" />

<span id="example-route-google-through-different-proxy" />

<span id="parameters-2" />

## Domain routing

Domain routing can reduce residential or mobile proxy costs by sending static assets through a cheaper datacenter proxy. Keep the target site on the main connection and test that asset hosts accept the alternate proxy. You can also use routing when a particular host needs a different exit location.

Send selected domains through a different proxy while the rest use the browser's main connection:

```json theme={null}
{
  "proxy": "socks5://user:pass@default-proxy.example.com:1080",
  "domain_routes": [{
    "proxy": "http://user:pass@regional-proxy.example.com:8080",
    "domain": ["example.com"],
    "domain_suffix": [".example.com"]
  }]
}
```

Each rule requires `proxy` and at least one matching condition:

| Field            | Matches                                             |
| ---------------- | --------------------------------------------------- |
| `domain`         | An exact domain.                                    |
| `domain_suffix`  | A domain suffix; `.example.com` selects subdomains. |
| `domain_keyword` | A substring in the domain.                          |
| `domain_regex`   | A regular expression matched against the domain.    |

Rules are evaluated in order; the first matching rule supplies the route. Unmatched traffic uses the main connection. Keep rules narrow so an unrelated service does not receive an unintended IP or location. Domain routes apply to `proxy` sessions; a session started with `open_vpn` or `wireguard` ignores them.

## Proxy errors

| Code                                                             | What to check                                                  |
| ---------------------------------------------------------------- | -------------------------------------------------------------- |
| `proxy_required` or `proxy_pool_unavailable`                     | Supply your own connection or enable a pool.                   |
| `premium_pool_unavailable` / `shared_pool_unavailable`           | The explicitly selected tier must be available to the account. |
| `shared_pool_country_unavailable`                                | Check the current shared country list.                         |
| `premium_traffic_limit_reached` / `shared_traffic_limit_reached` | Read the corresponding quota endpoint.                         |
| `bad_proxy`                                                      | Check the proxy URL, credentials, and provider availability.   |
| `validation_error`                                               | Inspect `data` for incompatible or missing targeting fields.   |

See [errors](/errors) for retry guidance. If the browser starts but the site rejects the connection, use [troubleshooting](/troubleshooting#the-site-is-blocking-you) to compare one variable at a time.
