CLI

Serpel CLI reference

The serpel command line runs crawls, rank checks, keyword research and exports through the same REST API as the dashboard. This page covers installation, sign-in, every command group, JSON output, exit codes and a CI example. Run any command with --help for its full list of flags.

How do you install the Serpel CLI?

The CLI is published on npm as `@serpel/cli` under the MIT license. It installs one command, serpel, ships as a single bundled file and needs Node.js 20.9 or newer.

  1. Install it globally.

    npm puts the serpel command on your path. pnpm, Yarn and Bun work the same way.

    Terminal
    npm install -g @serpel/cli
  2. Or run it without installing.

    npx downloads the latest version for a single run, which is handy in CI or on a shared machine.

    Terminal
    npx @serpel/cli --help
  3. Check the installation.

    The command prints the CLI version.

    Terminal
    serpel --version
    serpel --help

The package contains dist/index.js with its libraries bundled, plus their license notices. The one optional dependency is @napi-rs/keyring, which lets the CLI keep your token in the system keyring. Without it, the CLI falls back to a file that only you can read. To update, run npm install -g @serpel/cli@latest. To remove it, run npm uninstall -g @serpel/cli.

How do you sign in to the Serpel CLI?

Browser sign-in (device login)

This is the default and needs no token to copy.

Terminal
serpel auth login
  1. The CLI asks Serpel for a sign-in code and prints a confirmation address and a verification code such as ABCD-EFGH. The code is valid for ten minutes. The CLI opens the address in your default browser. With --no-browser, it only prints the address, which suits servers without a desktop.
  2. In the dashboard, check that the code matches, choose the permissions the token gets and approve the sign-in.
  3. The CLI waits for your approval, stores the token and prints your name, email address, permissions and project restriction.

Ctrl+C cancels the wait. If the code expires or you deny the sign-in, the command exits with code 3.

Sign in with an API token

Create a token in the dashboard under Settings, API tokens, or with serpel tokens create, and hand it to the CLI. The CLI checks it with GET /me first and stores nothing if the token is invalid. Prefer --token-stdin over --token, because an argument ends up in your shell history.

Terminal
echo "$SERPEL_TOKEN" | serpel auth login --token-stdin
serpel auth login --token-stdin < token.txt

Use SERPEL_TOKEN in scripts and CI

In CI you do not need serpel auth login. Set SERPEL_TOKEN and the CLI uses it for every command. The variable beats any stored token and is never written to disk.

Terminal
export SERPEL_TOKEN=vsk_your_token
serpel projects list --json

Check your session or sign out

Terminal
serpel auth status
serpel auth logout

auth logout revokes the stored token on the server and then deletes it locally. If the server cannot be reached, the CLI still deletes the local copy and warns that the token stays valid until you revoke it in the dashboard or it expires. A token from SERPEL_TOKEN is not touched.

How is the Serpel CLI configured?

The CLI talks to https://serpel.app unless you tell it otherwise. The first source that is set wins: the --api-url <url> flag, the SERPEL_API_URL variable, the config file (serpel config set api-url <url>), then the default. Only https:// addresses are accepted, except http:// for localhost, 127.0.0.1 and [::1]. A trailing /api/v1 is removed, and addresses with credentials, query parameters or anchors are rejected. Most people never change the address. Set it only if you use another Serpel instance.

Terminal
serpel config get
serpel config get api-url
serpel config set api-url https://example.com
serpel config unset api-url

Environment variables

VariableMeaning
SERPEL_API_URLAPI address, see above.
SERPEL_TOKENAPI token. Takes precedence over a stored token and is never stored.
SERPEL_CONFIG_DIRUse another directory for the config file and the credentials file.
SERPEL_TOKEN_STORAGEauto (default: keyring, otherwise file), keyring or file.
SERPEL_HTTP_TIMEOUTTime limit per request in seconds. Default 30. Keyword research and list refreshes get at least 120 seconds.
SERPEL_POLL_INTERVAL_MSCheck interval for --wait in milliseconds. Default 2000, minimum 50.
NO_COLOR, FORCE_COLORTurn colours off, or force them when output is not a terminal.

