> For the complete documentation index, see [llms.txt](https://faction-os.gitbook.io/faction-os-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/phases/phase_07/analytics_consent_payload_controls.md).

# Analytics Consent and Payload Controls

**Session ID**: `phase07-session05-analytics-consent-and-payload-controls` **Status**: Source-backed planned-state baseline **Created**: 2026-05-30 **Scope**: Optional analytics provider, disabled default, consent, opt-out, payload minimization, blocked analytics payloads, local-only fallback, and Phase 08 handoff

***

## Purpose

This artifact defines the analytics posture for Phase 07. It is a guardrail baseline, not an activation of analytics capture. FactionOS remains local-first and usable without Umami, PostHog, hosted accounts, hosted storage, public replay hosting, Cloudflare credentials, push, remote access, provider credentials, or production-hosted validation.

Umami is the selected optional default analytics provider from ADR 0003. It must remain disabled by default, replaceable, and self-hostable. Provider configuration is not consent. A website id is not consent. A future API key is not consent. Analytics can be described as ready only when operator configuration and explicit consent requirements are both satisfied, and this session still does not send events, install tracking scripts, import analytics SDKs, ship a dashboard, or collect runtime analytics.

## Source Ownership

| Surface             | Owner                                                       | Current state                                                                                             |
| ------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Shared vocabulary   | `packages/protocol/src/hostedAnalytics.ts`                  | Planned-state contracts, consent labels, taxonomy, payload fields, blocked labels, and unsupported claims |
| Browser helper copy | `apps/web/src/lib/hostedAnalytics.ts`                       | Pure readiness, settings copy, opt-out, and payload scrubbing helpers with no network side effects        |
| Settings UI         | `apps/web/src/components/SettingsDrawer.tsx`                | Disabled, unavailable, or consent-required status copy only                                               |
| Stable docs         | `.spec_system/PRD/phase_07/`, `docs/`, package README files | Current limitations and Phase 08 handoffs                                                                 |

## Provider Posture

| Requirement        | Minimum bar                                                                                                                                                              |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Default provider   | Umami is the optional default provider selected by ADR 0003.                                                                                                             |
| Self-hosting       | Local or operator-owned Umami origins are allowed after URL validation.                                                                                                  |
| Replaceability     | Provider labels and contracts must not hard-code an irreversible vendor dependency.                                                                                      |
| Disabled default   | Analytics is off when config is absent, blank, malformed, incomplete, explicitly false, or missing consent.                                                              |
| No runtime capture | This session does not send events, add a beacon, inject a script, import `@umami/node`, or ship server-side ingestion.                                                   |
| No dashboard claim | No source, UI, docs, or tests may claim that analytics dashboards, recorder, heatmaps, session replay, console-log capture, or production-hosted validation are shipped. |

PostHog remains historical service-discovery context only. It is not the selected default analytics provider and must not appear as an active runtime dependency.

## Status Vocabulary

| Status             | Meaning                                                                                                                       |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `planned`          | Requirements and contracts are documented, but runtime analytics capture is not shipped.                                      |
| `disabled`         | Analytics is intentionally off, including the default local development posture.                                              |
| `unavailable`      | Required provider configuration is absent, malformed, or incomplete.                                                          |
| `consent_required` | Configuration is syntactically usable, but consent has not been granted.                                                      |
| `ready`            | Provider config and consent are both satisfied. In this session, ready is a pure helper result only and does not send events. |
| `opted_out`        | The user or operator has disabled analytics even if provider config exists.                                                   |
| `unsupported`      | A requested dashboard, recorder, replay, ingestion, or erasure claim is not available in this build.                          |

No status in this artifact proves production-hosted validation, trusted erasure, server-side analytics ingestion, account-backed consent storage, or analytics capture.

## Consent and Opt-Out Requirements

Analytics requires separate controls for provider configuration, operator intent, user or operator consent, and opt-out. These controls must be evaluated at the point where a future event would be sent.

| Control         | Rule                                                                                                                                                                      |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Operator config | `FACTIONOS_ANALYTICS_ENABLED=true`, provider, host URL, and website id can only make analytics configurable. They do not grant consent.                                   |
| Consent         | Analytics remains off until a future reviewed consent state grants capture for the specific surface.                                                                      |
| Opt-out         | Opt-out wins over enabled config and prior consent. It must produce a visible disabled state.                                                                             |
| Re-entry        | Settings and helper state must be re-evaluated when the settings drawer opens or config inputs change.                                                                    |
| Local fallback  | Missing or invalid hosted analytics config keeps local server, web, hooks, CLI, adapters, public demo, replay, export, archive, backup, and diagnostics workflows usable. |
| Failure state   | Invalid config, denied consent, opt-out, missing website id, and unsupported provider values produce bounded user or operator copy.                                       |

Account identity, Worker authority, local auth, room role, API keys, and website ids are not analytics consent.

## Approved Event Taxonomy

Only coarse product posture events may be represented in the shared taxonomy. These event labels are future-ready names for tests and docs; this session does not emit them.

| Event                       | Purpose                                                                                      |
| --------------------------- | -------------------------------------------------------------------------------------------- |
| `cockpit_view`              | Coarse cockpit surface visibility.                                                           |
| `settings_status_view`      | Settings status viewed without raw settings values.                                          |
| `local_demo_view`           | Public demo or local demo surface viewed with synthetic data only.                           |
| `hosted_guardrail_status`   | Compact hosted-service guardrail posture.                                                    |
| `replay_local_action`       | Local replay panel action labels only, without replay payloads.                              |
| `export_local_action`       | Local export action outcome labels only, without export body.                                |
| `war_room_local_status`     | Local or room-scoped War Room status labels only, without room payloads or authority values. |
| `notification_local_status` | Browser notification permission/status labels only, without push subscription payloads.      |

Future sessions may add events only when the event name, allowed payload fields, consent requirement, minimization rule, and tests are updated together.

## Allowed Analytics Payload Fields

Analytics payloads must be allowlist based. Unknown keys are dropped. Nested objects are flattened only when their keys are explicitly allowed; otherwise they are dropped. Approved values must be bounded strings, booleans, or small counts.

| Field            | Allowed value                                                            |
| ---------------- | ------------------------------------------------------------------------ |
| `eventId`        | Stable synthetic event id or test id, not a provider request id.         |
| `surface`        | Coarse UI or runtime surface label.                                      |
| `status`         | Shared status label such as disabled, unavailable, ready, or opted\_out. |
| `feature`        | Coarse feature label, not raw feature config.                            |
| `provider`       | Shared provider label such as umami or custom.                           |
| `consent`        | Shared consent state label.                                              |
| `localOnly`      | Boolean local-only posture.                                              |
| `count`          | Bounded integer count.                                                   |
| `durationBucket` | Coarse bucket label, not a precise trace.                                |
| `reason`         | Stable reason code without raw values.                                   |
| `docsPath`       | Stable docs path from the protocol vocabulary.                           |

Payload helpers must never copy arbitrary objects into analytics output.

## Blocked Analytics Payload Labels

The following labels are blocked from analytics by default:

* `prompt_content`
* `provider_prompt`
* `transcript_content`
* `assistant_message`
* `file_content`
* `code_content`
* `diff_or_patch`
* `command_body`
* `terminal_output`
* `secret_value`
* `credential_value`
* `url_with_credentials`
* `local_path`
* `raw_env_dump`
* `replay_buffer`
* `export_body`
* `archive_body`
* `backup_payload`
* `scan_payload`
* `diagnostic_payload`
* `log_payload`
* `media_draft`
* `war_room_payload`
* `account_identifier`
* `zone_identifier`
* `tunnel_token`
* `quarantined_historical_content`

Tests must use synthetic values for these categories and assert serialized analytics payload output does not contain them.

## Payload Minimization Rules

* Build analytics payloads from an explicit allowlist.
* Drop unknown keys and blocked keys rather than forwarding raw input.
* Reject unknown event names.
* Normalize strings by trimming and bounding length.
* Represent counts as bounded non-negative integers.
* Represent timing as coarse buckets, not raw traces.
* Preserve `localOnly: true` when analytics is disabled, unavailable, or not consented.
* Expose stable reason codes instead of raw provider errors.
* Do not include account ids, organization ids, email addresses, IP addresses, provider request ids, local paths, prompt excerpts, terminal output, replay buffers, exports, archives, logs, backups, diagnostics, or scan payloads.

## Browser Readiness Rules

Browser analytics helpers may read caller-provided environment records, but they must not read `.env.local`, contact a provider, mutate remote state, write account-backed consent records, inject scripts, send beacons, or import an analytics SDK.

Analytics readiness is disabled or unavailable when:

* `FACTIONOS_ANALYTICS_ENABLED` is absent, blank, invalid, or false.
* `FACTIONOS_ANALYTICS_PROVIDER` is absent, blank, unsupported, or malformed.
* `UMAMI_HOST_URL` is absent, blank, too long, non-http(s), contains credentials, query strings, or fragments.
* `UMAMI_WEBSITE_ID` is absent or blank.
* Consent is missing, denied, unknown, unavailable, or withdrawn.
* Opt-out is active.

Readiness may return `ready` only when config is valid, the provider is supported, a non-empty website id is present, consent is granted, and opt-out is not active. This session still uses `ready` as a pure state only.

## Settings Copy Requirements

The settings drawer may show analytics posture so users can understand that tracking is not active. It must not add a working send-event control, dashboard link, recorder control, heatmap control, replay-inspection control, account consent store, or provider credential entry.

Visible copy should distinguish:

* Disabled default.
* Unavailable or incomplete provider config.
* Consent required.
* Opted out.
* Ready in helper state only, with no capture runtime.

The section must have accessible labeling and refresh status on drawer entry.

## Unsupported Claims

The following claims are unsupported in this build:

* `analytics_capture`
* `tracking_script`
* `server_side_ingestion`
* `analytics_dashboard`
* `recorder`
* `heatmap`
* `session_replay`
* `console_log_capture`
* `public_replay_analytics`
* `account_backed_consent_storage`
* `production_hosted_validation`
* `trusted_erasure`

Docs, diagnostics, tests, and UI copy should use these labels when preventing analytics overclaim drift.

## Local-Only Fallback

When analytics config, hosted accounts, hosted storage, public replay hosting, push, remote access, tunnels, provider credentials, or production hosts are absent:

* The local server still starts.
* The web cockpit still renders local state.
* Hooks, CLI, adapters, backup, export, replay, archive, scan, War Room, and public demo workflows remain credential-free.
* Settings shows disabled or unavailable analytics posture instead of a blank panel or implied capture.
* Payload helpers return minimized local-only payloads or empty payloads without network side effects.

## Evidence Requirements

* Shared analytics vocabulary starts in `packages/protocol`.
* Browser helpers consume shared protocol labels instead of duplicating sensitive categories.
* Tests prove config alone, consent alone, website id alone, malformed URLs, disabled flags, and opt-out cannot activate analytics.
* Tests prove blocked sensitive categories do not appear in serialized analytics payload output.
* Settings tests prove disabled, unavailable, or consent-required copy renders with accessible labels and revalidates when the drawer opens.
* Documentation distinguishes shipped, planned, disabled, unavailable, unsupported, and Phase 08 deferred states.

## Phase 08 Handoff

Phase 08 remains responsible for production-hosted validation, trusted unified erasure, release hardening, mobile and WCAG certification, legacy decommission, and any release-grade deletion claim.

This Session 05 artifact is sufficient to prevent analytics overclaim and payload drift. It is not sufficient to ship analytics capture.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/phases/phase_07/analytics_consent_payload_controls.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
