Logs, usage and status
Inspect recent requests with spicrawl logs, read billed usage with spicrawl usage, and check the API end to end with spicrawl status.
Three read-only command groups tell you what happened, what it cost, and whether the API is reachable from this machine.
spicrawl logs --errors --limit 20 # recent failures
spicrawl logs get 01M0FK1EP2E7FBMWAR7W10SMXW
spicrawl logs --watch # live request log (0.1.4 or later)
spicrawl usage summary # credits used against the plan
spicrawl status # API reachable, workers ready, key accepted, agents connectedspicrawl logs
Lists recent API requests in the key's project, newest first (GET /v1/requests). With --all-projects, every project in the key's organization instead, which needs a key with the read scope. Records are kept for the organization's retention window (24 hours by default); older ones are gone.
spicrawl logs
spicrawl logs --errors --limit 20
spicrawl logs --all-projects --errors
spicrawl logs --status blocked --all --jsonl | jq -r .url| Flag | API parameter | Default | Meaning |
|---|---|---|---|
--errors | only_errors=true | off | Every request whose status is not success. Cannot be combined with --status (exit 2). |
--status S | status | all | One of success, failed, timeout, blocked, rejected, cancelled. Any other value exits 2. |
--limit N | limit | 50 | Page size, 1-200. |
--all | before, before_id | off | Follow the cursor until every retained record is read. |
--jsonl | none | off | One compact JSON record per line, streamed page by page. |
--all-projects | all_projects=true | off | Every project in the key's organization, not just its own. Needs the read scope (403 ERR::AUTH::INSUFFICIENT_SCOPE without it). Sent on every page. |
Output:
- Human mode: a
TIME STATUS HTTP ENGINE CREDITS TOTAL_MS URLtable, with aPROJECTcolumn afterTIMEunder--all-projects. When more pages exist and you did not pass--all, stderr saysmore records exist; pass --all to fetch every page. - JSON mode:
{"data": [...], "page": {...}}.pagecarriesretention_hours,retained_since,has_more,next_beforeandnext_before_id. - No matching requests: human mode on a terminal prints
no requests in the last N hourson stderr and nothing on stdout (-qsilences it). Piped, or with--json, stdout is{"data": [], "page": {...}}. --jsonl: oneRequestLogEntryper line, no wrapper.
Each record has id, created_at, engine (the rendering tier: fetch, js or browser), status, http_status, error_code, error_detail, attempts, url, proxy, spans, blocked, credits_micro and features. Credits are in micro-credits (1 credit = 1,000,000).
# Error codes of the last day's failures, most frequent first
spicrawl logs --errors --all --jsonl | jq -r .error_code | sort | uniq -c | sort -rnLive view: --watch
spicrawl logs --watch
spicrawl logs --watch --errors --all-projects
spicrawl logs --watch --json | jq -r 'select(.status != "success") | .url'logs --watch (0.1.4 or later) polls the request log every --poll (default 2s) and shows new requests as they arrive. --errors, --status, --limit and --all-projects work as in logs; with --watch the default --limit is 200.
On a terminal it is a full-screen, scrollable view, newest request on top, and the selection stays on its row as new ones arrive. Keys:
| Keys | Does |
|---|---|
Arrows, PgUp/PgDn, g/G | Move. |
Enter | Open the request: what logs get prints. |
/ | Search. |
s, t, e | Cycle the status filter, the tier filter (fetch, js, browser), and errors only. c clears them. |
p, r | Pause; refresh now. |
q, Esc | Quit; from an open request, go back to the list. Ctrl-C quits with exit 130. |
The filters apply to the rows loaded so far (the newest --limit and everything since). To narrow the query itself, start with --errors or --status. A failed poll does not close the view: the error shows on the status bar and the poll is retried with backoff. A wrong key fails at once with its usual exit code, before the screen opens. NO_COLOR turns colour off and the selected row is marked with >.
The full-screen view needs a terminal on stdin and stdout. When either is not one, or with --json, -q, CI or TERM=dumb, logs --watch streams new requests as plain lines instead, oldest first: one JSON record per line with --json, which is the default when stdout is piped.
spicrawl logs get
Shows one request: outcome, error, latency spans, proxy and bot-block details (GET /v1/requests/{id}). The id is the X-Request-Id response header, the request_id in a scrape's JSON output, or the request_id of a problem document. Every failed command prints it in human mode as request id: <id> (spicrawl logs get <id>).
spicrawl logs get 01M0FK1EP2E7FBMWAR7W10SMXW
spicrawl logs get 01M0FK1EP2E7FBMWAR7W10SMXW --json | jq .spansSpans are measured by different processes and do not sum to total_ms. A span shown as — was not measured, which is not the same as 0. An id older than the retention window returns ERR::REQUEST::NOT_FOUND or ERR::REQUEST::BEYOND_RETENTION (exit 4).
spicrawl usage
Billed usage for the key's organization, broken down by one dimension (GET /v1/usage). Needs a key with the read scope; otherwise ERR::AUTH::INSUFFICIENT_SCOPE (exit 3).
spicrawl usage
spicrawl usage --from 2026-08-01 --to 2026-09-01 --group-by engine
spicrawl usage --group-by project --metrics credits,requests
spicrawl usage --group-by key --metrics requests,client_cli| Flag | API parameter | Default | Meaning |
|---|---|---|---|
--from YYYY-MM-DD | from | 29 days ago | First UTC day, inclusive. |
--to YYYY-MM-DD | to | tomorrow | End UTC day, exclusive. One day, 2026-08-01, is --from 2026-08-01 --to 2026-08-02. At most 400 days per call. |
--group-by G | group_by | day | day, project, engine (groups are the rendering tiers fetch, js and browser), feature or key. |
--metrics LIST | metrics | all | Comma-separated: requests, credits, engine_ms, bytes_egress, bytes_ingress, proxy_bytes_dc, proxy_bytes_resi, extractions, ai_extractions, batch_items. |
--project ID | project_id | every project | Only this project. |
JSON mode prints the API's UsageBreakdown unchanged: period, group_by, groups, totals, unattributed, usage_as_of, stale_seconds, warnings. totals is the billed figure; trust it over the sum of groups. Credits are in micro-credits in JSON; the human table shows whole credits. credits is total spend, batch items included, in every grouping; with --group-by feature, the batch share of it is under batch.
With --group-by key the body is instead {period, group_by: "key", keys[]}. Each key has key_id, name, prefix, project_id, revoked, days[] ({day, metrics}) and window totals, read from the per-key rollup. Requests made without a key (the dashboard) are not in it, and a project-scoped key only sees its own project's keys. No caller IPs or countries are returned. The human table shows one row per key with window totals.
Besides the billing metrics, --metrics accepts requests_failed, requests_timeout, the per-feature counters (feature_screenshot, feature_pdf, ...) and the per-client counters (client_cli, client_mcp, client_sdk, client_other).
spicrawl usage summary
Current-period usage against the plan's credit allowance (GET /v1/usage/summary). When no subscription covers today, the organization is on the free plan (plan.code free, subscription_status none) and the period is its allowance month, which runs from the day of the month the organization was created. That is the window the monthly allowance is enforced over, not a billing period, so it is not a bill preview.
spicrawl usage summary
spicrawl usage summary --json | jq .allowance.remaining_microallowance is the monthly allowance as the API enforces it: limit_micro, limit_source (default or override), used_micro, remaining_micro, window_start and resets_at. Its used_micro includes credits held for work in flight (open browser sessions, unfinished batch items), so allowance.remaining_micro is what you can still spend. It includes extra_micro, extra credits granted on top of the monthly limit.
credits is metered usage for the period: included_micro, used_micro, remaining_micro, overage_micro and used_basis_points. It includes batch spend, but not credits held for work still running.
spicrawl usage reconciliation
Compares billed usage for one UTC day with usage re-derived from the request log (GET /v1/usage/reconciliation). Report only; nothing is repaired.
spicrawl usage reconciliation
spicrawl usage reconciliation --day 2026-09-21 --json | jq .drift| Flag | Default | Meaning |
|---|---|---|
--day YYYY-MM-DD | yesterday | UTC day to reconcile. |
Read interpretation before drift: when the request log holds no rows for the day, every billed row shows as drift, which is not evidence of overbilling. Batch usage is not reconciled here, because batch items are not in the request log: batch_items never appears, and a credits row compares only the non-batch part of the day's credits.
spicrawl status
Checks the whole path from this machine to a working API, in three calls and one look at the agent config files:
| Source | Checks |
|---|---|
GET /readyz | The API is reachable and ready, and whether the cloud browser (cdp) is enabled. No key needed. |
GET /v1/workers | Which worker kinds are present and ready. |
GET /v1/requests?limit=1 | The key is accepted. |
| Agent config files | Each agent client found in the current directory or your home directory (Claude Code, Cursor, VS Code, Codex) has a spicrawl MCP server, in a project or user config, that can authenticate. A project entry shadows a user-level one. No network. Skipped when no client is found. |
spicrawl status
spicrawl status --json | jq .workers
spicrawl status --base-url http://localhost:8080 --api-key "$SPICRAWL_API_KEY"{
"api_reachable": true,
"ready": true,
"checks": { "postgres": "ok", "redis": "ok" },
"cdp": "disabled",
"key_valid": true,
"key_source": "env",
"base_url": "https://api.spicrawl.com",
"workers": {
"browser": { "present": 2, "ready": 2 },
"egress": { "present": 1, "ready": 1 }
},
"mcp": { "detected": ["claude", "cursor"], "connected": ["claude", "cursor"], "needs_env": [], "stale": [] },
"repairs": []
}cdp says whether GET /v1/browser (remote browser) can serve a session on this deployment: enabled, disabled (the operator did not install the CDP browser; /v1/browser answers 501 or does not exist, and every other endpoint still works) or unknown (the browser worker could not be asked). Human output prints it as a cdp: line. key_valid is true, false, or null when the check could not tell (for example a network error mid-check). key_error explains a rejected or missing key; key is valid but lacks the read scope still counts as valid. workers is read only once the key is accepted; workers_error is set when that call failed.
mcp lists agent client ids (claude, cursor, vscode, codex):
| Field | Clients that |
|---|---|
detected | Are found here. [] when none is. |
connected | Have a Spicrawl MCP server that can authenticate. |
needs_env | Have an entry that reads ${SPICRAWL_API_KEY} while that variable is unset in the environment status runs in. |
stale | Have an entry with a key written into it that is not the key in use. The keys are compared by fingerprint; neither is printed. |
A client in needs_env or stale is not connected, and it fails the mcp check. A client in none of the three has no Spicrawl entry. Human output adds an mcp: line, for example connected: Claude Code, not configured: Cursor, needs $SPICRAWL_API_KEY, which is not set here: Claude Code or has a different key than the one in use: Claude Code.
| Exit code | When |
|---|---|
0 | Every check passed: the API is reachable and ready, the key works, every worker kind that is present has at least one ready, and every detected agent client has an MCP server that can authenticate. |
1 | Any other check failed: the API reports not ready, a worker kind has none ready, or a detected agent client has no Spicrawl MCP server that can authenticate. stderr says 1 check failed: run the repairs listed in the status output (N checks failed for more). |
3 | The key is missing or rejected. |
10 | The API could not be reached. |
A connection that fails during the key check exits with the transport error's code (12 if it timed out or dropped). The report is on stdout whatever the exit code. Behaviour change in 0.1.4: before it, a reachable API that reported not ready exited 0, and status had no mcp or repairs. A script that needs the old result reads ready and checks from --json instead of the exit code.
Repairs
For every failed check, status prints a repair command, and --json has them in the repairs array of {check, command, unattended_safe, why}, in the order to run them. The array is always present and is [] when every check passed. On a terminal, status draws a checklist with the repairs under it. With NO_COLOR, TERM=dumb or CI set, the entries print as a repairs: block of check:, command:, unattended_safe: and why: lines. Piped, as an agent runs it, status prints the JSON.
"repairs": [
{
"check": "key",
"command": "spicrawl login --api-key <YOUR_API_KEY>",
"unattended_safe": false,
"why": "no API key is configured: create one at https://app.spicrawl.com/dashboard/keys and supply it"
},
{
"check": "mcp",
"command": "spicrawl init --all --yes",
"unattended_safe": true,
"why": "no Spicrawl MCP server is configured for Claude Code; this writes the MCP entry and the skill for every client found here"
}
]unattended_safe: true means an agent may run the command without asking. false means the user must act (supply a key) or decide, so show them the command instead. A command holds the placeholder <YOUR_API_KEY>, never a key. When the CLI was started by npx, commands name npx -y @spicrawl/cli@latest instead of spicrawl.
check | Fails when | command | unattended_safe |
|---|---|---|---|
reachable | /readyz did not answer. | curl -sS -m 10 <base url>/readyz | true |
ready | The API reports not ready. That is on the server side: wait a minute and run status again. | spicrawl status | true |
key | No key is configured, or the API rejects it. | spicrawl login --api-key <YOUR_API_KEY>; for a rejected $SPICRAWL_API_KEY, export SPICRAWL_API_KEY=<YOUR_API_KEY> | false |
key | The key check got no answer (key_valid is null). | spicrawl status | true |
workers.<kind> | A worker kind (browser, egress, extract or batch) is present with none ready. Server side: wait a minute and run status again; if it persists, tell Spicrawl support. | spicrawl status | true |
mcp | A detected agent client has no Spicrawl MCP server. | spicrawl init --all --yes | true |
mcp | An entry reads ${SPICRAWL_API_KEY} while it is unset here (needs_env), or holds another key than the one in use (stale). One repair covers the user-level entries and another the project entries. | spicrawl init --client <ids> --yes, plus --global=false for a project entry | true when a key is saved in the CLI's config file; otherwise --api-key <YOUR_API_KEY> is added and it is false |
A needs_env or stale repair rewrites the entry with the key saved in the CLI's config file (by spicrawl login or init --api-key) and keeps the old file as <file>.bak, so nothing needs exporting and --force is not needed. A key that is only in $SPICRAWL_API_KEY is not saved, so init keeps writing ${SPICRAWL_API_KEY} references for it: see Agent setup.
Sessions and browser
Keep cookies and login state across scrapes with spicrawl sessions, and open a cloud browser with spicrawl browser url.
Agent setup
Connect Claude Code, Cursor, VS Code and Codex to Spicrawl with spicrawl init, mcp install and skill install, and give agents docs and request schemas offline with spicrawl docs and spicrawl schema.