Where does the CLI keep your token?

  • In the system keyring when one is available: Windows Credential Manager, macOS Keychain or the Secret Service on Linux. The entry uses the service name serpel and the API address as the account.
  • Otherwise in credentials.json in the config directory, with permissions that only your account can read, and a warning. Under Windows, the permissions of your user profile protect the file.
  • The token never appears in output, not even with --verbose or --json, and the CLI does not follow redirects, so the token cannot be sent to another address.
SystemConfig file
Windows%APPDATA%\serpel\config.json
Linux and macOS$XDG_CONFIG_HOME/serpel/config.json, otherwise ~/.config/serpel/config.json

Which global flags does the CLI have?

These flags work with every command and can come before or after it.

FlagMeaning
--api-url <url>API address for this call.
--jsonMachine-readable JSON on standard output only.
--no-colorTurn colours off.
--verboseLog method, URL, status and duration of each request to standard error, without headers, bodies or the token.
-h, --helpShow help for the command.
-V, --versionShow the CLI version.

Which commands does the Serpel CLI have?

Every command accepts --help and prints its flags. Arguments such as <id> stand for IDs you get from other commands, for example serpel projects list. Commands that delete or disconnect something send nothing until you add --yes, and exit with code 2 without it.

Account and configuration

CommandWhat it does
serpel auth loginSigns in. By default it opens a browser approval (device login). --no-browser only prints the address, --token-stdin or --token <token> stores an existing API token after checking it.
serpel auth statusShows the signed-in user, permissions, project restriction, API address and where the token is stored.
serpel auth logoutRevokes the stored token on the server and deletes it locally.
serpel auth profileChanges the name (--name) or email address (--email) of your own account. Needs a token with all permissions and no project restriction.
serpel config get [api-url]Shows the configuration, or a single value.
serpel config set api-url <url>Stores the API address in the config file.
serpel config unset api-urlRemoves the stored API address.
serpel tokens listLists your API tokens with status, permissions and last use.
serpel tokens create --name <name> --scope <scope>Creates an API token. Repeat --scope for several permissions. --project <id> (repeatable) restricts the token to projects and --expires-in-days <n> (1 to 365) sets an expiry. The secret is printed once.
serpel tokens revoke <id> --yesRevokes a token immediately.

Projects

CommandWhat it does
serpel projects listLists your projects. Flags: --query (-q), --limit, --page, --offset.
serpel projects create --domain <domain>Creates a project. Optional: --name, --country (API default DE) and --language (API default de). Exit code 6 with the existing project ID if you already have a project for the domain.
serpel projects show <id>Shows the project overview: last crawl, issues, rankings, AI visibility, tasks and next steps.
serpel projects update <id>Changes the settings you pass, listed below.
serpel projects delete <id> --yesDeletes a project and cancels its running jobs. Owners only.
serpel projects members list --project <id>Lists the members and their roles.
serpel projects members add --project <id> --email <address>Adds an existing user. --role editor or viewer (API default viewer). Owners only.
serpel projects members remove <userId> --project <id> --yesRemoves a member. Owners only.

serpel projects update takes these settings. Pass only the ones you want to change.

FlagSetting
--name, --country, --languageDisplay name and market.
--location <location>Default location for new keywords: a city, postal code, location code or nationwide.
--max-pages <n>Maximum pages per crawl, 1 to 1,000.
--rank-depth <n>Result depth of rank checks: 10, 20, 30, 50, 100.
--device desktop or --device mobileDevice used for rank checks.
--schedule <schedule>, --schedule-hour <0-23>Automatic rank check: manual, daily, every_3_days or weekly, and the hour it starts.
--crawl-schedule <schedule>Automatic crawl: manual or weekly.
--render-mode <mode>JavaScript rendering during crawls: auto (only nearly empty pages), always or never.
--ai-overview on or offTrack the Google AI Overview during rank checks and AI visibility checks.
--keyword-metrics on or offAdd search volume and CPC automatically before rank checks.
--slack-webhook, --discord-webhook, --webhookWhere monitoring reports are sent. --no-slack-webhook, --no-discord-webhook and --no-webhook remove a target. --webhook takes your own https address and receives JSON.
--slack-channel, --discord-channelChannel name shown in Serpel (up to 80 characters). --no-slack-channel and --no-discord-channel remove it.

Crawls and audit

