Skip to content

Output and exit codes

What a person reads and what a script reads come out of the same command. This page is the contract between them.

Formats

--format human (the default), --format json, --format csv. All three carry the same content: a command never reaches for JSON directly, so asking for CSV cannot silently return JSON.

Two things sit outside the payload deliberately. A failure is always a JSON envelope in a machine format, because an error is not tabular. And facts about how to read the numbers, the period the server resolved, that a window overlaps imported data, that more rows exist, go to stderr in every format, so a pipeline stays clean:

statable top pages --format csv > pages.csv     # stdout is only the table
statable stats --json | jq '.visitors'

Numbers are numbers in JSON, not strings, so jq '.visitors + 1' works. Geographic breakdowns answer twice: a person sees United States, a script gets US, because the code is exactly what the matching filter accepts.

Exit codes

The exit code is the answer, so a script does not have to parse anything.

CodeMeaning
0Success
1Action required; next_steps names the fix
2The operation failed
3statable check ran and the metric was outside its bounds
64The command line itself was malformed. Nothing was sent
130Interrupted

64 covers every mistake caught before a request exists: an unknown metric, a filter with no operator, a range that is not a range. Repeating the command unchanged will fail identically, which is exactly what 2 must not be confused with.

Errors

Failures carry a stable code. Prose may be reworded at any time; codes may not. See Errors for the full list.

{
  "status": "action_required",
  "error": "no API key is configured",
  "issues": [{"code": "NOT_AUTHENTICATED", "message": "no API key is configured"}],
  "next_steps": ["statable auth login"]
}

On a 429 the CLI reads X-RateLimit-Reset and tells you when to try again rather than guessing. See Rate limits.

In CI

statable check --metric visitors --range 7d --min 100
statable check --metric bounce_rate --max 60

Exit 3 means the number was outside its bounds; 1 and 2 mean the check could not run at all. That separation is the point: a pipeline can tell "traffic dropped" from "the tool is broken".

A rate can be null when it is undefined for the window. check refuses to judge that rather than treating it as zero.

Set the key in the environment, never with --key, and the run leaves nothing behind:

env:
  STATABLE_API_KEY: ${{ secrets.STATABLE_API_KEY }}

Ready to take control of your web analytics? Try Statable free for 30 days. No credit card required, full feature access, built for GDPR. Start your free trial or view a live demo.