> ## Documentation Index
> Fetch the complete documentation index at: https://docs.second.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Product analytics

> How Second captures PostHog events while preserving the anonymized usage-data setting.

Second captures lightweight product analytics after onboarding. Analytics are
enabled by default, and the default user setting is anonymized.

The PostHog project token is a public client/project token, not a private API
key. Configure it with `SECOND_POSTHOG_TOKEN` when overriding the built-in
release default, and use `SECOND_POSTHOG_HOST` for non-US PostHog projects.

## Capture path

Browser code does not send directly to PostHog. It posts events to Second's
same-origin `/api/analytics/capture` endpoint.

The web route:

* requires an authenticated, onboarded user
* allowlists the supported event names
* sanitizes property keys and values
* applies the current anonymization mode
* forwards the final payload to PostHog

This keeps the privacy and tenant checks in Second instead of trusting every
call site to send the right PostHog payload.

## Events

Second currently captures:

* `page viewed`
* `onboarding finished`
* `chat initiated`
* `sidebar clicked`
* `import existing app clicked`
* `import existing app triggered`
* `build completed`
* `build failed`
* `approval shown`
* `approval acted`
* `integration setup started`
* `integration setup completed`
* `app displayed`
* `app agent triggered`
* `app agent finished`
* `app agent error`
* `showed suggestions tool called`
* `suggestion picked`
* `agents approved`

All browser analytics events include anonymous-safe page context:

* `surface`, such as `workspace_home`, `app_chat`, `settings`, `library`, or
  `workspace_agents`
* `route_shape`, such as `/w/:workspace/apps/:objectId`
* small client context such as viewport size

The route shape removes workspace IDs, app IDs, run IDs, UUIDs, and integration
route segments before the event is sent.

Build and agent events use counts and outcomes where possible: message count,
tool call count, attachment count, file count, duration, runtime ID/model, and
failure phase/error code. Raw prompts, messages, app names, agent names, URLs,
and IDs are still stripped in anonymized mode.

The analytics endpoint also adds release metadata server-side to every event:

* `release_version`
* `release_package`
* `release_runtime`
* `cli_launcher_version`
* `cli_launcher_package`

For CLI runs these values come from the launcher/runtime environment. In other
deployment modes they may be `null` unless the deployment sets release
environment variables.

## Anonymized mode

When anonymization is on, the browser creates one stable local anonymous ID in
`localStorage`:

```text theme={null}
second:analytics-anonymous-id:v1
```

The value is an `anon_...` UUID generated by Second. It is sent as the PostHog
`distinct_id` for anonymized events, so repeated events from the same browser
are grouped together without identifying the user.

Anonymized events deliberately:

* do not call PostHog `$identify`
* do not alias the anonymous ID to the real user ID
* set `$process_person_profile: false`
* strip user, workspace, app, run, agent, prompt, message, raw error,
  suggestion, URL, and referrer identifiers
* strip generic identifier-shaped properties such as `*_id`, `*_ids`,
  `*_email`, `*_name`, and `*_names`

This means anonymized events stay useful for aggregate product analytics while
remaining separate from the user's PostHog person profile.

## Non-anonymized mode

Users can turn off anonymization from the workspace account menu under
**Usage data settings**.

When anonymization is off, Second sends a PostHog `$identify` event for the
onboarded user and uses the Second user ID as the PostHog `distinct_id`.
Non-anonymized events may include the user, workspace, app, agent, message, and
screen properties needed for debugging and product analysis.

## Screen recording

Screen recording is a separate opt-in inside **Usage data settings**. It is off
by default, and enabling it also turns anonymization off because replay captures
the actual Second interface for product debugging.

Regular product analytics still use the same-origin `/api/analytics/capture`
route. Screen recording is the exception: PostHog session replay runs in the
browser through `posthog-js`, because replay is captured from the browser DOM and
cannot be produced by the server-side capture endpoint.

When screen recording is enabled, the browser loads the public PostHog project
token and host from Second's authenticated analytics config route, identifies the
current onboarded user, and starts PostHog session recording. The SDK is
configured without PostHog pageview/autocapture product events so it does not
replace or duplicate Second's sanitized analytics capture path.

When screen recording is disabled, anonymization is re-enabled, telemetry is
disabled, or the user signs out, Second stops PostHog session recording and
resets the browser SDK state on that tab. Browser-level password-field masking
from PostHog/rrweb still applies, but Second does not apply its anonymized
analytics redaction model to replay after the user explicitly enables recording.

## Switching modes

Switching from anonymized to non-anonymized affects future events only.

Second does not merge or alias the local anonymous ID into the identified
PostHog person. That is intentional: PostHog's standard frontend SDK can link
anonymous history to a user after `identify`, but doing that here would make
the anonymized setting weaker. In Second, historical anonymized events remain
anonymous even if the same user later disables anonymization.

On sign-out, Second resets the local anonymous ID. This prevents two different
users sharing one browser profile from being grouped under the same anonymous
PostHog identity.

## Disabling analytics

For local development, disable analytics for a run with:

```bash theme={null}
npm run dev -- --disable-telemetry
npm run dev -- --no-analytics
SECOND_POSTHOG_DISABLED=1 npm run dev
```

For CLI runs:

```bash theme={null}
npx --yes @second-inc/cli --disable-telemetry
```

For deployments, set either of:

```bash theme={null}
SECOND_POSTHOG_DISABLED=1
SECOND_TELEMETRY_DISABLED=1
```