CommandWhat it does
serpel crawl start --project <id>Starts a crawl as a background job and prints the job ID. Flags: --max-pages <n> (1 to 1,000), --wait, --timeout <seconds>. If a crawl is already running, you get that one back.
serpel crawl list --project <id>Lists crawls with status, pages and audit score.
serpel crawl show <crawlId>Shows a crawl in detail: status codes, rendering, link check, Core Web Vitals status, robots.txt, sitemaps and llms.txt.
serpel crawl pages --crawl <crawlId>Lists the crawled pages. --status filters by ok, redirect, client_error, server_error, failed or blocked, --query searches URL and title.
serpel crawl page <pageId> --crawl <crawlId>Shows one page: metadata, issues, rendering, hreflang, structured data and links.
serpel crawl compare --project <id>Compares two completed crawls (--crawl, --base): score, new, resolved and changed issues. Defaults to the latest crawl and the one before it.
serpel audit issues --project <id>Lists the issues of the latest completed crawl (or --crawl) grouped by type. Filters: --severity error, warning or notice, --category, --query.
serpel audit issue <code> --project <id>Shows one issue with what was found, why it matters, how to fix it and the affected URLs.
serpel audit web-vitals <crawlId>Shows LCP, INP and CLS per URL and device, as field and lab values.

The --category filter accepts availability, redirects, meta, headings, indexing, crawling, links, images, security, content, performance, mobile, structured_data, ai_search, rendering, international, web_vitals, social.

Jobs

CommandWhat it does
serpel jobs status <jobId>Shows the status of a job. Add --wait (and --timeout <seconds>) to follow it to the end.
serpel jobs listLists jobs. Filters: --project, --status (queued, running, succeeded, failed, cancelled) and --type (crawl, rank_check, ai_check, monitoring, search_sync, analytics_sync, codebase_snapshot, recommendation_generate).
serpel jobs cancel <jobId>Cancels a queued or running job.
serpel jobs retry <jobId>Restarts a failed or cancelled job. Other jobs end with exit code 6.
serpel jobs activity --project <id>Shows the project history: jobs, emailed reports and keyword research with cost and duration. --days (1 to 90, default 7).

Keyword research and keyword lists

CommandWhat it does
serpel keywords research "<keyword>"Researches keyword ideas and uses credits. Choose exactly one mode: a keyword, --list "a,b,c", --file <path> (one keyword per line, - reads standard input) or --domain <domain>. Up to 700 keywords per request. Flags: --country, --language, --limit (1 to 500, API default 100), --project, --refresh (bypasses the cache and queries the provider again, which incurs costs), --save-to <listId>, --idempotency-key <key>.
serpel keywords historyLists saved research runs, newest first (--project, --limit).
serpel keywords research-show <runId>Shows a saved result again without a new query and without cost.
serpel keywords listsLists keyword lists (--project, --query, --limit, --page, --offset).
serpel keywords list-show <listId>Shows a list with its description and keyword count.
serpel keywords list-create --project <id> --name <name>Creates a list. Optional --description.
serpel keywords list-update <listId>Renames a list or changes the description (--name, --description, --no-description). list-rename is an alias.
serpel keywords list-delete <listId> --yesDeletes a list with all its keywords.
serpel keywords items <listId>Shows the keywords of a list. --sort takes keyword, volume, difficulty, cpc or created.
serpel keywords items-add <listId> --keyword <keyword>Adds keywords. Repeat --keyword, or add --research-run <runId> to take the metrics from a saved run. A list holds up to 5,000 keywords.
serpel keywords items-remove <listId> <itemId> --yesRemoves one keyword. The item ID is the ID column of keywords items.
serpel keywords import <listId> --file <csv>Imports a CSV file of at most 2 MB (- reads standard input). Optional --country and --language.
serpel keywords refresh <listId>Fetches the metrics of all keywords in a list again. Uses credits. Optional --idempotency-key.

Rankings and competitors

