Skip to content
Build Actors

Proxy

Managed residential and datacenter proxies, your own proxies, and how browsers fit in.

Every run can use a managed proxy with residential and datacenter IPs. There's no account or password to set up: each run gets its own credentials, and you pay per GB. You can also bring your own proxy URLs, or mix them with the managed proxy.

const proxyConfiguration = await Actor.createProxyConfiguration({ countryCode: 'US' });

How the managed proxy works

When a run starts, the platform injects these environment variables into the container:

VariableValue
SCRAPELY_PROXY_HOSTNAMEProxy host reachable from inside the run
SCRAPELY_PROXY_PORTProxy port (HTTP and SOCKS5 on the same port)
SCRAPELY_PROXY_USERNAMEscrapely
SCRAPELY_PROXY_PASSWORDThe run ID
SCRAPELY_PROXY_STATUS_URLStatus endpoint used by the SDK access check

The same values are also set as APIFY_PROXY_* so existing proxy code works unchanged.

The password only works from inside the run that owns it, so Actors never get a reusable proxy credential and there's no account-level password to leak. You can't use the managed proxy outside a run. The SDKs read these variables for you.

Groups and countries

You pick a pool with groups and a location with countryCode:

GroupPoolPrice
RESIDENTIAL (default)Residential IPs$2–$4 per GB
DATACENTERDatacenter IPs$0.75–$1 per GB
  • These two are the only groups. No group means the residential pool.
  • The legacy datacenter group names SHADER and BUYPROXIES94952 are accepted and use the datacenter pool.
  • Any other group, including groups Scrape.ly doesn't offer, such as GOOGLE_SERP, is refused. It is never routed through another pool or billed. See Unsupported groups.
  • countryCode takes an ISO 3166-1 alpha-2 code such as US or DE. The SDKs also accept subdivisionCode (needs countryCode), but the proxy targets the country only.
  • Traffic is billed per GB as run usage and counts toward the run's maxTotalChargeUsd. If you can't cover it, the run is aborted.
  • Traffic to your own proxies is never billed as proxy usage.

Unsupported groups

If you ask for a group that doesn't exist, the SDK's access check fails when you create the proxy configuration, and the proxy refuses every request that names it. The message is the same everywhere:

.text
Proxy group "GOOGLE_SERP" is not available on Scrapely. Available groups: RESIDENTIAL, DATACENTER.
WhereWhat you see
Python SDKActor.create_proxy_configuration() raises ConnectionError with the message
JavaScript SDKOn the platform, Actor.createProxyConfiguration() throws an Error with the message. In local runs it logs the message as a warning
HTTP proxy, CONNECT or plain request407 Proxy Authentication Required, with the message in the X-Scrapely-Proxy-Error header and the response body
SOCKS5Authentication fails

This also applies to groups that come from an input field (scrapelyProxyGroups), and to a known group combined with an unknown one (groups: ['RESIDENTIAL', 'GOOGLE_SERP']). Several unknown groups are named together: Proxy groups "GOOGLE_SERP", "UNBLOCKER" are not available on Scrapely. ....

To fall back to a pool that exists, catch the error and create the configuration again with RESIDENTIAL or DATACENTER. Actors built with an older SDK only log a warning at start; their requests then get the 407 above.

Use it from code

On the platform, Actor.createProxyConfiguration() / Actor.create_proxy_configuration() with no options gives you the residential pool:

import { Actor, CheerioCrawler } from 'scrapely';

await Actor.main(async () => {
    const proxyConfiguration = await Actor.createProxyConfiguration({
        groups: ['DATACENTER'],
        countryCode: 'US',
    });

    const crawler = new CheerioCrawler({
        proxyConfiguration,
        requestHandler: async ({ request, $ }) => {
            await Actor.pushData({ url: request.url, title: $('title').text() });
        },
    });

    await crawler.run(['https://example.com']);
});

To use your own proxies, pass proxyUrls / proxy_urls:

const proxyConfiguration = await Actor.createProxyConfiguration({
    proxyUrls: [
        'http://user:password@proxy.example:8000',
        'http://user:password@proxy-2.example:8000',
    ],
});

const proxyUrl = await proxyConfiguration.newUrl();

