Skip to main content

Actor Programming Interface

An Apify Actor's programming interface is the contract every Actor honors: it reads a single JSON input (the INPUT record in the default key-value store), processes it inside a Docker container, and writes results to three run-scoped storages. The lifecycle is Input → Processing → Output → Exit, and each stage maps to exact SDK calls.

The whole interface reduces to a handful of elements you read or write through the SDK:

Interface elementWhat it isHow you access it
InputOne JSON object, shape declared by an input schemaActor.getInput() / Actor.get_input()
DatasetAppend-only table of JSON output recordsActor.pushData(record)
Key-value storeNamed blobs: INPUT, OUTPUT, screenshots, checkpointsActor.setValue(key, body) / Actor.getValue(key)
Request queueURL frontier for crawlsActor.openRequestQueue()
Environment variablesRun context (ACTOR_*) plus credentials (APIFY_*)process.env (read for you by the SDK)
Run statusOutcome derived from how the process exitsActor.exit() / Actor.fail()

For a wider view of how these pieces fit the platform, see the Actor programming model overview and the Apify storage guide. To put it into practice, follow build your first Actor. Actors can also serve responses over HTTP through Standby mode.

1. Input

An Actor receives a single JSON object at startup. Two things describe it:

  • Runtime input: the JSON object your code reads with Actor.getInput() (JS) or Actor.get_input() (Python). It's stored as INPUT in the run's default key-value store.
  • Input schema: a JSON Schema definition the Console uses to render a form, validate types, apply defaults, and mark secret fields (stored encrypted, decrypted only at run time). Set it via the input field in .actor/actor.json, either inline or as a path to a JSON file. A standalone .actor/INPUT_SCHEMA.json still works but is the deprecated form.
import { Actor } from 'apify';

await Actor.init();
const input = (await Actor.getInput()) ?? {};
const { startUrls = [], maxPages = 100, apiToken } = input; // apiToken may be a secret field

Fields marked "isSecret": true in the schema (available on textfield, textarea, hidden, and json editors) are encrypted at rest and in the Console UI; they arrive decrypted in getInput().

2. Processing

Your code runs inside a Docker container that Apify boots with a set of environment variables. The current programming interface exposes run context under the ACTOR_* prefix, while credentials and proxy settings keep the older APIFY_* prefix. The SDK reads these for you, so you rarely touch them directly, but knowing the names helps when you debug or shell into a container:

VariableWhat it holds
ACTOR_RUN_IDID of the current run
ACTOR_DEFAULT_DATASET_IDID of the run's default dataset
ACTOR_DEFAULT_KEY_VALUE_STORE_IDID of the run's default key-value store
ACTOR_DEFAULT_REQUEST_QUEUE_IDID of the run's default request queue
ACTOR_INPUT_KEYKey in the default key-value store that holds the input (defaults to INPUT)
ACTOR_MEMORY_MBYTESMemory limit allocated to the run
APIFY_TOKENAPI token scoped to the run, used for API and Actor.call
APIFY_PROXY_PASSWORDPassword for Apify Proxy

Between Actor.init() and Actor.exit() you also have access to:

  • Crawlee crawlers and ProxyConfiguration for request handling and rotation.
  • Platform events via Actor.on(eventName, handler):
    • migrating: the worker is about to move your run; persist state immediately.
    • aborting: a user aborted the run with "graceful abort"; flush work.
    • persistState: periodic (by default every 60 s) signal to save useState / session pool state.
    • systemInfo: memory and CPU telemetry for self-throttling.
  • Outgoing calls: Actor.call(actorId, input), Actor.callTask(taskId, input), Actor.start(actorId, input) to orchestrate other Actors, and Actor.addWebhook({ eventTypes, requestUrl, payloadTemplate }) to register run-scoped webhooks.
Actor.on('migrating', async () => {
await Actor.setValue('CHECKPOINT', { processedAt: Date.now() });
});

The Python SDK exposes the same surface (Actor.on, Actor.call, Actor.add_webhook) inside an async with Actor: block.

3. Output

An Actor has three storages, all scoped to the run by default and addressable by name for cross-run sharing.