CommandWhat it does
serpel rankings add --project <id> --keyword <keyword>Adds keywords to rank tracking. Repeat --keyword. Optional --device, --country, --language, --location.
serpel rankings run --project <id>Starts a rank check for all or selected keywords (--keyword-id, repeatable) as a background job. Uses credits. Supports --wait and --timeout.
serpel rankings list --project <id>Lists tracked keywords with position, change, URL, AI Overview status and check time.
serpel rankings history <keywordId>Shows the position history of a keyword (--limit 1 to 365, default 90).
serpel rankings serp <keywordId>Shows the stored Google results of the last check (--limit 1 to 100, default 10).
serpel rankings summary --project <id>Shows top 3, top 10, average position and changes for all tracked keywords.
serpel rankings locations <query>Searches locations for local rank tracking (--country, --limit).
serpel rankings remove <keywordId> --yesRemoves a keyword and its history.
serpel competitors list --project <id>Lists competitors with visibility, top 10 keywords and estimated clicks.
serpel competitors compare --project <id>Compares your position with each competitor, keyword by keyword.
serpel competitors suggest --project <id>Suggests domains that often appear in the top 20 for your keywords.
serpel competitors add --project <id> --domain <domain>Adds a competitor, up to 10 per project.
serpel competitors remove --project <id> --domain <domain>Removes a competitor by domain or ID.

AI visibility

CommandWhat it does
serpel ai add --project <id> --prompt <prompt>Adds prompts the way users ask them of an AI. Repeat --prompt. --platform currently accepts chat_gpt only. Optional --country and --language.
serpel ai prompts --project <id>Lists prompts with the latest result: cited, mentioned, Google AI Overview and check time.
serpel ai run --project <id>Checks all or selected prompts (--prompt-id, repeatable) as a background job. Uses credits. Supports --wait and --timeout.
serpel ai history <promptId>Shows the history of a prompt for ChatGPT and the Google AI Overview (--limit 1 to 365, default 60).
serpel ai status --project <id>Shows citations, mentions, the most frequent sources, AI crawler access in robots.txt and llms.txt.
serpel ai remove <promptId> --yesRemoves a prompt with all its results.

Monitoring and reports

CommandWhat it does
serpel monitoring run --project <id>Checks rankings and AI visibility now, compares with the last report and creates a new report. Uses credits. Supports --wait and --timeout.
serpel monitoring webhook-test --project <id>Sends a test message to the configured webhooks. --channel limits it to slack, discord or custom.
serpel monitoring recipients list --project <id>Lists the email recipients of the reports.
serpel monitoring recipients add --project <id> --email <address>Adds a recipient, up to 10 per project.
serpel monitoring recipients remove --project <id> --email <address>Removes a recipient by address or ID.
serpel monitoring email-test --project <id>Sends the latest report as a test email to all recipients, or to one with --email.
serpel reports listLists reports, newest first (--project, --unread, --limit, --page, --offset).
serpel reports show <id>Shows a report with rankings, AI visibility and website audit. Does not mark it as read.
serpel reports read <id>Marks a report as read.
serpel reports read-allMarks all reports as read, or those of --project.
serpel reports unreadShows the number of unread reports.
serpel reports send <reportId>Sends a report again to all active recipients.
serpel reports preview <reportId>Shows the email of a report, or saves it as HTML with --output <file> and opens it with --open.

Search data, web analytics and integrations

API keys for Bing, PostHog and Plausible are read from a file with --api-key-file <path>, or from standard input with -. They are never passed as an argument and never printed. Google connections open a browser approval; --no-open only prints the address.

