Anonymous telemetry
SEO sends small anonymous usage events so the project can count installs, completed setup and audits, retention, agent usage, and report popularity.
Your SEO data stays on your machine. Telemetry never contains an identifier that could link events to a person or machine.
See the same aggregate data as the maintainer on the public usage stats page.
First run notice
This notice is shown before the first event is sent.
The notice shown before anonymous telemetry starts.
SEO Skill collects anonymous usage data to improve the tool (event name,
report id, version, agent, OS, architecture, Node major, and install week;
never URLs, report data, or identifiers of any kind).
Docs: https://seoskill.dev/telemetry
Disable: seo telemetry disable (or set DO_NOT_TRACK=1)Every event
| Event name | When it is sent | Frequency |
|---|---|---|
first_run | The first invocation that creates local telemetry state. | Once per local install. |
setup_complete | A non-dry-run guided setup finishes successfully. | Once per local install. |
audit_start | A recognised report starts through the CLI or MCP server. | Every report run. |
audit_complete | A recognised report finishes successfully. | Every successful report run. |
audit_failed | A recognised report fails. It includes only a fixed errorCategory. | Every failed report run. |
first_audit_complete | The first recognised report finishes successfully. | Once per local install. |
active_d1 | An invocation happens at least one day after the first run. | Once per local install. |
active_d7 | An invocation happens at least seven days after the first run. | Once per local install. |
active_d30 | An invocation happens at least 30 days after the first run. | Once per local install. |
Every field sent
| Field | Value |
|---|---|
event | One event name from the table above. |
version | The installed seo package version, such as 0.2.5. |
agent | claude-code | cursor | codex | cli | unknown. MCP uses the client name from its standard initialize handshake, then discards the original name. |
os | aix | android | darwin | freebsd | haiku | linux | openbsd | sunos | win32. |
arch | arm | arm64 | ia32 | loong64 | mips | mipsel | ppc | ppc64 | riscv64 | s390 | s390x | x64. |
node | The Node.js major version as a string, such as 22. |
cohort | The ISO week of the first run, such as 2026-W29. The exact first-run time never leaves local state. |
schema | The integer wire schema version. The current value is 1. |
errorCategory | Sent only with audit_failed. One of auth | crawl_timeout | network | config | unknown. Raw errors are never sent. |
report | Sent only with report lifecycle events. It is one fixed public report identifier from the list below, never a URL or user-supplied string. |
A successful report completion event.
{
"event": "audit_complete",
"version": "0.2.5",
"agent": "codex",
"os": "darwin",
"arch": "arm64",
"node": "22",
"cohort": "2026-W29",
"schema": 1,
"report": "site-crawl"
}Never collected or transmitted
- User IDs, machine IDs, UUIDs, advertising IDs, or fingerprints of any kind.
- Audited domains, URLs, hostnames, page content, search queries, or crawl results.
- Report findings, recommendations, scores, exports, or other report content.
- Google Search Console or Google Analytics responses, property IDs, account data, or metrics.
- API keys, OAuth tokens, secrets, file paths, usernames, local hostnames, or raw error messages.
- IP addresses in D1, Worker logs, application storage, or the public stats response.
- Country, region, city, coordinates, or any other location data.
How to disable it
The local command is the simplest permanent setting. Environment settings can disable every telemetry network call without changing the saved preference.
Change or check the saved telemetry setting.
seo telemetry disable
seo telemetry status
seo telemetry enableDisable telemetry for the current environment.
DO_NOT_TRACK=1
SEOSKILL_TELEMETRY_DISABLED=1
SEO_TELEMETRY_DISABLED=1Telemetry is also disabled when CI=true or a common CI environment variable is present, including GitHub Actions, GitLab CI, CircleCI, Travis CI, Buildkite, Jenkins, TeamCity, Azure Pipelines, Bitbucket Pipelines, and AWS CodeBuild. An environment override wins over seo telemetry enable.
Local state
The memory needed for once-only events stays in telemetry.json inside the existing SEO config directory. Run seo telemetry status --json to see the exact path on your platform. The file contains only these fields.
The complete local telemetry state file.
{
"telemetryEnabled": true,
"firstRunAt": "2026-07-16T09:12:00.000Z",
"cohort": "2026-W29",
"sentMilestones": ["first_run", "first_audit_complete", "active_d1"]
}firstRunAt is used only on your machine to decide when a retention milestone is due. Only its week-level cohort is sent. Clearing all local SEO state means a later run is counted as a new install because the server has no identity to recognise it.
Transport and storage
Each event is one JSON POST to https://seoskill.dev/api/t. The sender has a two-second timeout, does not batch or retry, silently drops failures, and never changes command output or exit status.
The Cloudflare Worker accepts only the fields and fixed values documented above. Unknown fields or values are rejected. It writes those values to a dedicated D1 table through a Worker binding. The server adds only the UTC receipt month, such as 2026-07, for monthly totals. It does not store the exact request time. There is no account or identity column, and no telemetry KV, R2, or Analytics Engine dataset. Worker invocation logs are disabled, and the code never readsrequest.cf, IP headers, or location fields. Cloudflare handles the ordinary network request at the edge, but no IP address or geography is written to D1.
D1 keeps the accepted anonymous events until they are deliberately deleted. Public totals cover all events recorded since collection began. Only aggregate counts are returned by the public stats endpoint.