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
| Symptom | Cause | Fix |
|---|---|---|
Actor.<name>() requires Actor.init() to be called first | A method that needs initialization ran before init() | Wrap your code in Actor.main() or call Actor.init() first |
Missing required configuration for secure storage | SCRAPELY_IS_AT_HOME is set but the API URL, token, or run ID is missing | Don't set SCRAPELY_IS_AT_HOME locally; on the platform the run injects all three |
Input does not exist | getInputOrThrow() found no input | Pass input (-i / -f locally), or use getInput() and handle null |
Cannot find package 'scrapely' or missing exports locally | The 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 disabled | Use Scrapely browser is on, but a browser launched without CDP_URL | Don't unset CDP_URL; check setCdpUrl() calls |
Custom proxies are ignored when using the Scrapely remote browser | Your own proxy URLs were passed to a browser crawler while the Scrape.ly browser is on | Use createBrowserConfiguration() for browser location; use your proxies with HTTP crawlers |
Proxy configuration is undefined | No 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 / countryCode | Use 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 offer | Use RESIDENTIAL or DATACENTER; see Unsupported groups |
Actor.addWebhook() is only supported on the platform. Ignoring. | addWebhook() ran locally | Expected; test webhooks on a platform run |
eventChargeLimitReached: true | The run hit maxTotalChargeUsd, or the platform rejected the charge | Stop or reduce work |
ChargeUncertainError | The platform didn't confirm a charge after retries | Treat the charge as possibly applied; don't charge again blindly |
Metamorph requires apiBaseUrl, token, and actorRunId | metamorph() ran without run credentials | Metamorph only works on a platform run |
| Output missing after exit | A write wasn't awaited, or the process exited early | Await every write; exit through Actor.main() or Actor.exit() |
| Progress lost after a reboot or migration | State wasn't persisted | Use useState() and let the SDK handle migrating |
Run failed with exit code 1 and [Scrapely] Fatal uncaughtException | An unhandled error or rejection | Catch 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).
scrapely validate-schema
scrapely run -i '{"urls":["https://example.com"]}'- Storage goes to
./storage. The default storages are purged before each run, exceptINPUT.json; pass--no-purgeto keep them. - Without
-ior-f, input comes fromstorage/key_value_stores/default/INPUT.json. --entrypointruns a specific file or npm script instead ofnpm startormain.- 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:
export function normalizeTitle(value: string): string {
return value.trim().replace(/\s+/g, ' ');
}On the platform
scrapely push
scrapely call -i '{"urls":["https://example.com"]}' -o
scrapely runs log <runId>
scrapely datasets get-items <datasetId> --format json --limit 20scrapely 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:
- Don't rely on the
scrapelyversion independencies; with Transform actors on, the build uses the base image's SDK. - Validate input before expensive work.
- Await every dataset, key-value store, and queue write.
- Persist crawl state with
useState()so a reboot doesn't lose progress. - Check
eventChargeLimitReachedif the Actor is priced per event. - Keep tokens and proxy credentials out of source code and logs.
Production template
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.