CommandWhat it does
serpel search status --project <id>Shows the Google Search Console and Bing Webmaster Tools connections of a project.
serpel search connect-google --project <id>Creates an authorisation address (valid for ten minutes) and opens it. Confirm it with the account that created the token.
serpel search connect-bing --project <id> --api-key-file <path>Connects Bing Webmaster Tools. Optional --site-url.
serpel search site --project <id> --provider <provider> --site-url <url>Chooses the property of a connection. --provider is google or bing.
serpel search queries --project <id>Shows clicks, impressions, CTR and position. Flags: --provider google or bing, --dimension query or page, --days 7, 28 or 90, --limit (1 to 500, default 50).
serpel search disconnect --project <id> --provider <provider> --yesDeletes the stored credentials of a connection.
serpel analytics status --project <id>Shows which of PostHog, Plausible and Google Analytics 4 are connected.
serpel analytics report --project <id>Shows visitors, sessions, pageviews, bounce rate, top pages, entry pages, sources and devices. Flags: --provider, --days 7, 28 or 90, --daily.
serpel analytics connect-posthog --project <id> --posthog-project <id> --api-key-file <path>Connects PostHog. --region eu or us, or --host <url> for your own instance.
serpel analytics connect-plausible --project <id> --site-id <domain> --api-key-file <path>Connects Plausible. Optional --host <url> for your own instance.
serpel analytics connect-google --project <id>Connects Google Analytics 4 in the browser.
serpel analytics property --project <id> --property-id <id>Chooses the Google Analytics property.
serpel analytics properties --project <id>Lists the Google Analytics properties with their domains. --refresh reloads them from Google.
serpel analytics disconnect --project <id> --provider <provider> --yesDeletes the stored credentials of a connection.
serpel integrations statusShows account integrations and how they map to your projects (--details per project).
serpel integrations connect-googleConnects Google Search Console and Google Analytics for all projects.
serpel integrations connect-bing --api-key-file <path>Connects Bing Webmaster Tools for all projects.
serpel integrations connect-posthog --api-key-file <path>Connects PostHog for all projects (--region, --host).
serpel integrations connect-plausible --api-key-file <path>Connects Plausible for all projects (--host).
serpel integrations sync --provider <integration>Maps projects again, for example after new properties. --provider is google, bing, posthog or plausible.
serpel integrations disconnect --provider <integration> --yesDisconnects an integration. Connected projects lose its data.

Tasks and recommendations

CommandWhat it does
serpel tasks list --project <id>Lists tasks. Filters: --status open, in_progress or done, --priority high, medium or low, --query.
serpel tasks create --project <id> --title <title>Creates a task. Optional --priority, --description and --url (repeatable).
serpel tasks create --project <id> --issue <code>Creates a task from an audit issue and carries over the affected URLs. --crawl picks the crawl, default is the last completed one.
serpel tasks update <taskId>Changes --status, --priority, --title or --description.
serpel tasks show <taskId>Shows a task with its URLs and the result of the recheck after the latest crawl.
serpel tasks delete <taskId> --yesDeletes a task.
serpel recommendations list --project <id>Lists recommendations (alias serpel recs). --status takes open, accepted, dismissed, done, stale or active, --rule filters by rule, --query searches.
serpel recommendations show <id>Shows a recommendation with evidence, data sources and the next action.
serpel recommendations accept <id>Accepts a recommendation. dismiss, done and reopen work the same way.

Codebase scan

serpel scan [directory] reads a Next.js project, builds a snapshot of its routes and metadata and uploads it to a project. Serpel then matches routes to crawled pages and search data and flags differences between code and live site. The snapshot contains no source code. The upload is free and needs the codebase:write scope.

FlagMeaning
[directory]The folder with the package.json of the Next.js app. Defaults to the current folder. In a monorepo, pass the subfolder, for example apps/web.
--project <id>The project the snapshot belongs to. Required unless you use --dry-run.
--dry-runSends nothing and needs no sign-in. The snapshot goes to standard output, or to --out.
--out <file>Writes the snapshot as JSON to a file.
--include-textAlso sends a text excerpt of at most 500 characters per page, only for routes with build output.
--yesSkips the confirmation before sending. Without a terminal and without --yes, the command exits with code 2.
--wait, --timeout <seconds>Waits until Serpel has processed the snapshot.

The CLI never reads or sends .env files, key files, node_modules, .git or anything your .gitignore excludes, and it removes values that look like credentials. Limits: 2,000 routes, 5,000 sitemap URLs, 2 MB of JSON and 20 uploads per project and day. Answering anything but yes to the confirmation prompt ends the command with exit code 130.

Terminal
serpel scan --dry-run
serpel scan apps/web --dry-run --out snapshot.json
serpel scan --project "$PROJECT_ID" --wait
serpel scan apps/web --project "$PROJECT_ID" --yes --include-text

Export

serpel export --project <id> --type <type> exports issues, keywords, rankings or tasks. --format is csv (default) or json. Without --output <file> (-o), the file content goes to standard output so you can redirect it. --crawl <id> applies to issues (default: the last completed crawl) and --list <id> to keywords.

Terminal
serpel export --project "$PROJECT_ID" --type issues --format csv --output issues.csv
serpel export --project "$PROJECT_ID" --type rankings --format json > rankings.json

