18 KiB
jcode Telemetry
jcode collects anonymous, minimal usage statistics to help understand how many people use jcode, what providers/models are popular, whether onboarding works, which feature families are used, how often sessions succeed, and whether performance/regressions are improving. This data helps prioritize development without collecting prompts or code.
Recent telemetry additions also include: coarse onboarding steps, explicit thumbs-up / thumbs-down feedback, build-channel / dev-mode cleanup flags, session/workflow/tool-category summaries, coarse project language buckets, retention helpers like active days in the last 7 / 30 days, workflow cadence fields for session timing and multi-sessioning, privacy-safe per-turn timing/outcome metrics, and schema v5 agent-time / autonomy / pain-attribution metrics.
What We Collect
Install Event (sent once, on first launch)
| Field | Example | Purpose |
|---|---|---|
id |
a1b2c3d4-... |
Random UUID, not tied to your identity |
event |
"install" |
Event type |
version |
"0.6.0" |
jcode version |
os |
"linux" |
Operating system |
arch |
"x86_64" |
CPU architecture |
Upgrade Event
| Field | Example | Purpose |
|---|---|---|
id |
a1b2c3d4-... |
Same random UUID |
event |
"upgrade" |
Event type |
version |
"0.9.1" |
Current jcode version |
from_version |
"0.8.1" |
Previously recorded jcode version |
os / arch |
"linux" / "x86_64" |
Environment breakdown |
Auth Success Event
| Field | Example | Purpose |
|---|---|---|
id |
a1b2c3d4-... |
Same random UUID |
event |
"auth_success" |
Event type |
auth_provider |
"claude" |
Which provider/account system was configured |
auth_method |
"oauth" |
Coarse auth method only |
version / os / arch |
"0.9.1" / "linux" / "x86_64" |
Activation funnel dimensions |
Onboarding Step Event
| Field | Example | Purpose |
|---|---|---|
event |
"onboarding_step" |
Event type |
step |
"first_prompt_sent" |
Coarse funnel step |
auth_provider |
"openai" |
Optional provider dimension for auth steps |
auth_method |
"oauth" |
Optional auth-method dimension for auth steps |
milestone_elapsed_ms |
42000 |
Rough time from install to milestone |
Feedback Event
| Field | Example | Purpose |
|---|---|---|
event |
"feedback" |
Event type |
feedback_text |
"The model switcher is confusing" |
Freeform feedback explicitly submitted with /feedback ... |
feedback_rating |
"up" / "down" |
Legacy explicit product sentiment, if present |
feedback_reason |
"slow" |
Legacy optional coarse reason bucket, if present |
Sponsored Discovery Event
One event is sent after each discover_tools attempt. A random per-request ID
is also sent to the discovery API as the x-jcode-discovery-request-id header,
allowing client reliability telemetry to be correlated with server request logs
without exposing prompts or a persistent telemetry identifier to that service.
| Field | Example | Purpose |
|---|---|---|
event |
"discovery" |
Event type |
request_id |
"9a23..." |
Random correlation ID scoped to one request |
phase |
"browse" / "select" / "unknown" |
Discovery funnel stage |
category |
"payments" |
Fixed discovery category, when valid |
selected_tool |
"agentcard" |
Public catalog tool name in the select phase |
outcome |
"success" / "failure" |
Attempt result |
failure_reason |
"timeout" |
Allowlisted coarse failure class only |
http_status |
200 |
Discovery service response status, if received |
latency_ms |
125 |
End-to-end client attempt latency |
response_bytes |
2048 |
Response payload size, if received |
result_count |
3 |
Number of browse results, or one for selection |
query_present / reason_present |
true / true |
Presence flags only |
custom_endpoint |
false |
Whether a non-default discovery endpoint was configured |
The query text, selection-reason text, endpoint URL, prompts, transcript, file paths, and tool setup instructions are not included in telemetry. The backend rejects unknown phase, outcome, and failure labels rather than storing arbitrary strings.
Session Start Event
| Field | Example | Purpose |
|---|---|---|
id |
a1b2c3d4-... |
Same random UUID |
event |
"session_start" |
Event type |
version |
"0.6.0" |
jcode version |
os |
"linux" |
Operating system |
arch |
"x86_64" |
CPU architecture |
provider_start |
"OpenAI" |
Provider when session started |
model_start |
"gpt-5.4" |
Model when session started |
resumed_session |
false |
Whether this was a resumed session |
session_start_hour_utc |
13 |
Coarse hour-of-day bucket for workflow timing |
session_start_weekday_utc |
2 |
Weekday bucket for usage cadence |
previous_session_gap_secs |
3600 |
How long since this install's previous session |
sessions_started_24h / sessions_started_7d |
3 / 8 |
How bursty a user's workflow is recently |
active_sessions_at_start |
2 |
Concurrent sessions observed including this one |
other_active_sessions_at_start |
1 |
Other sessions already open when this started |
Session End / Crash Event
| Field | Example | Purpose |
|---|---|---|
id |
a1b2c3d4-... |
Same random UUID |
event |
"session_end" / "session_crash" |
Event type |
version |
"0.6.0" |
jcode version |
os |
"linux" |
Operating system |
arch |
"x86_64" |
CPU architecture |
provider_start |
"OpenAI" |
Provider when session started |
provider_end |
"OpenAI" |
Provider when session ended |
model_start |
"gpt-5.4" |
Model when session started |
model_end |
"gpt-5.4" |
Model when session ended |
provider_switches |
0 |
How many times you switched providers |
model_switches |
1 |
How many times you switched models |
duration_mins |
45 |
Session length in minutes |
duration_secs |
2700 |
Finer-grained session length |
turns |
23 |
Number of user prompts sent |
had_user_prompt |
true |
Whether any real prompt was submitted |
had_assistant_response |
true |
Whether the assistant produced a response |
assistant_responses |
6 |
Number of assistant responses |
first_assistant_response_ms |
1200 |
Time to first assistant response |
first_tool_call_ms |
900 |
Time to first tool invocation |
first_tool_success_ms |
1500 |
Time to first successful tool execution |
first_file_edit_ms |
2200 |
Time to first successful file edit |
first_test_pass_ms |
4100 |
Time to first successful test run |
tool_calls |
8 |
Number of tool executions |
tool_failures |
1 |
Number of tool execution failures |
executed_tool_calls |
10 |
Centralized count of actual registry tool executions |
executed_tool_successes |
9 |
Successful registry tool executions |
executed_tool_failures |
1 |
Failed registry tool executions |
tool_latency_total_ms |
4200 |
Aggregate tool execution latency |
tool_latency_max_ms |
1800 |
Slowest single tool call |
file_write_calls |
2 |
Count of write/edit/patch style tool uses |
tests_run |
1 |
Coarse count of test runs triggered |
tests_passed |
1 |
Coarse count of successful test runs |
input_tokens / output_tokens |
12345 / 678 |
Session-level provider-reported token usage totals |
cache_read_input_tokens / cache_creation_input_tokens |
9000 / 1200 |
Session-level provider-reported prompt-cache token totals when available |
total_tokens |
23223 |
Sum of input, output, cache-read, and cache-creation tokens |
feature_*_used |
true/false |
Whether a feature family was used (memory, swarm, web, email, MCP, side panel, goals, selfdev, background, subagents) |
tool_cat_* |
0..N |
Coarse tool category counts (read/search, write, shell, web, memory, subagent, swarm, email, side-panel, goal, MCP, other) |
command_*_used |
true/false |
Whether a slash-command family was used in-session |
workflow_*_used |
true/false |
Whether the session looked like coding, research, testing, background, subagent, or swarm work |
unique_mcp_servers |
2 |
Count of distinct MCP servers touched in-session |
session_success |
true |
Coarse success proxy based on outcomes like responses, successful tools, tests, or edits |
abandoned_before_response |
false |
Whether the user engaged but got no successful outcome before ending |
session_stop_reason |
"tool_error_loop" |
Coarse inferred pain/churn bucket, such as crash, auth blocked, rate limited, no first response, too slow, tool failures, no useful action, or completed successfully |
agent_role |
"foreground" / "subagent" |
Coarse role classification for the session: foreground, background, subagent, or swarm |
parent_session_id |
"session_..." |
Optional parent session ID for attributing spawned/background/subagent work to the initiating session |
agent_active_ms_total |
7200000 |
Sum of active agent time across finalized turns; two agents active for two hours count as four agent-hours in aggregate |
agent_model_ms_total / agent_tool_ms_total |
5400000 / 1800000 |
Approximate active-time split between model/agent thinking and registry tool execution latency |
session_idle_ms_total |
300000 |
Time around turns where the session was open but no agent activity was observed |
time_to_first_agent_action_ms |
900 |
Time from session start to the first assistant response or tool action |
time_to_first_useful_action_ms |
1500 |
Time from session start to the first successful tool/file/test outcome, falling back to first response |
spawned_agent_count |
3 |
Count of background, subagent, and swarm task invocations attributed to the session |
background_task_count / background_task_completed_count |
1 / 1 |
Background work started and successfully completed via background/scheduled tool paths |
subagent_task_count / subagent_success_count |
1 / 1 |
Subagent task invocations and successful completions |
swarm_task_count / swarm_success_count |
1 / 0 |
Swarm/agent-coordination task invocations and successful completions |
user_cancelled_count |
1 |
Urgent interrupt count, used to detect sessions where the user stopped the agent mid-work |
transport_https |
2 |
Number of provider requests sent over HTTPS/SSE |
transport_persistent_ws_fresh |
1 |
Number of fresh persistent WebSocket requests |
transport_persistent_ws_reuse |
5 |
Number of turns that reused an existing persistent WebSocket |
transport_cli_subprocess |
0 |
Number of requests sent through a CLI subprocess transport |
transport_native_http2 |
0 |
Number of requests sent through native HTTP/2 transports |
transport_other |
0 |
Number of requests using any other transport |
project_repo_present |
true |
Whether the working directory looked like a repo |
project_lang_* |
true/false |
Coarse project-language buckets (Rust, JS/TS, Python, Go, Markdown, mixed) |
days_since_install |
12 |
Rough install age in days |
active_days_7d / active_days_30d |
4 / 9 |
How many distinct active days this install had recently |
session_start_hour_utc / session_end_hour_utc |
13 / 14 |
Session timing buckets for workflow analysis |
session_start_weekday_utc / session_end_weekday_utc |
2 / 2 |
Weekday timing buckets |
previous_session_gap_secs |
1800 |
Time since the previous session on this install |
sessions_started_24h / sessions_started_7d |
5 / 12 |
Recent session burstiness |
active_sessions_at_start / other_active_sessions_at_start |
2 / 1 |
Concurrent-session snapshot at session start |
max_concurrent_sessions |
3 |
Highest concurrent session count seen during the session |
multi_sessioned |
true |
Whether the user appeared to be running multiple sessions |
resumed_session |
false |
Whether this session was resumed |
end_reason |
"normal_exit" |
Coarse end reason |
errors |
{"provider_timeout": 0, ...} |
Count of errors by category |
Turn End Event
This is a privacy-safe per-prompt summary event. It contains no prompt text, no response text, and no tool inputs/outputs.
| Field | Example | Purpose |
|---|---|---|
event |
"turn_end" |
Event type |
turn_index |
4 |
Which user turn in the session this was |
turn_started_ms |
182000 |
Time from session start to turn start |
turn_active_duration_ms |
8200 |
Active duration until the last meaningful response/tool activity |
idle_before_turn_ms / idle_after_turn_ms |
45000 / 12000 |
Workflow pacing around the turn |
assistant_responses |
1 |
Responses produced during this turn |
first_assistant_response_ms |
1200 |
Time to first response within the turn |
first_tool_call_ms / first_tool_success_ms |
900 / 1500 |
Tool timing within the turn |
first_file_edit_ms / first_test_pass_ms |
2200 / 4100 |
Useful outcome timing within the turn |
tool_calls / tool_failures |
3 / 1 |
Coarse tool activity within the turn |
executed_tool_calls / executed_tool_successes / executed_tool_failures |
4 / 3 / 1 |
Registry tool execution outcomes |
tool_latency_total_ms / tool_latency_max_ms |
2600 / 1400 |
Tool latency footprint within the turn |
file_write_calls / tests_run / tests_passed |
1 / 1 / 1 |
Outcome proxies for coding workflows |
input_tokens / output_tokens |
1200 / 180 |
Turn-level provider-reported token usage totals |
cache_read_input_tokens / cache_creation_input_tokens |
8000 / 600 |
Turn-level provider-reported prompt-cache token totals when available |
total_tokens |
9980 |
Sum of input, output, cache-read, and cache-creation tokens for the turn |
feature_*_used |
true/false |
Which feature families were touched in the turn |
tool_cat_* |
0..N |
Tool category mix for the turn |
workflow_*_used |
true/false |
What kind of workflow this turn looked like |
turn_success |
true |
Whether the turn produced a useful response/outcome |
turn_abandoned |
false |
Whether the turn appears to have ended without success |
turn_end_reason |
"next_user_prompt" |
Why the turn was finalized |
Shared Event Metadata
Most events also carry a few coarse quality / cleanup fields:
| Field | Example | Purpose |
|---|---|---|
event_id |
"uuid" |
Deduplication |
session_id |
"uuid" |
Joins session-scoped events together |
schema_version |
3 |
Forward-compatible parsing |
build_channel |
"release" / "selfdev" / "local_build" |
Filter out dev/test usage |
is_git_checkout |
true/false |
Distinguish source-tree usage from installed usage |
is_ci |
true/false |
Filter CI noise |
ran_from_cargo |
true/false |
Filter local dev launches |
What We Do NOT Collect
- No file paths, project names, or directory structures
- No code, prompts, or LLM responses, except text explicitly submitted with
/feedback ... - No tool inputs or tool outputs
- No MCP server names or configurations
- No IP addresses (Cloudflare Workers don't log these by default)
- No personal information of any kind
- No error messages or stack traces in telemetry (only coarse categories and end reasons)
- No exact wall-clock timestamps beyond coarse hour-of-day / weekday buckets
The UUID is randomly generated on first run and stored at ~/.jcode/telemetry_id. It is not derived from your machine, username, email, or any identifiable information.
How It Works
- On first launch, jcode generates a random UUID and sends an
installevent - When a session begins, jcode sends a
session_startevent - When a session ends normally, jcode sends a
session_endevent with coarse session metrics - When auth succeeds, jcode sends a coarse
auth_successevent for activation-funnel analysis - When jcode detects a version change, it sends an
upgradeevent - On best-effort crash/signal handling, jcode sends a
session_crashevent - jcode may also send one-off onboarding milestone events and explicit feedback events when triggered
- Requests are fire-and-forget HTTP POSTs that don't block normal usage (install/session shutdown have short bounded blocking timeouts)
- If a request fails (offline, firewall, etc.), jcode silently continues - no retries, no queuing
The telemetry endpoint is a Cloudflare Worker that stores events in a D1 database. The source code for the worker is in telemetry-worker/.
Schema v5 deployment note
Agent-time, autonomy, and pain-attribution fields require the D1 migration in telemetry-worker/migrations/0008_agent_time_and_churn.sql. Until that migration is applied, schema v5 clients can still send the new JSON payloads, but the worker will drop unknown columns through dynamic column filtering and dashboard agent-time panels will remain empty or show optional-panel errors. After migration, run/redeploy the telemetry worker and query the dashboard's Agent time / autonomy panel.
How to Opt Out
Any of these methods will disable telemetry completely:
# Option 1: Environment variable
export JCODE_NO_TELEMETRY=1
# Option 2: Standard DO_NOT_TRACK (https://consoledonottrack.com/)
export DO_NOT_TRACK=1
# Option 3: File-based opt-out
touch ~/.jcode/no_telemetry
When opted out, zero network requests are made. The telemetry module short-circuits immediately.
Verification
This is open source. The entire telemetry implementation is in src/telemetry.rs - you can read exactly what gets sent. There are no other network calls related to telemetry anywhere in the codebase.
Data Retention
Telemetry data is used in aggregate only (install count, active users, provider distribution, session success/crash rates, feature-level counts). Individual event records are retained for up to 12 months and then deleted.
High-volume raw events are pruned earlier on a nightly schedule, after their aggregate signal has been captured in a compact daily-activity rollup: per-turn and per-session-start records and onboarding-step records are kept for about 30 days, upgrade records for about 60 days, and auth-success records for about 180 days. Session summary records (the per-session aggregate counts described above) are kept for up to 12 months.