Lifecycle
Start, exit, fail, and initialize an Actor, with exit codes and local runs.
Every Actor initializes the SDK, does its work, and shuts down so storage writes and charges are flushed before the process ends. Actor.main() handles all three steps; the manual methods give you control over each one.
Lifecycle
Actor.main()
Actor.main(userFunc, options?) calls Actor.init(options), awaits your callback, shuts down events, storage, and charging, flushes standard output, and calls process.exit().
import { Actor } from 'scrapely';
await Actor.main(async () => {
const input = await Actor.getInputOrThrow<{ url: string }>();
await Actor.pushData({ url: input.url, ok: true });
});| Outcome | What happens | Exit code |
|---|---|---|
| Callback resolves | Shutdown (waits up to timeoutSecs, default 30) | options.exitCode, default 0 |
| Callback throws | Logs [Scrapely] Actor failed: <message> (plus the error's cause), then shuts down | options.exitCode, default 1 |
options accepts every InitOptions field plus timeoutSecs and exitCode. main() always exits the process, even if you pass exit: false. The first argument must be a function, otherwise main() throws before initializing.
The platform marks the run SUCCEEDED on exit code 0 and FAILED on any other code, unless the run was aborted or timed out. Because exitCode applies to both outcomes, setting exitCode: 0 also makes a failed callback exit with 0.
Manual lifecycle
Use init() and exit() when your code must control when the process ends:
await Actor.init();
try {
const input = await Actor.getInputOrThrow<Record<string, unknown>>();
await Actor.pushData({ received: input });
await Actor.exit('Completed');
} catch (error) {
await Actor.fail(error instanceof Error ? error.message : String(error));
}These methods throw Actor.<name>() requires Actor.init() to be called first. Hint: Use Actor.main() which calls init() for you. when called before init(): getInput, getInputOrThrow, pushData, getValue, setValue, openDataset, openKeyValueStore, openRequestQueue, useState, setStatusMessage, charge, reboot, exit, and fail.
Actor.exit() and Actor.fail()
Actor.exit(messageOrOptions?: string | ExitOptions, options?: ExitOptions): Promise<void>
Actor.fail(messageOrOptions?: string | ExitOptions, options?: ExitOptions): Promise<void>ExitOptions field | Type | Default | Meaning |
|---|---|---|---|
statusMessage | string | — | Printed to the log as [Scrapely] <message> |
timeoutSecs | number | 30 | How long shutdown may wait for flushes |
exitCode | number | 0 for exit(), 1 for fail() | Process exit code |
exit | boolean | true | Whether to call process.exit() after shutdown |
await Actor.exit('Finished');
await Actor.exit({ statusMessage: 'Finished', exit: false });
await Actor.fail('Validation failed');
await Actor.fail({ statusMessage: 'Upstream down', exitCode: 2 });fail() logs [Scrapely] Actor failed: <message> and calls exit() with exitCode defaulting to 1.
Exit codes
EXIT_CODES is exported for code that sets exit codes explicitly. main() and fail() don't use it; they use 0 and 1.
| Constant | Value |
|---|---|
EXIT_CODES.SUCCESS | 0 |
EXIT_CODES.ERROR_USER_FUNCTION_THREW | 91 |
EXIT_CODES.ERROR_UNKNOWN | 92 |
Initialization
interface InitOptions {
configuration?: ConfigurationOptions;
storage?: ApiStorageConfig | StorageClient;
gracefulShutdown?: boolean;
gracefulShutdownDelayMillis?: number;
}| Option | Default | Behavior |
|---|---|---|
configuration | — | Overrides SDK and Crawlee configuration values (see Configuration) |
storage | from environment | API credentials { apiUrl, token, runId }, or any Crawlee StorageClient |
gracefulShutdown | true | On aborting, calls Actor.exit(); on migrating, calls Actor.reboot() |
gracefulShutdownDelayMillis | 0 | Delay before that automatic exit() or reboot() |
Calling init() again after it succeeded does nothing. If init() fails, it undoes the partial setup, so you can retry.
What init() does
- Installs handlers for
uncaughtExceptionandunhandledRejection. On either, the SDK logs the error, flushes pending charges for up to 5 seconds, and exits with code1(a hard exit after 10 seconds at most). - Picks storage:
- the
storageoption, if you passed one; - otherwise, API-backed storage from
SCRAPELY_API_URL,SCRAPELY_TOKEN, andACTOR_RUN_ID; - otherwise, Crawlee local storage (see Local runs).
- the
- Connects the platform events WebSocket when the events URL, token, and run ID are all set.
- Starts the event manager, and registers the graceful shutdown handlers unless
gracefulShutdownisfalse. - Loads pricing and starts the charging manager.
- Handles
SIGINTandSIGTERM: flushes storage and charges for up to 5 seconds, then exits with code0.
On the platform (SCRAPELY_IS_AT_HOME=1), missing credentials are an error:
Missing required configuration for secure storage. Required: apiBaseUrl (SCRAPELY_API_URL), token (SCRAPELY_TOKEN/APIFY_TOKEN), actorRunId (ACTOR_RUN_ID). Containers must be started by the scrapely-server, or pass storage in Actor.init().Explicit storage credentials
On a platform run you don't need this. Pass storage only to point the SDK at a specific run's storage:
await Actor.init({
storage: {
apiUrl: process.env.SCRAPELY_API_URL!,
token: process.env.SCRAPELY_TOKEN!,
runId: process.env.ACTOR_RUN_ID!,
},
});Any other value that isn't API credentials or a StorageClient throws Actor.init() storage option must be ApiStorageConfig or StorageClient.
Local runs
Without platform credentials and outside the platform, init() logs [Scrapely] Local run detected — using Crawlee local storage and keeps working:
| Feature | Local behavior |
|---|---|
| Storage | Crawlee storage in ./storage |
| Input | ACTOR_INPUT, or the INPUT record of the local default key-value store |
| Events | No platform events; Crawlee still emits persistState on its interval |
| Browsers | Launched on your machine, even if the Actor uses the Scrape.ly browser on the platform |
| Proxy | No platform proxy unless you set SCRAPELY_PROXY_*; your own proxyUrls work |
| Charging | Every event is priced at 1; nothing is billed |
addWebhook() | Logs a warning and returns undefined |
scrapely run sets this up for you. It purges the default local storages (keeping INPUT.json) unless you pass --no-purge, passes -i/-f input as ACTOR_INPUT, and starts npm start or main. See CLI: Actor runtime.
Platform-only calls such as metamorph(), reboot(), and setStatusMessage() need run credentials; see each method for its local behavior.