Billing, agents and providers

CommandWhat it does
serpel billing balanceShows available, total and reserved credits, usage today and in the last 30 days, and a forecast of how long the balance lasts.
serpel billing estimate --operation <operation>Estimates the cost of an operation and books nothing. Operations: rankCheck, aiCheck, keywordResearch, keywordListRefresh, keywordMetrics, crawl, monitoring. Inputs: --keywords, --depth, --prompts, --no-ai-overview, --scheduled, --mode, --limit, --tasks, --max-pages.
serpel billing historyLists credit transactions (--limit, --page, --offset).
serpel billing planShows your plan, limits and subscription.
serpel billing top-upOpens Stripe Checkout for a credit top-up. --package credits500, credits1000, credits2500 or credits5000, or --amount <cents>. --no-open only prints the address.
serpel billing subscribe --plan <plan>Opens Stripe Checkout for starter or pro.
serpel billing change-plan --plan <plan>Changes the plan. Upgrades apply immediately, downgrades at the end of the billing period.
serpel billing cancel, serpel billing resumeCancels the subscription at the end of the billing period, or withdraws the cancellation.
serpel billing portalOpens the Stripe customer portal for payment details and invoices.
serpel agents statusShows whether agents may spend credits, the daily limit and today’s usage.
serpel agents allowAllows agents to spend credits through the MCP server. Needs the Starter or Pro plan. --daily-limit <credits> sets the limit at the same time.
serpel agents denyStops agents from spending credits.
serpel agents daily-limit <credits>Sets the daily limit for agents. --reset restores the default.
serpel providers statusShows the data providers, whether they are configured, daily budget and usage, and when each was last used.

Top-ups, plan changes and the agent settings need the workspace owner role.

Which permissions do the commands need?

A token can only run commands whose scope it has. Without the scope, the API answers with HTTP 403 and the CLI exits with code 4. The REST API reference lists every scope.

CommandsScopes
projects (read), reports (list, show, read, preview), search, analytics and integrations (status and reports), monitoring recipients listprojects:read
projects (create, update, delete, members), connect and disconnect commands, monitoring webhook-test, monitoring recipients add and remove, monitoring email-test, reports sendprojects:write
crawl (list, show, pages, page, compare), auditaudit:read
crawl startaudit:write
rankings (list, history, serp, summary, locations), competitors (list, compare, suggest), ai (prompts, history, status)rankings:read
rankings (add, run, remove), competitors (add, remove), ai (add, run, remove), monitoring runrankings:write
keywords (history, research-show, lists, list-show, items)keywords:read
keywords (research, list-create, list-update, list-delete, items-add, items-remove, import, refresh)keywords:write
jobs (status, list)audit:read for crawls, rankings:read for rank checks, AI checks and monitoring runs
jobs (cancel, retry)audit:write for crawls, rankings:write for the other jobs
tasks (list, show)tasks:read
tasks (create, update, delete)tasks:write
recommendations (list, show)recommendations:read
recommendations (accept, dismiss, done, reopen)recommendations:write
scancodebase:write
exportexport:read
billing (balance, estimate, history, plan), agents statusbilling:read
billing (top-up, subscribe, change-plan, cancel, resume, portal), agents (allow, deny, daily-limit)billing:write
providers statusAny valid token.
tokens, auth profileA token with all permissions. A token restricted to projects can only create tokens for its own projects.

How do you wait for background jobs?

Crawls, rank checks, AI visibility checks and monitoring runs run in a worker. crawl start, rankings run, ai run and monitoring run print the job ID and return. With --wait, the CLI checks the job every two seconds until it succeeds, fails or is cancelled, and then prints a summary. --timeout <seconds> limits the wait and only works with --wait. jobs status <jobId> --wait follows a job you started earlier.

  • If the job fails or is cancelled, the CLI exits with code 8 and prints the last error.
  • If --timeout is reached, the CLI exits with code 10. The job keeps running on the server.
  • Ctrl+C stops waiting and exits with code 130. The job keeps running.
  • Short network errors while waiting are retried up to three times.
  • SERPEL_POLL_INTERVAL_MS changes the check interval.
Terminal
serpel crawl start --project "$PROJECT_ID" --wait --timeout 900
serpel jobs status "$JOB_ID" --wait

