CLI
The bw command-line interface.
The Bytewells CLI, bw, creates, pushes, publishes, rents, runs and inspects Actors, and imports existing Actors from Apify.
Installation
npm install -g @bytewells/cliOr use directly with npx:
npx @bytewells/cli <command>After installation the command is bw (long form: bytewells):
bw <command>
bw --helpThe default API is https://bytewells.com/api. Pass --url only if Bytewells support gives you a different endpoint.
Commands
init
Create a new Actor project from a template.
bw init [name] [options]Options:
| Flag | Description |
|---|---|
--template, -t | Template ID from Apify catalog |
--list, -l | List available templates |
Example:
# Interactive mode - prompts for name and template
bw init
# Quick start with specific template
bw init my-scraper --template ts-crawlee-cheeriosignup
Create a Bytewells account and log in.
bw signup [options]| Flag | Description |
|---|---|
--email | Account email |
--password | Password (prompted if omitted; or BYTEWELLS_PASSWORD) |
--name | Your name |
--username | Public handle used in Store slugs (<username>/<actor-name>) |
--referral-code | Referral code from the developer who invited you |
--url, -u | API base URL (default: https://bytewells.com/api) |
--profile, -p | Profile name to save the login under |
import apify
Zero-code port from Apify: imports the source, README, input schema, run defaults and rental price of Actors you own on Apify, builds them on Bytewells and (unless --no-listing) creates Store listings. It only reads from Apify.
For interactive import without a token, use Continue with Apify / Connect Apify in the console — see Import from Apify. Prefer the CLI when source is a private Git repo or you need CI/--all automation.
bw import apify [actors...] [options]actors are Apify Actor IDs or username/actor-name.
| Flag | Description |
|---|---|
--apify-token | Apify API token (default: $APIFY_TOKEN, then $APIFY_SOURCE_TOKEN) |
--all | Import every Actor owned by the token's Apify account |
--dry-run | Read from Apify and show what would happen, without writing anything |
--price-discount <pct> | Undercut your Apify rental price by this percentage (default: 0) |
--publish | Publish each listing after its build succeeds |
--no-listing | Import and build without creating a Store listing |
--update | Re-import Actors that already exist on Bytewells |
--tag, -t | Build tag (default: latest) |
--out-dir <dir> | Keep the downloaded source in <dir>/<actor-name> |
--verbose | Stream every build log line |
--json | Print the results as JSON |
Example:
export APIFY_TOKEN=<your Apify token>
bw import apify --all --dry-run
bw import apify jane/google-maps-scraper --price-discount 20 --publishdev
Run Actor code on your machine in development mode (against the hosted API if env is set).
bw dev [options]Options:
| Flag | Description |
|---|---|
--watch, -w | Enable file watching & auto-reload |
Example:
cd my-actor
bw dev # Run once
bw dev --watch # Run with hot reloadstatus
Check the status of an Actor run.
bw status <run-id> [options]Options:
| Flag | Description |
|---|---|
--watch, -w | Watch for status updates |
--interval, -i | Watch interval in seconds (default: 5) |
Example:
bw status abc123
bw status abc123 --watch --interval 5login
Log in with email and password or an API token.
bw login [options]Options:
| Flag | Description |
|---|---|
--email | Account email (logs in with password) |
--password | Account password (prompted if omitted; or BYTEWELLS_PASSWORD) |
--token, -t | API token |
--url, -u | API base URL (default: https://bytewells.com/api) |
--profile, -p | Save under a named profile (for multi-environment setups) |
Without flags, you'll be prompted interactively. The token is validated against the server before saving — invalid tokens never get persisted.
Examples:
# Interactive login (prompts for URL and token)
bw login
# Non-interactive
bw login --email [email protected]
bw login --token your-api-token
# Save under a named profile (sets it as active too)
bw login --profile prod --url https://bytewells.com/api --token <T>Credentials are stored in ~/.bytewells/config.json. The file uses a multi-profile shape; legacy single-profile configs (and an existing ~/.crawlee-cloud/config.json) are migrated transparently on first read.
info
Show the active profile, API URL, server status, and authenticated user. The "where am I?" command for context-switching between environments.
bw info [-j, --json]Output (human-readable):
Profile: prod (active)
API: https://bytewells.com/api
Server: v1.6.0 reachable, 53ms
Auth: valid
User: [email protected]
Token: eyJhbGciOiJI...Exits non-zero if the server is unreachable or the token is invalid — useful as a CI healthcheck before bw push:
bw info --json >/dev/null && bw pushThe --json output (short flag: -j) has a stable shape suitable for piping into scripts. The full token is never exposed; only a 12-char preview.
profile
Manage saved login profiles. A profile is a stored apiBaseUrl + token pair; one is active at a time. Use bw login --profile <name> to create one.
bw profile list # show all profiles, mark active (alias: ls)
bw profile use <name> # switch active
bw profile rm <name> # delete a profile (alias: remove)Examples:
$ bw profile list
* prod https://bytewells.com/api eyJhbGciOiJI...
For per-invocation overrides without changing the active profile, use the BYTEWELLS_PROFILE env var:
BYTEWELLS_PROFILE=prod bw push # one-off push, no `profile use` neededpush
Upload the Actor in the current directory and build it. The command takes no positional argument — the Actor name is always read from .actor/actor.json in the current directory.
By default push packs the directory as a tar.gz, uploads it to POST /v2/acts/:id/builds/source and follows the build log; the build runs on the Bytewells builder, so you don't need Docker on your machine. The image is named bytewells/<username>/<actor-name>.
bw push [options]Options:
| Flag | Description |
|---|---|
--tag, -t | Build tag (default: latest) |
--actor-version | Actor version for this build (default: version in .actor/actor.json, else 0.0) |
--no-wait | Start the hosted build and exit without following its log |
--env, -e | Set an Actor default env var as KEY=VALUE (repeatable; empty values are dropped) |
--env-file | Load Actor default env vars from a file (KEY=VALUE per line, # comments allowed) |
--platform | Self-hosted: Docker build platform (e.g. linux/amd64) |
--remote | Self-hosted: build on a remote runner via SSH (user@host) |
--ssh-key | SSH key to use for the remote build |
--ghcr | Self-hosted: build and push to GitHub Container Registry (e.g. org/repo) |
--ghcr-user | GHCR username (default: github) |
--ghcr-token | GHCR token (or set the GHCR_TOKEN env var) |
Examples:
cd my-actor
# Push (name comes from .actor/actor.json)
bw push --tag 1.0.0
# Inject default env vars into the Actor (repeatable -e, or a file)
bw push -e API_KEY=abc123 --env-file .env.productionAfter the first successful build, publish the Actor with bw publish or from the dashboard (Publish).
publish
Put an Actor on the Store. Creates the listing if it doesn't exist yet (needs --price or --free), applies the pricing flags, then publishes it. Paid listings need a Stripe Connect account that can accept charges (set it up in the dashboard under Earnings).
bw publish <actor> [options]actor is an Actor name or ID, or a listing slug.
| Flag | Description |
|---|---|
--price <usd> | Monthly rental price in USD, e.g. 29 |
--trial-days <n> | Free trial length in days (0-30) |
--free | List the Actor for free |
--draft | Create or update the listing without publishing |
--unpublish | Take the listing off the Store |
bw publish my-scraper --price 29 --trial-days 7Price changes apply to new rentals only; existing renters keep the price they signed up at.
listings
List your Store listings with status and price.
bw listings [--json]rent
Rent an Actor from the Store. Free listings are active immediately; paid listings print a Stripe Checkout link. Renting shares your name and email with the developer, and the command asks you to confirm that.
bw rent <username>/<actor-name> [--yes]--yes, -y skips the confirmation prompt (you consent to share your contact details).
run
Run Actor code on your machine with local file storage.
bw run [options]Options:
| Flag | Description |
|---|---|
--input, -i | JSON input or path to JSON file |
--no-purge | Do not purge storage before run |
Examples:
# Run in current directory
cd my-actor
bw run
# Run with input
bw run --input '{"url": "https://example.com"}'
# Keep previous storage data
bw run --no-purgeLocal storage is created in ./storage/ with datasets, key-value stores, and request queues.
logs
Stream logs from a run.
bw logs <run-id> [options]Options:
| Flag | Description |
|---|---|
--follow, -f | Continuously stream new logs |
--limit, -l | Number of log lines to show (default: 1000) |
Example:
bw logs abc123 --followcall
Call a remote Actor on the platform and optionally wait for results. Store Actors can be addressed as username~actor-name; you need an active rental (or a free listing) and a positive credit balance.
bw call <actor> [options]Options:
| Flag | Description |
|---|---|
--input, -i | Input JSON or path to JSON file |
--env, -e | Environment variable KEY=VALUE (repeatable) |
--wait, -w | Wait for run to finish |
--timeout, -t | Timeout in seconds (default: 3600) |
--memory, -m | Memory in MB (default: 1024) |
Examples:
# Call an Actor
bw call my-scraper --input '{"url": "https://example.com"}'
# Call and wait for results
bw call my-scraper --wait --input '{"url": "https://example.com"}'
# Call a rented Store Actor
bw call jane~google-maps-scraper --wait --input input.json
# Call with environment variables (use -e multiple times)
bw call my-actor -e KEY1=val1 -e KEY2=val2Tip: The
-eflag can be repeated to pass multiple environment variables in a single call.
list
List actors and recent runs on the platform. Alias: ls. Without flags, both actors and recent runs are shown.
bw list [options]Options:
| Flag | Description |
|---|---|
--actors, -a | List actors only |
--runs, -r | List recent runs only |
--limit, -n | Max items to show (default: 20) |
--json, -j | Output as JSON |
Examples:
# List actors and recent runs
bw list
# Recent runs only, as JSON
bw ls --runs --jsonGetting Your API Token
Via the Dashboard
- Sign in at https://bytewells.com/dashboard
- Go to Settings → API Keys
- Create a new API key
Via the API
First, obtain a JWT token by logging in (or signing up with POST /v2/auth/register):
curl -X POST https://bytewells.com/api/v2/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"your-password"}'Then create an API key using the JWT token:
curl -X POST https://bytewells.com/api/v2/auth/api-keys \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name":"my-key"}'Use the resulting API key as your token when running bw login.
Configuration
Configuration is stored in ~/.bytewells/config.json:
{
"activeProfile": "default",
"profiles": {
"default": {
"apiBaseUrl": "https://bytewells.com/api",
"token": "your-api-token"
}
}
}If you have a legacy flat config file (just { apiBaseUrl, token } at the top level), the CLI migrates it transparently into a default profile on first read.
Environment Variables
| Variable | Description |
|---|---|
BYTEWELLS_API_URL | Override the active profile's API base URL |
BYTEWELLS_TOKEN | Override the active profile's API token |
BYTEWELLS_PROFILE | Use this profile for the current invocation (overrides active) |
BYTEWELLS_PASSWORD | Password for non-interactive signup / login --email |
BYTEWELLS_REGISTRY_URL | Reserved; not required for the hosted product |
BYTEWELLS_NO_FEEDBACK_NOTE | Suppress the one-time feedback note after push |
APIFY_TOKEN | Apify token for bw import apify (fallback: APIFY_SOURCE_TOKEN) |
GHCR_TOKEN | GitHub Container Registry token used by the bw push --ghcr path |
GHCR_USER | GHCR username for bw push --ghcr (default: github) |
The legacy CRAWLEE_CLOUD_* names are still accepted as fallbacks.