Skip to content
JavaScript SDK

Errors & deployment

Fix common SDK errors, then test and deploy your Actor.

This page lists common SDK errors and their fixes, and shows how to test an Actor locally and on the platform before you ship it.

Errors and troubleshooting

SymptomCauseFix
Actor.<name>() requires Actor.init() to be called firstA method that needs initialization ran before init()Wrap your code in Actor.main() or call Actor.init() first
Missing required configuration for secure storageSCRAPELY_IS_AT_HOME is set but the API URL, token, or run ID is missingDon't set SCRAPELY_IS_AT_HOME locally; on the platform the run injects all three
Input does not existgetInputOrThrow() found no inputPass input (-i / -f locally), or use getInput() and handle null
Cannot find package 'scrapely' or missing exports locallyThe SDK isn't in your local node_modules, or a lockfile pins the empty placeholder (scrapely 1.2.3 or older)Run npm install scrapely@latest; see Get the SDK
cdpUrl is required. Local browser launch is disabledUse Scrapely browser is on, but a browser launched without CDP_URLDon't unset CDP_URL; check setCdpUrl() calls
Custom proxies are ignored when using the Scrapely remote browserYour own proxy URLs were passed to a browser crawler while the Scrape.ly browser is onUse createBrowserConfiguration() for browser location; use your proxies with HTTP crawlers
Proxy configuration is undefinedNo proxy options and no platform proxy credentials (e.g. a local run)Pass proxyUrls, or set SCRAPELY_PROXY_* locally
Cannot combine custom proxies with Scrapely Proxy!proxyUrls combined with groups / countryCodeUse one mode, or put 'auto' in proxyUrls
Proxy group "GOOGLE_SERP" is not available on Scrapely. Available groups: RESIDENTIAL, DATACENTER.groups or scrapelyProxyGroups names a group Scrape.ly doesn't offerUse RESIDENTIAL or DATACENTER; see Unsupported groups
Actor.addWebhook() is only supported on the platform. Ignoring.addWebhook() ran locallyExpected; test webhooks on a platform run
eventChargeLimitReached: trueThe run hit maxTotalChargeUsd, or the platform rejected the chargeStop or reduce work
ChargeUncertainErrorThe platform didn't confirm a charge after retriesTreat the charge as possibly applied; don't charge again blindly
Metamorph requires apiBaseUrl, token, and actorRunIdmetamorph() ran without run credentialsMetamorph only works on a platform run
Output missing after exitA write wasn't awaited, or the process exited earlyAwait every write; exit through Actor.main() or Actor.exit()
Progress lost after a reboot or migrationState wasn't persistedUse useState() and let the SDK handle migrating
Run failed with exit code 1 and [Scrapely] Fatal uncaughtExceptionAn unhandled error or rejectionCatch errors in your handlers; the SDK flushes charges and exits with 1

Testing and deployment

On your machine

scrapely run runs the project in the current directory with your local Node.js. It needs the SDK installed locally (see Get the SDK).

.bash
scrapely validate-schema
scrapely run -i '{"urls":["https://example.com"]}'
  • Storage goes to ./storage. The default storages are purged before each run, except INPUT.json; pass --no-purge to keep them.
  • Without -i or -f, input comes from storage/key_value_stores/default/INPUT.json.
  • --entrypoint runs a specific file or npm script instead of npm start or main.
  • Browsers launch locally. The platform proxy and charging aren't available; see Local runs.

Extract pure helpers (parsing, URL normalization) and unit-test them with your usual test runner:

.ts
export function normalizeTitle(value: string): string {
    return value.trim().replace(/\s+/g, ' ');
}

On the platform

.bash
scrapely push
scrapely call -i '{"urls":["https://example.com"]}' -o
scrapely runs log <runId>
scrapely datasets get-items <datasetId> --format json --limit 20

scrapely push uploads the source and builds it (-w 0 returns without waiting for the build). scrapely call runs the Actor from scrapely.json on the platform, streams its log, and waits; -o prints the default dataset when it succeeds. Use -b, -m, and -t for build, memory, and timeout. See CLI: Actors and CLI: Runs & builds.

Start with a small input, then check the log and the default dataset in the dashboard or with the CLI. Test charging, webhooks, abort, reboot, metamorph, and standby on real runs.

Before you ship a larger crawl:

  1. Don't rely on the scrapely version in dependencies; with Transform actors on, the build uses the base image's SDK.
  2. Validate input before expensive work.
  3. Await every dataset, key-value store, and queue write.
  4. Persist crawl state with useState() so a reboot doesn't lose progress.
  5. Check eventChargeLimitReached if the Actor is priced per event.
  6. Keep tokens and proxy credentials out of source code and logs.

Production template

.ts
import { Actor, CheerioCrawler } from 'scrapely';

type Input = { urls: string[] };

await Actor.main(async () => {
    const input = await Actor.getInputOrThrow<Input>();
    if (!input.urls?.length) throw new Error('urls is required');

    const proxyConfiguration = await Actor.createProxyConfiguration();

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

    await crawler.run(input.urls);
});

On the platform, createProxyConfiguration() with no options uses the platform proxy (residential, billed per GB); locally it returns undefined and the crawler connects directly.