How does pagination work?

List commands accept --limit <n> (1 to 200, default 50) and either --page <n> (from 1) or --offset <n>. When more entries exist, the CLI prints the range and the flags for the next page on standard error. With --json, the total is in pagination.total.

How do you use JSON output in scripts?

With --json, the CLI writes only JSON to standard output. Hints, warnings and progress go to standard error, and colours are off. Lists come as { "data": [...], "pagination": { "limit", "offset", "total" } }. Single objects and actions return the object itself. Errors are printed to standard output as an object and set the exit code.

Error output with --json
{
  "error": {
    "code": "not_logged_in",
    "message": "Not signed in to https://serpel.app."
  }
}

API errors keep the code of the API, such as validation_error or unauthorized. Local errors use their own codes: usage_error, not_logged_in, network_error, timeout, job_failed, job_cancelled, wait_timeout, interrupted and webhook_failed. Some errors add a details field.

Terminal
serpel projects list --json | jq -r '.data[] | "\(.id) \(.domain)"'
PROJECT_ID=$(serpel projects list --json | jq -r '.data[] | select(.domain == "example.com") | .id')
JOB_ID=$(serpel crawl start --project "$PROJECT_ID" --json | jq -r .job.id)

What do the exit codes mean?

CodeMeaning
0Success.
1Unexpected error, HTTP 500 internal_error, an invalid API response, or a webhook test message that was not delivered (webhook_failed).
2Usage error such as an unknown flag, a missing argument or an invalid value, or validation_error and bad_request from the API. Also a destructive command without --yes.
3Not signed in, HTTP 401, or a device login that expired or was denied.
4HTTP 403: a missing scope, no access to the project, or token management with a restricted token.
5HTTP 404: not found.
6HTTP 409 conflict, such as a project that already exists or jobs retry on a running job. Also HTTP 402 insufficient_credits.
7Provider problem: HTTP 429 (rate_limited, budget_exceeded), 502 (provider_error) or 503 (provider_not_configured).
8A job failed or was cancelled while waiting with --wait.
9The API is not reachable: connection error, DNS, TLS, request timeout or an unexpected redirect.
10The --wait --timeout limit was reached. The job keeps running.
130Interrupted with Ctrl+C, or any answer but yes to the scan confirmation.

How do you run the CLI in GitHub Actions?

Create a token with only the scopes the job needs, restrict it to one project and store it as the repository secret SERPEL_TOKEN. The CLI reads that variable on every run and never stores it.

Create a CI token
serpel tokens create --name "GitHub Actions" --scope projects:read --scope audit:read --scope audit:write --project "$PROJECT_ID" --expires-in-days 90

The workflow below crawls the site every Monday, waits for the crawl and fails when the latest crawl contains errors. The install step pulls @serpel/cli from npm; pin a version such as @serpel/cli@0.1.0 if you want reproducible builds.

.github/workflows/serpelCrawl.yml
name: Serpel crawl
on:
  schedule:
    - cron: "0 6 * * 1"
  workflow_dispatch:
jobs:
  crawl:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - name: Install the Serpel CLI
        run: npm install -g @serpel/cli
      - name: Crawl the site and fail on errors
        env:
          SERPEL_TOKEN: ${{ secrets.SERPEL_TOKEN }}
          SERPEL_PROJECT_ID: ${{ vars.SERPEL_PROJECT_ID }}
        run: |
          serpel crawl start --project "$SERPEL_PROJECT_ID" --wait --timeout 900
          serpel audit issues --project "$SERPEL_PROJECT_ID" --json > issues.json
          jq -e '.counts.error == 0' issues.json

How do you troubleshoot the CLI?

  • --verbose prints the method, URL, status and duration of every request to standard error, without headers, bodies or the token.
  • serpel config get shows which API address applies and where it comes from.
  • “Endpoint not found (HTTP 404)” or “The API response is not valid JSON” usually means a wrong API address. Run serpel config get and check --api-url and SERPEL_API_URL.
  • If the system keyring is not available, for example on Linux without a running Secret Service, the CLI stores the token in credentials.json and prints a warning.
  • Exit code 3 means the token is missing, invalid, expired or revoked. Sign in again or create a new token.

Updated 10 Oct 2026

See also