StorageTypical contentPrimary SDK calls
DatasetAppend-only JSON records (one row per item)Actor.pushData(record) / Actor.open_dataset()
Key-value storeNamed blobs: INPUT, OUTPUT, HTML snapshots, screenshots, checkpointsActor.setValue(key, body, { contentType }), Actor.getValue(key)
Request queueFrontier of URLs + metadata for a crawlActor.openRequestQueue(), then addRequests / handled implicitly by Crawlee

pushData accepts a single object or an array; it enforces JSON-serializability and attaches the record to the dataset named in ACTOR_DEFAULT_DATASET_ID. setValue accepts strings, Buffers, or JSON. Pass contentType for anything other than JSON.

4. Exit and run status

Run status is derived from how the process ends:

  • Actor.exit([message]): graceful termination, status SUCCEEDED, optional status message shown in Console and webhook payloads.
  • Actor.fail([message]): terminates with status FAILED and the message stored on the run.
  • Uncaught exception or non-zero exit: status FAILED.
  • Platform-initiated abort (user, timeout, memory): status ABORTED or TIMED-OUT; may be preceded by an aborting event for graceful cleanup.

Always prefer Actor.exit / Actor.fail over raw process.exit: they flush buffered dataset writes, persist final state, and attach the status message that external webhooks consume.

try {
await run();
await Actor.exit('Scrape complete: 1,204 items.');
} catch (err) {
await Actor.fail(`Unrecoverable error: ${err.message}`);
}
Apify Affiliate Banner 728x90Apify Affiliate Banner 728x90Apify Affiliate Banner 300x50Apify Affiliate Banner 300x50
Frequently Asked Questions

Input is a single JSON object stored as the `INPUT` key in the run's default key-value store; its shape is declared in `.actor/INPUT_SCHEMA.json` (JSON Schema). Output uses three storages: datasets for append-only JSON records (`Actor.pushData`), key-value stores for named blobs like screenshots or checkpoints (`Actor.setValue`), and request queues for crawl frontiers (`Actor.openRequestQueue`).

Wrap your main logic in try/catch and call `Actor.fail(message)` on unrecoverable errors. This sets the run status to FAILED with a message surfaced in Console and webhooks. Uncaught exceptions also produce FAILED but without a custom message. Listen for the `aborting` and `migrating` events via `Actor.on(...)` to flush state before the platform stops the container.

Datasets (ordered JSON records, `Actor.pushData`), key-value stores (named blobs addressed by key, `Actor.setValue` / `Actor.getValue`), and request queues (URL frontiers for crawlers, `Actor.openRequestQueue`). Each run gets default instances of all three, and you can open named storages by passing a name to `Actor.openDataset(name)` / `Actor.openKeyValueStore(name)` to share data across runs.

Run context is exposed under the `ACTOR_*` prefix: `ACTOR_RUN_ID`, `ACTOR_DEFAULT_DATASET_ID`, `ACTOR_DEFAULT_KEY_VALUE_STORE_ID`, `ACTOR_DEFAULT_REQUEST_QUEUE_ID`, `ACTOR_INPUT_KEY` (the key holding the input, default `INPUT`), and `ACTOR_MEMORY_MBYTES`. Credentials keep the older `APIFY_*` prefix, such as `APIFY_TOKEN` and `APIFY_PROXY_PASSWORD`. The SDK reads these automatically, so most code uses `Actor.getInput()` and `Actor.pushData()` instead of touching them directly.

Set the `input` field in `.actor/actor.json`, either as an inline JSON Schema object or a path to a JSON file. A standalone `.actor/INPUT_SCHEMA.json` file still works but is the deprecated form. The schema renders the Console input form, validates types, applies defaults, and marks secret fields with `"isSecret": true` so they are encrypted at rest and decrypted only inside the run.

Input → Processing → Output → Exit. Between `Actor.init()` and `Actor.exit()`, the SDK emits events you can subscribe to with `Actor.on`: `migrating` (persist state before the run moves), `aborting` (graceful shutdown requested), `persistState` (periodic save signal, default every 60 seconds), and `systemInfo` (CPU/memory telemetry). Exit status comes from `Actor.exit()` / `Actor.fail()` or the process exit code.

Apify Affiliate Banner 728x90Apify Affiliate Banner 728x90Apify Affiliate Banner 300x50Apify Affiliate Banner 300x50