Environment
Injected variables, configuration, the Scrape.ly browser, and the API client.
A platform run describes itself through environment variables. This page lists what the platform injects, how the SDK exposes it, how to tune the SDK configuration, how browser crawlers reach the remote browser, and how to get an API client.
Environment and run metadata
Actor.getEnv()
getEnv() reads the environment and returns an object (TypeScript type ApifyEnv, a compatibility name). Missing values are null. It's available as Actor.getEnv() and on instances.
| Property | Source |
|---|---|
actorId | ACTOR_ID |
actorRunId | ACTOR_RUN_ID |
actorTaskId | ACTOR_TASK_ID |
actorFullName | ACTOR_FULL_NAME (owner/actor-name) |
actorBuildId, actorBuildNumber, actorBuildTags | ACTOR_BUILD_ID, ACTOR_BUILD_NUMBER, ACTOR_BUILD_TAGS (raw strings) |
actorEventsWsUrl | ACTOR_EVENTS_WS_URL, then ACTOR_EVENTS_WEBSOCKET_URL |
actorMaxPaidDatasetItems | ACTOR_MAX_PAID_DATASET_ITEMS as a number |
actorPermissionLevel | ACTOR_PERMISSION_LEVEL |
apiBaseUrl | APIFY_API_BASE_URL, then SCRAPELY_API_URL |
apiPublicBaseUrl | APIFY_API_PUBLIC_BASE_URL |
token | APIFY_TOKEN, then SCRAPELY_TOKEN |
isAtHome | APIFY_IS_AT_HOME, then SCRAPELY_IS_AT_HOME (string, '1' on the platform) |
userId | APIFY_USER_ID |
userIsPaying | APIFY_USER_IS_PAYING ('1' or '0') |
userPlan | SCRAPELY_USER_PLAN ('paid' or 'free') |
defaultDatasetId, defaultKeyValueStoreId, defaultRequestQueueId | ACTOR_DEFAULT_*_ID |
inputKey | ACTOR_INPUT_KEY |
containerPort, containerUrl | ACTOR_WEB_SERVER_PORT (number), ACTOR_WEB_SERVER_URL |
metaOrigin | APIFY_META_ORIGIN, then ACTOR_META_ORIGIN ('STANDBY' for standby runs) |
memoryMbytes | ACTOR_MEMORY_MBYTES as a number |
startedAt, timeoutAt | ACTOR_STARTED_AT, ACTOR_TIMEOUT_AT as Date |
maxTotalChargeUsd | ACTOR_MAX_TOTAL_CHARGE_USD as a number |
restartOnError | ACTOR_RESTART_ON_ERROR ('1' or '0') |
proxyHostname, proxyPort, proxyPassword, proxyStatusUrl | APIFY_PROXY_* |
headless, logLevel, logFormat, localStorageDir, chromeExecutablePath | APIFY_HEADLESS, APIFY_LOG_LEVEL, APIFY_LOG_FORMAT, CRAWLEE_STORAGE_DIR or APIFY_LOCAL_STORAGE_DIR, APIFY_CHROME_EXECUTABLE_PATH |
The object also has compatibility fields that Scrape.ly doesn't set (dedicatedCpus, fact, workflowKey, systemInfoIntervalMillis, disableOutdatedWarning, sdkLatestVersion, inputSecretsPrivateKeyFile, inputSecretsPrivateKeyPassphrase).
Variables the platform injects
These are set on every platform run container. Don't set them yourself.
Identity and storage
| Variable | Purpose |
|---|---|
ACTOR_ID / ACTOR_FULL_NAME | Current Actor ID and owner/actor-name |
ACTOR_RUN_ID | Current run ID |
ACTOR_TASK_ID | Task that started the run, if any |
ACTOR_BUILD_ID / ACTOR_BUILD_NUMBER / ACTOR_BUILD_TAGS | Build this run executes |
ACTOR_DEFAULT_DATASET_ID / ACTOR_DEFAULT_KEY_VALUE_STORE_ID / ACTOR_DEFAULT_REQUEST_QUEUE_ID | Default storages |
ACTOR_STORAGES_JSON | Storage aliases for this run |
ACTOR_INPUT | Run input as base64-encoded JSON (also stored in the INPUT record) |
ACTOR_INPUT_KEY | INPUT |
ACTOR_METAMORPH_COUNT | Number of metamorphs so far (after a metamorph) |
Authentication and API
| Variable | Purpose |
|---|---|
SCRAPELY_TOKEN (also APIFY_TOKEN) | Token scoped to this run |
SCRAPELY_API_URL (also APIFY_API_BASE_URL) | API URL the container uses (internal address) |
APIFY_API_PUBLIC_BASE_URL | Public API URL, for links you hand to others |
SCRAPELY_IS_AT_HOME (also APIFY_IS_AT_HOME) | 1 on a platform run |
ACTOR_PERMISSION_LEVEL | LIMITED_PERMISSIONS (default) or FULL_PERMISSIONS |
APIFY_USER_ID | User who started the run |
APIFY_USER_IS_PAYING / SCRAPELY_USER_PLAN | 1/paid or 0/free |
SCRAPELY_LLM_BASE_URL | LLM gateway base URL (OpenRouter-compatible, ends in /v2/llm/api/v1). Use SCRAPELY_TOKEN as the API key |
Runtime
| Variable | Purpose |
|---|---|
CDP_URL | Scrape.ly browser endpoint. Set on every run; used for launches only when the Actor's browser setting is on |
ACTOR_EVENTS_WEBSOCKET_URL | Platform events (persistState, migrating, aborting, systemInfo, cpuInfo) |
ACTOR_WEB_SERVER_PORT / ACTOR_WEB_SERVER_URL | Port your HTTP server listens on (4321) and the URL the platform proxies to it |
ACTOR_META_ORIGIN (also APIFY_META_ORIGIN) | STANDBY for standby runs |
ACTOR_STANDBY_URL / ACTOR_STANDBY_IDLE_TIMEOUT_SECS | Standby runs only |
ACTOR_STARTED_AT / ACTOR_TIMEOUT_AT | ISO timestamps |
ACTOR_MEMORY_MBYTES / CRAWLEE_MEMORY_MBYTES | Memory allocation |
ACTOR_RESTART_ON_ERROR | 1 if the run restarts once after failing |
APIFY_HEADLESS | 1 |
SCRAPELY_PROXY_* (also APIFY_PROXY_*) | Platform proxy credentials; see Proxy configuration |
SCRAPELY_BROWSER_PATCH | 0 when the build has Use Scrapely browser off (the default), so browsers launch in the container |
Pricing
| Variable | Purpose |
|---|---|
ACTOR_MAX_TOTAL_CHARGE_USD | Run spending cap |
ACTOR_MAX_PAID_DATASET_ITEMS | Result cap (maxItems) |
APIFY_ACTOR_PRICING_INFO (also ACTOR_PRICING_INFO) | Pricing as JSON |
APIFY_CHARGED_ACTOR_EVENT_COUNTS (also ACTOR_CHARGED_EVENT_COUNTS) | Events already charged in this run |
Environment variables defined in your Actor's version settings or environmentVariables in the Actor config are added too. Secret inputs are decrypted on the host before the container starts; the platform doesn't provide the APIFY_INPUT_SECRETS_PRIVATE_KEY_* variables.
Convenience properties
These are static getters on Actor:
| Getter | Type | Source |
|---|---|---|
Actor.fullName | string | undefined | ACTOR_FULL_NAME |
Actor.taskId | string | undefined | ACTOR_TASK_ID |
Actor.buildId | string | undefined | ACTOR_BUILD_ID |
Actor.buildNumber | string | undefined | ACTOR_BUILD_NUMBER |
Actor.buildTags | string[] | ACTOR_BUILD_TAGS, split on commas |
Actor.startedAt | string | undefined | ACTOR_STARTED_AT |
Actor.timeoutAt | string | undefined | ACTOR_TIMEOUT_AT |
Actor.token | string | undefined | Configured token |
Actor.userId | string | undefined | APIFY_USER_ID |
Actor.isPaying | boolean | APIFY_USER_IS_PAYING |
Actor.apiPublicBaseUrl | string | undefined | APIFY_API_PUBLIC_BASE_URL |
const msLeft = Actor.getRemainingTime();
if (msLeft !== undefined && msLeft < 30_000) {
await Actor.exit('Stopping before the timeout');
}
const custom = Actor.getenv('MY_SETTING');Actor.getRemainingTime() returns milliseconds until ACTOR_TIMEOUT_AT (never below 0), or undefined when there's no timeout. Actor.getenv(key) returns process.env[key]. Actor.isAtHome() is true on a platform run.
Web server and standby metadata
There are no dedicated getters for the web server. Read the values from the configuration:
const port = Actor.config.get('containerPort'); // ACTOR_WEB_SERVER_PORT, default 4321
const url = Actor.config.get('containerUrl'); // ACTOR_WEB_SERVER_URL
const standbyUrl = Actor.config.get('standbyUrl'); // ACTOR_STANDBY_URL
const isStandby = Actor.isStandby(); // metaOrigin === 'STANDBY'The SDK doesn't start an HTTP server; your code listens on containerPort. See Standby mode.
Configuration
Configuration extends Crawlee's configuration with Scrape.ly fields. Actor.init() builds it from the environment; most Actors never touch it.
import { Actor } from 'scrapely';
const token = Actor.config.get('token');
Actor.config.set('persistStateIntervalMillis', 30_000);To set values before the SDK reads them, pass configuration to Actor.init() or Actor.main() (a matching environment variable still takes precedence):
await Actor.main(async () => { /* ... */ }, {
configuration: { persistStateIntervalMillis: 30_000 },
});| Member | Purpose |
|---|---|
get(key, defaultValue?) | Read a value |
set(key, value) | Override a value at runtime |
getStorageClient() / useStorageClient(client) | Read or replace the storage client |
getEventManager() / useEventManager(events) | Read or replace the event manager |
Configuration.getGlobalConfig() | The process-wide instance |
Configuration.resetGlobalState() | Reset the process-wide instance |
Scrape.ly fields and their environment variables:
| Field | Environment | Default |
|---|---|---|
token | SCRAPELY_TOKEN, APIFY_TOKEN | — |
apiBaseUrl | SCRAPELY_API_URL, APIFY_API_BASE_URL | Non-production URL. Set to https://api.scrape.ly |
apiPublicBaseUrl | APIFY_API_PUBLIC_BASE_URL | Non-production URL. Set to https://api.scrape.ly |
isAtHome | SCRAPELY_IS_AT_HOME, APIFY_IS_AT_HOME | — |
actorId, actorRunId, actorTaskId | ACTOR_ID, ACTOR_RUN_ID, ACTOR_TASK_ID | — |
actorEventsWsUrl | ACTOR_EVENTS_WEBSOCKET_URL, APIFY_ACTOR_EVENTS_WS_URL | — |
containerPort, containerUrl | ACTOR_WEB_SERVER_PORT, ACTOR_WEB_SERVER_URL | 4321, http://localhost:4321 |
standbyUrl | ACTOR_STANDBY_URL | — |
standbyPort | ACTOR_STANDBY_PORT (deprecated; use containerPort) | 4321 |
metaOrigin | ACTOR_META_ORIGIN, APIFY_META_ORIGIN | — |
inputKey | ACTOR_INPUT_KEY | INPUT |
persistStateIntervalMillis | CRAWLEE_PERSIST_STATE_INTERVAL_MILLIS | 60000 |
maxTotalChargeUsd | ACTOR_MAX_TOTAL_CHARGE_USD | — |
testPayPerEvent, useChargingLogDataset | ACTOR_TEST_PAY_PER_EVENT, ACTOR_USE_CHARGING_LOG_DATASET | false |
actorStoragesJson | ACTOR_STORAGES_JSON | — |
actorPermissionLevel | ACTOR_PERMISSION_LEVEL | — |
userId, userIsPaying | APIFY_USER_ID, APIFY_USER_IS_PAYING | — |
An environment variable that is set wins over a value passed in configuration or set with set(); defaults apply last. When several variables map to one field, they carry the same value on the platform. Crawlers use the global configuration by default; pass Actor.config as the second constructor argument only if you created a separate Actor instance:
const crawler = new CheerioCrawler({ /* ... */ }, Actor.config);Browsers and remote CDP
Where a browser runs depends on the Actor's Use Scrapely browser setting, which is off by default and applied per build. See Scrape.ly Browser.
| Situation | What happens |
|---|---|
Setting off (SCRAPELY_BROWSER_PATCH=0) | Normal launch in the container, from the browsers in your image |
| Setting on, on the platform | Playwright calls chromium.connectOverCDP(CDP_URL); Puppeteer calls connect({ browserWSEndpoint }) |
| Setting on, Firefox, WebKit, or Camoufox launcher | Redirected to the Scrape.ly browser (Chromium) |
| Setting on, no CDP URL | Throws cdpUrl is required. Local browser launch is disabled — all runs must use the remote browser. |
| Local run, no CDP URL | Normal local launch |
Importing the SDK patches Crawlee's browser pool and the Playwright and Puppeteer launchers. The scrapely/actor-node* images also preload the patch through NODE_OPTIONS, so Actors that don't import the SDK are covered.
CDP_URL is set on every run, whatever the setting. setCdpUrl(url) overrides it and setCdpUrl(undefined) clears the override. Call it before the first browser launches, for example to point a local run at a CDP endpoint you host:
import { Actor, PlaywrightCrawler, setCdpUrl } from 'scrapely';
setCdpUrl('wss://browser.example.com/devtools?token=...');
const crawler = new PlaywrightCrawler({
async requestHandler({ page }) {
await Actor.pushData({ title: await page.title() });
},
});The Scrape.ly browser has its own exit IP and ignores your proxy URLs. Choose its location with createBrowserConfiguration().
Instance API and API client
Instance API
The class can be instantiated for code that expects an Actor object:
const actor = new Actor();
await actor.init();
const input = await actor.getInputOrThrow<{ url: string }>();
await actor.pushData({ url: input.url });
await actor.exit({ exit: false });new Actor(options?) takes ConfigurationOptions. Without options it uses the global configuration. The first instance created becomes the default instance that the static methods use; Actor.getDefaultInstance() returns it.
Instances have the lifecycle, input, storage, status, proxy, browser, state, reboot, metamorph, abort, webhook, call, charging, getEnv(), isAtHome(), and isStandby() methods, plus actor.config and actor.apifyClient. These are static only: the run metadata getters, Actor.events, Actor.input, Actor.getenv(), Actor.getRemainingTime(), and Actor.utils.
API client
Actor.apifyClient and Actor.newClient() return an ApifyClient from scrapely-client, the Scrape.ly JavaScript API client. The name is kept so existing code works; it's the same class as ScrapelyClient. See JavaScript client for its full API.
const client = Actor.newClient();
const actorInfo = await client.actor('owner~name').get();
const other = Actor.newClient({ token: process.env.OTHER_TOKEN });| Call | Client |
|---|---|
Actor.apifyClient / Actor.newClient() | Shared client with the run's token and SCRAPELY_API_URL |
Actor.newClient({ token, baseUrl }) | New client with that token and/or base URL |
The run's client uses the internal API URL for requests and APIFY_API_PUBLIC_BASE_URL for public links such as getRecordPublicUrl(). On pay-per-event Actors it also charges for writes to the default dataset (see Default dataset item event).
ApifyClient, ApifyClientOptions, and ActorRun are re-exported from the SDK root.