Projects & running
Create, initialize, validate, push, pull, and run Actor projects.
These commands work on the Actor project in a folder on your machine: create it from a template or add a config to existing code, check its schemas, push it to the platform, download it again, and run it locally or on the platform.
Create a project
From a template
scrapely create my-actor --template crawlee-cheerio-jscreate makes a new folder named after the Actor, in the current directory. It fails if the folder already exists. The name must be at least three characters long and contain only lowercase letters, digits, and hyphens, and it can't start or end with a hyphen.
Without a name, create asks for one. Without --template, it asks what you want to build, which language you prefer, and then which template to use.
| Option | Description |
|---|---|
-t, --template <template> | Template ID or alias. See the table below. |
-l, --language <language> | Only offer templates in this language: javascript (js) or typescript (ts) |
-u, --use-case <useCase> | Only offer templates for this use case: web-scraper, browser-automation, or data-pipeline. Ignored with --template. |
--source <source> | Where the source lives: platform (the default, on the platform) or github (a new GitHub repository). apify is a deprecated alias of platform. gitlab and bitbucket are rejected. |
--git-repo <repo> | GitHub repository for --source github, as owner/name, a bare name, or a URL |
--auto-build <on|off> | With --source github, create the Actor on the platform from the repository and rebuild it on every Git push |
--skip-dependency-install | Don't run npm install |
--omit-optional-deps | Run npm install --omit=optional |
--skip-git-init | Don't create a Git repository or the first commit |
--json | Print the result as JSON. Also skips the Git setup and npm install. |
What create does:
- Fetches the template catalog from the API (
GET /v2/actor-templates). If the API can't be reached, it uses the copy bundled with the CLI. - Clones scrapely-app/actor-templates with
git clone --depth 1and copies the template folder, withoutnode_modules,.git,.github,storage,dist, and.env. Git and access to GitHub are required. - Sets the Actor name in
package.jsonand in the template's.actor/scrapely.json. Python projects created from a repository with--git-repoalso rename amy_actor/package to the Actor name with hyphens replaced by underscores. - Adds
.gitignoreand.actorignoreif the template has none. - Runs
git init,git add ., andgit commit -m "Initial commit". - Runs
npm installfor JavaScript and TypeScript templates. Python projects install nothing locally.
List the templates with:
scrapely templates ls
scrapely templates ls --json--json prints each template's name, aliases, displayName, description, language, and useCases. templates ls doesn't need a login.
| Template | Language | Use cases | Source |
|---|---|---|---|
crawlee-cheerio-js | JavaScript | web-scraper, data-pipeline | js-crawlee-cheerio |
crawlee-playwright | JavaScript | web-scraper, browser-automation | js-crawlee-playwright-chrome |
crawlee-puppeteer-chrome | JavaScript | web-scraper, browser-automation | js-crawlee-puppeteer-chrome |
crawlee-playwright-ts | TypeScript | web-scraper, browser-automation | ts-crawlee-playwright-chrome |
js-bootstrap-cheerio-crawler | JavaScript | web-scraper | js-bootstrap-cheerio-crawler |
js-crawlee-playwright-camoufox | JavaScript | web-scraper | js-crawlee-playwright-camoufox |
js-cypress | JavaScript | browser-automation | js-cypress |
js-empty | JavaScript | - | js-empty |
js-langchain | JavaScript | ai-agent | js-langchain |
js-langgraph-agent | JavaScript | ai-agent | js-langgraph-agent |
js-standby | JavaScript | data-pipeline | js-standby |
js-start | JavaScript | web-scraper | js-start |
ts-beeai-agent | TypeScript | ai-agent | ts-beeai-agent |
ts-crawlee-cheerio | TypeScript | web-scraper | ts-crawlee-cheerio |
ts-crawlee-playwright-camoufox | TypeScript | web-scraper | ts-crawlee-playwright-camoufox |
ts-crawlee-puppeteer-chrome | TypeScript | web-scraper | ts-crawlee-puppeteer-chrome |
ts-empty | TypeScript | - | ts-empty |
ts-mastraai | TypeScript | ai-agent | ts-mastraai |
ts-mcp-empty | TypeScript | ai-agent, data-pipeline | ts-mcp-empty |
ts-mcp-proxy | TypeScript | ai-agent, data-pipeline | ts-mcp-proxy |
ts-playwright-test-runner | TypeScript | browser-automation | ts-playwright-test-runner |
ts-standby | TypeScript | data-pipeline | ts-standby |
ts-start | TypeScript | web-scraper | ts-start |
ts-start-bun | TypeScript | web-scraper | ts-start-bun |
crawlee-playwright-js and crawlee-puppeteer-js still work as aliases for crawlee-playwright and crawlee-puppeteer-chrome.
Keep the source on GitHub
scrapely create my-actor --template crawlee-cheerio-js --source github --git-repo my-org/my-actor --auto-build onWith --source github, create creates a private GitHub repository with the GitHub CLI (gh) and pushes the template to it. Without gh, it adds the remote and pushes with Git. If the repository already exists and isn't empty, create clones it instead of copying the template.
--auto-build on then creates the Actor on the platform from the repository, starts the first build, and registers a webhook so each push to the linked branch rebuilds the Actor. Pushes to other branches are ignored. The webhook needs the GitHub integration with admin rights on the repository. If it can't be registered, create prints the webhook URL to add by hand. Don't run scrapely push for an Actor set up this way, because it replaces the Git source with uploaded files. Commit and git push instead.
In an existing folder
scrapely init
scrapely init my-actorinit adds Actor files to existing code. Without an argument it works in the current folder. With one, it works in the subfolder of that name and creates it if needed. It then asks for the Actor name, with the argument or my-actor as the default.
| Option | Description |
|---|---|
--dockerfile <path> | Record this Dockerfile path in the config |
-y, --yes | Don't prompt. Use the argument or my-actor as the name, and keep an existing package.json. |
If the folder already has a package.json, init asks whether to continue. In a non-interactive shell without -y, it stops there. If the folder has files but no package.json, pyproject.toml, requirements.txt, or scrapy.cfg, it asks for confirmation first.
What init writes:
scrapely.jsonwithactorSpecification,name,version0.0,buildTaglatest, anddockerfileif you passed one. It skips this if any Actor config already exists.- For a Scrapy project (a folder with
scrapy.cfg): amain.pywrapper that runs the project's spiders inside the Actor and pushes every scraped item to the default dataset, plusscrapely-python(the SDK's PyPI name) andscrapyinrequirements.txt. Ascrapelyline from an older CLI version is replaced, because the PyPI packagescrapelyis an unrelated library. - For anything else: a
package.jsonwith astartscript if there is none, and amain.jsPlaywright starter if there is none. An existingpackage.jsonis never changed. .gitignoreand.actorignoreif missing.
init doesn't create a Dockerfile. Add one before you push, or start from a template, whose Dockerfile builds on the Scrape.ly base images.
Check schemas
scrapely validate-schema
scrapely validate-schema .actor/input_schema.jsonWithout a path, validate-schema finds the Actor config and checks every schema it references: the input schema (input or inputSchema), the dataset schema (storages.dataset), the output schema (output or outputSchema), and the key-value store schema (storages.keyValueStore). Each can be inline or a path, resolved relative to the config file or the current folder. With a path, it checks that one file.
The check is basic: the schema must be an object, properties must be an object, required must be a list of strings, and title and description must be strings. It exits with code 1 on errors. It doesn't check editor types, defaults against types, or the full Actor input schema specification.
For the input schema it also checks categories. A category that names no defined category is an error, with the closest key suggested. So are a parent loop, nesting deeper than 3 levels, and a wrong value type. Unused categories and unknown category settings are warnings, which don't change the exit code.
Push to the platform
scrapely push
scrapely push <actorId>push uploads the project, creates or replaces a version of the Actor, and builds it. scrapely actors push is the same command.
| Option | Description |
|---|---|
-v, --version <version> | Version number. Default: version from the config, then from package.json, then 0.0.1. |
-b, --build-tag <tag> | Build tag for the version and the build. Default: buildTag from the config, then latest. |
-f, --force | Push even if the Actor on the platform was changed after your local files |
--allow-missing-secrets | Continue when an @secret in environmentVariables isn't in your local secrets |
--dir <path> | Push the project in this folder instead of the current one |
-w, --wait-for-finish [seconds] | How long to wait for the build. No value, or no flag, waits until the build finishes. 0 returns as soon as the build has started. |
--open | Open the Actor in the dashboard afterwards |
--json | Print { actorId, version, buildTag, buildId, buildStatus } |
Step by step:
- Reads the Actor config. It fails with
No package.json found. Run scrapely init first.if the folder has neither a config nor apackage.json. - Checks that every
@secretinenvironmentVariablesexists in your local secrets. Secret values are not uploaded. See Secrets on the platform. - Collects the files. It always skips
node_modules,.git,storage,dist,.env,.DS_Store,*.log, and.scrapely, plus every pattern in.gitignoreand in.actorignore. Both files apply. Symbolic links are skipped. Binary files are uploaded base64-encoded. If the upload is larger than 3 MB, the files are sent as one ZIP archive. - Finds the Actor: the ID you passed, or
actorIdfrom the config. If there is none, it creates a new Actor with the config'sname,title, anddescription, and writes the newactorIdinto the config file it read. If no config file exists, it createsscrapely.json. - For an existing Actor, compares modification times. If the Actor on the platform is newer than your files, it asks before overwriting. In a non-interactive shell or with
--jsonit fails instead.--forceskips the check. - Uploads the version. If a version with that number exists, it is replaced, including any environment variables set on it in the dashboard.
- Starts a build without the Docker cache and waits for it as
-wsays. If the build fails, it prints the build log and exits with code 1. If-w <seconds>runs out while the build is still running, it exits with code 0.
Without --json, push ends by printing scrapely call <actorId> so you can run the new build.
Pull from the platform
scrapely pull
scrapely pull <actorId> --version 0.1 --dir ./my-actorpull downloads an Actor's source. Only the Actor's owner can pull it. Without an ID it uses actorId from the config in the current folder, then the config's name.
| Option | Description |
|---|---|
-v, --version <version> | Version to pull. Default: the last version in the Actor's list. |
--dir <dir> | Folder to write to. Default: the current folder. |
For an Actor built from a Git repository, pull runs git clone. Only the owner can see the repository URL. If the target folder isn't empty, it clones into a subfolder named after the repository.
Run locally
scrapely run
scrapely run -i '{"startUrls":[{"url":"https://crawlee.dev"}]}'
scrapely run -f input.json
echo '{"startUrls":[{"url":"https://crawlee.dev"}]}' | scrapely run -f -run starts the project in the current folder as a process on your machine. It doesn't use the platform or Docker. To run on the platform, use call. If you pass an Actor ID, run only prints a note pointing you to call.
| Option | Description |
|---|---|
-i, --input <json> | Input as a JSON string |
-f, --input-file <path> | Input from a JSON file, or - for stdin |
--entrypoint <path> | What to start. Node: a .js file, a folder with index.js, or an npm script name. Python: a .py file or a module name. |
-p, --purge | Clear the default local storages first. This is already the default. |
--no-purge, --resurrect | Keep the data from the previous run |
--allow-missing-secrets | Warn instead of failing when an @secret isn't in your local secrets |
Before it starts the process, run:
- Clears
storage/datasets/default,storage/key_value_stores/default, andstorage/request_queues/default, unless you pass--no-purge. It keepsINPUT.jsonand named storages. - Reads the input from
-ior-f, or fromstorage/key_value_stores/default/INPUT.json. Passing both-iand-fis an error. - Applies the defaults from the input schema and fails if a required field is missing. The schema is the config's
input, or.actor/input_schema.json. - Sets the input as
ACTOR_INPUT(base64-encoded JSON) andACTOR_INPUT_KEY=INPUT. - Sets the config's
environmentVariables, replacing each@secretwith its value fromscrapely secrets.
How it starts the project:
- Node.js:
--entrypointif given, elsenpm run startifpackage.jsonhas astartscript, elsenodewithpackage.json'smain. - Python: the interpreter from
.venvif there is one, elsepython3. It runs--entrypoint(a file, or a module with-m), elsemain.pyorsrc/main.py. If your Python code lives in a package, pass the package name, for example--entrypoint my_actor.
run exits with the exit code of the process.
Run on the platform
scrapely call
scrapely call <actorId> -i '{"startUrls":[{"url":"https://crawlee.dev"}]}' -ocall starts a run on the platform and waits for it to finish, printing new log output every two seconds. Without an ID it uses actorId from the config in the current folder. scrapely actors call is the same command.
| Option | Description |
|---|---|
-i, --input <json> | Input as a JSON string |
-f, --input-file <path> | Input from a JSON file, or - for stdin |
-b, --build <tag> | Build tag or number to run. Your own Actors only; others run the User Build |
-m, --memory <mb> | Memory for the run, in megabytes |
-t, --timeout <seconds> | Run timeout in seconds. 0 means no timeout. |
-o, --output-dataset | When the run succeeds, print the items of its default dataset as JSON |
-s, --silent | Don't print the run log |
--json | Print { "data": <run> } when the run ends, with no log |
Without -i or -f, the input is storage/key_value_stores/default/INPUT.json if that file exists. Otherwise the run starts without input. call exits with code 1 if the run ends in any status other than SUCCEEDED.
To start a run without waiting, use actors start.
Project configuration
The CLI reads the Actor config from the first of these files that exists:
.actor/actor.json.actor/scrapely.jsonscrapely.jsonactor.json
If both a file in .actor/ and a root scrapely.json exist, the fields in scrapely.json override the ones in .actor/. Templates use .actor/scrapely.json. init writes scrapely.json.
The fields the CLI uses:
| Field | Used by |
|---|---|
name | push when it creates the Actor. Falls back to package.json's name. |
title, description | push when it creates the Actor |
version | push and builds create. Falls back to package.json's version, then 0.0.1. |
buildTag | push. Default latest. |
actorId | push, call, pull, runs ls, and builds ls. Written by the first push. Falls back to package.json's actorId. |
environmentVariables | run sets them. push checks that the @secret ones exist locally. |
input or inputSchema | run and validate-schema. Inline schema or a path. |
storages.dataset, storages.keyValueStore, output or outputSchema | validate-schema |
dockerfile | Written by init --dockerfile |
The platform reads the same file when it builds and runs the Actor, including dockerfile, dockerContextDir, the schemas, the memory limits, environmentVariables, and usesStandbyMode. See Actors for the full format.
Two ignore files decide what push uploads: .gitignore and .actorignore. .dockerignore only affects the Docker build on the platform.
Example
{
"actorSpecification": 1,
"name": "listing-scraper",
"title": "Listing scraper",
"description": "Scrapes product listings into a dataset",
"version": "0.1",
"buildTag": "latest",
"dockerfile": "./Dockerfile",
"environmentVariables": {
"LOG_LEVEL": "info",
"API_KEY": "@my-api-key"
},
"input": "./input_schema.json"
}With this file at .actor/scrapely.json, the paths are resolved relative to .actor/.
What's next
- Actor runtime: commands your code can call inside the container.
- Runs & builds: inspect and control what you deployed.
- Config & troubleshooting: run
pushfrom a pipeline.