Rules the SDKs enforce:

  • proxyUrls can't be combined with groups or countryCode; the SDK throws.
  • 'auto' in proxyUrls (or tieredProxyUrls) reserves a slot for the managed proxy next to your own URLs.
  • newUrl(sessionId) keeps related requests on one IP. Session IDs are at most 50 characters from a-z, A-Z, 0-9, ., _, and ~.
  • checkAccess (default true) runs a quick status check at start. If the proxy refuses the configuration, for example an unsupported group, the SDK throws. If the check can't reach the proxy, it logs a warning and the run continues.
  • Outside the platform, with no proxyUrls, the SDK warns and returns undefined.
SDKOptionsGuide
JavaScriptAlso accepts the input-field keys useScrapelyProxy, scrapelyProxyGroups, scrapelyProxyCountry, and scrapelyProxySubdivision, and their Apify aliasesProxy & events
Pythongroups, country_code, subdivision_code, proxy_urls, new_url_function, tiered_proxy_urls, tiered_proxy_config, password, check_access, actor_proxy_inputEnvironment & proxy

Let users choose in the input

Add a field with the proxy editor to your input schema:

.json
{
    "proxyConfiguration": {
        "title": "Proxy configuration",
        "type": "object",
        "editor": "proxy",
        "description": "Use the scrape.ly proxy or your own proxy URLs",
        "default": { "useScrapelyProxy": true }
    }
}

In the dashboard, this field renders a Use Scrapely Proxy (recommended) switch. When the switch is off, users can enter a list of custom proxy URLs. The value looks like {"useScrapelyProxy": true} or {"useScrapelyProxy": false, "proxyUrls": ["http://..."]}, and it can also carry scrapelyProxyGroups, scrapelyProxyCountry, and scrapelyProxySubdivision.

useScrapelyProxy decides whether the run uses Scrape.ly Proxy:

  • true: requests go through Scrape.ly Proxy, with the groups and country from the same object.
  • false with proxyUrls: requests go through your own proxy URLs.
  • false without proxyUrls: no proxy. Actor.createProxyConfiguration() returns undefined (None in Python).

To pick the pool or the exit country, add them to the same object, for example as the field's default:

.json
{ "useScrapelyProxy": true, "scrapelyProxyGroups": ["DATACENTER"], "scrapelyProxyCountry": "US" }
KeyMeaning
scrapelyProxyGroups["RESIDENTIAL"] (default pool) or ["DATACENTER"]. Other groups are refused
scrapelyProxyCountryTwo-letter ISO country code, e.g. "US"
scrapelyProxySubdivisionISO 3166-2 subdivision, requires scrapelyProxyCountry. The proxy currently routes by country only

Without scrapelyProxyGroups, the run uses the residential pool.

Apify names

Every key also has an Apify alias, so inputs, tasks and actors written for Apify keep working:

Scrape.ly nameApify alias
useScrapelyProxyuseApifyProxy
scrapelyProxyGroupsapifyProxyGroups
scrapelyProxyCountryapifyProxyCountry
scrapelyProxySubdivisionapifyProxySubdivision

Callers and input schemas can use either name. The run receives each proxy object under both names with the same values, whichever naming the caller used. So actor code can read input.proxyConfiguration.useScrapelyProxy or useApifyProxy, and both reflect the user's choice. When an object sets both names, the Scrape.ly name wins. The stored input, the run's Input tab and the API return the input exactly as it was sent.

One exception: an actor that installs the upstream apify JavaScript package itself (no Scrape.ly SDK swap) receives only the Apify names. Versions of that package up to 3.7.0 reject unknown proxy keys.

Pass the value straight to the SDK:

const input = await Actor.getInput();
const proxyConfiguration = await Actor.createProxyConfiguration(input?.proxyConfiguration);

Browser crawlers

How browser traffic is proxied depends on the Actor's Use Scrapely browser setting:

SettingWhere browsers runProxy for browser trafficBilled as
Off (default)In the run containerThe proxyConfiguration you pass to the crawler, as for HTTP crawlersProxy GB
OnOn the Scrape.ly browserThe Scrape.ly browser's own residential proxy. Your proxy URLs are ignored, with a warningBrowser credits

With the setting on, pick the browser's exit location with a browser configuration rather than a proxy:

const browserConfiguration = await Actor.createBrowserConfiguration({ countryCode: 'DE' });
const crawler = new PlaywrightCrawler({ browserConfiguration, requestHandler });

Without one, the browser uses the country of a platform ProxyConfiguration on the crawler, then the run default (US). All options, including state, city, os, and Cloudflare solving: Choose the location and fingerprint.

What's next