# Crash reports and usage stats

> Two optional switches, both off until you turn them on: what each one sends, every field, and how to turn them off.

Dobby asks two questions during `dobby init`: crash reports and usage stats. Pressing Enter answers no, `--yes` answers no, and no answer is off. They exist to show where installs stop in setup, what gets used and what breaks, without anything private leaving your machine.

## Turn them on or off

- `dobby stats` shows the status. `dobby stats on` or `dobby stats off` changes both; add `crashes` or `usage` to change one.
- `dobby stats show` prints exactly the usage payload the next daily send would carry.
- `dobby stats log` prints every payload that left this machine; the same lines are in `<data>/stats/sent.jsonl`.
- `dobby stats reset-id` makes a new random install id.
- The Settings page in the dashboard has the same two switches.
- Nothing is sent when `DO_NOT_TRACK` is set, when `DOBBY_STATS=off`, or when `CI` is set, whatever the switches say.
- Nothing is sent while `stats.endpoint` is empty.

## What is sent

Crash reports are sent when an unexpected error happens, at most 10 a day. An expected refusal (a typo in a command, a missing ticket) is not a crash. Usage stats are one batch a day at most, sent by the background tick job.

### every event

Added to every event below.

| Field | Values | Meaning |
| --- | --- | --- |
| `install` | text | random id made when you said yes; `dobby stats reset-id` makes a new one |
| `v` | text | Dobby version |
| `os` | darwin \| linux | operating system |
| `node` | number | Node major version |
| `day` | text | UTC date, no time |

### setup_started

Sent: once, when `dobby init` starts (usage stats).

### setup_step

Sent: once per setup step (usage stats).

| Field | Values | Meaning |
| --- | --- | --- |
| `props.step` | checks \| repos \| chat \| tools \| settings \| jobs \| first_ticket | which setup step |
| `props.ok` | true \| false | whether it passed |
| `props.reason` | gh_missing \| gh_signed_out \| claude_missing \| claude_signed_out \| git_missing \| node_old \| no_repos \| tests_failed \| skipped \| other | why it did not pass, from a fixed list |

### setup_done

Sent: once, when `dobby init` finishes (usage stats).

### first_ticket

Sent: once, the first time a ticket exists (usage stats).

### first_pr

Sent: once, the first time a ticket has a pull request (usage stats).

### first_merge

Sent: once, the first time a ticket has merged (usage stats).

### first_week_report

Sent: once, the first time the 7-day scoreboard or receipt was read (usage stats).

### setup_help

Sent: once, the first time you click Ask Claude in setup (usage stats).

| Field | Values | Meaning |
| --- | --- | --- |
| `props.kind` | no-commands \| verify-failed \| check | what the help was asked about: a repo with no commands, a repo that failed to verify, or a failed machine check |
| `props.ok` | true \| false | whether Claude gave an answer that could be read |

### heartbeat

Sent: at most once a day (usage stats).

| Field | Values | Meaning |
| --- | --- | --- |
| `props.plan` | pro \| max \| max20 \| api \| unknown | your Claude plan, from billing.planUsd (20 pro, 100 max, 200 max20) or api in API-key mode |
| `props.projects` | 0 \| 1 \| 2-3 \| 4+ | how many projects, as a range |
| `props.shipped` | 0 \| 1-2 \| 3-5 \| 6+ | tickets shipped in the last 24 hours, as a range |
| `props.sent_back` | 0 \| <25 \| 25-50 \| 50+ | share of pull requests the reviewer sent back in the last 7 days, in percent, as a range |
| `props.safety` | strict \| balanced \| autonomous | safety.preset |
| `props.review_auto` | off \| drafts \| on | review.auto |
| `props.merges_paused` | true \| false | whether merging is paused |
| `props.chat` | terminal \| discord | where Dobby asks you things |
| `props.week_cap` | number | pacing.weekCap, rounded down to a multiple of 10 |
| `props.week_used` | number | absent when no reading exists |
| `props.features` | object | which of these were used in the last 24 hours: dashboard, mcp_stdio, mcp_http, discord_buttons, brief_sent, deploy_tap, role_override, config_set |
| `props.roles` | object | runs per role in the last 24 hours, as a range; only roles that ran |

### crash

Sent: when Dobby fails with an unexpected error, at most 10 a day (crash reports).

| Field | Values | Meaning |
| --- | --- | --- |
| `props.kind` | text | the error's class name, like TypeError |
| `props.where` | list of text | file:line of frames inside Dobby's own package, paths relative to the package; other frames are dropped |
| `props.command` | text | the dobby subcommand or job that failed |
| `props.code` | text | Dobby's own error code, if the error had one |

## Never sent

Repo or project names, paths, ticket or pull request titles or text, prompts, model output, code, URLs, GitHub or Discord usernames, emails, hostnames, tokens, error messages and exact times. The collector stores no IP address.

## The collector

It is a small Cloudflare Worker with a D1 database on the owner's own account (`stats-worker/` in the code folder). It checks every event against the same list as this page and refuses anything else. Rows older than 180 days are deleted every day.
