4b465e0e5e
Establish an idempotent analytics pipeline and internal decision dashboard while keeping event metadata allowlisted and account deletion enforceable.
192 lines
5.2 KiB
Markdown
192 lines
5.2 KiB
Markdown
# Product analytics
|
|
|
|
OSGKeyboard analytics records product behavior metadata only. It is separate
|
|
from billing, provider execution and immutable credit ledgers.
|
|
|
|
## Privacy boundary
|
|
|
|
Never send or persist:
|
|
|
|
- audio or audio-derived content;
|
|
- keyboard input, prompts, context, transcripts or model output;
|
|
- Apple subjects, email addresses, names, tokens, API keys or provider
|
|
credentials;
|
|
- arbitrary property names or free-form text.
|
|
|
|
The service stores a SHA-256 digest of the random installation identifier, not
|
|
the identifier supplied by the client. Event DTO string representations are
|
|
redacted. Product analytics rows linked to an account are deleted with that
|
|
account. Anonymous installations that never link to an account are retained for
|
|
90 days and are eligible for scheduled deletion in a later operational job.
|
|
|
|
## Ingestion API
|
|
|
|
`POST /v1/analytics/events` accepts one batch of 1 to 50 events.
|
|
|
|
- Authentication is optional so first-open and pre-login events can be
|
|
measured. Invalid bearer credentials are rejected.
|
|
- `installationId` must be a client-generated UUID stored in the containing app
|
|
and shared with the keyboard extension through the App Group.
|
|
- When a valid account session is present, the installation is linked to that
|
|
account. An installation cannot later be linked to a different account.
|
|
- Every `clientEventId` is a client-generated UUID. The pair
|
|
`(installation, clientEventId)` is unique.
|
|
- Replaying an identical event is accepted and reported as replayed.
|
|
- Reusing an event ID with different values returns `409 conflict`.
|
|
- The whole batch is validated before persistence and committed atomically.
|
|
- `occurredAt` must be no more than 35 days old and no more than five minutes in
|
|
the future. UTC ISO-8601 timestamps are required.
|
|
|
|
The successful response reports `accepted` and `replayed` event counts. It does
|
|
not return account or installation identifiers.
|
|
|
|
## Event catalog
|
|
|
|
### Lifecycle events
|
|
|
|
`FIRST_OPEN`
|
|
|
|
- Required: `surface=APP`, `acquisitionChannel`.
|
|
- Optional: `appVersion`, `osVersion`.
|
|
- Must be emitted once per installation. Server idempotency protects retries.
|
|
|
|
`SESSION_STARTED`
|
|
|
|
- Required: `surface` (`APP` or `KEYBOARD`).
|
|
- Optional: `appVersion`, `osVersion`.
|
|
|
|
`KEYBOARD_ACTIVATED`
|
|
|
|
- Required: `surface=KEYBOARD`.
|
|
- Emit when the custom keyboard becomes active, not for every keystroke.
|
|
|
|
### AI events
|
|
|
|
`AI_FEATURE_STARTED`
|
|
|
|
- Required: `feature`, `executionMode`, `surface`.
|
|
- Optional: `durationBucket` is not allowed.
|
|
|
|
`AI_FEATURE_SUCCEEDED`
|
|
|
|
- Required: `feature`, `executionMode`, `surface`, `durationBucket`.
|
|
- This is the client-side core value event.
|
|
- Managed totals remain server-authoritative; the event provides feature and
|
|
surface detail.
|
|
|
|
`AI_FEATURE_FAILED`
|
|
|
|
- Required: `feature`, `executionMode`, `surface`, `failureCategory`.
|
|
- Optional: `durationBucket`.
|
|
- Never include provider response bodies or user content.
|
|
|
|
### Purchase events
|
|
|
|
`PURCHASE_VIEWED`
|
|
|
|
- Required: `surface=APP`.
|
|
|
|
`PURCHASE_STARTED`
|
|
|
|
- Required: `surface=APP`.
|
|
|
|
`PURCHASE_CANCELLED`
|
|
|
|
- Required: `surface=APP`, `failureCategory=CANCELLED`.
|
|
|
|
Successful purchases are derived from verified StoreKit transactions and must
|
|
not be duplicated as client success events.
|
|
|
|
### Referral events
|
|
|
|
`REFERRAL_SHARED`
|
|
|
|
- Required: `surface=APP`.
|
|
|
|
`INVITE_OPENED`
|
|
|
|
- Required: `surface=INVITE_WEB`, `acquisitionChannel=REFERRAL`.
|
|
- The app may emit this event after handling an invitation Universal Link.
|
|
- The first-party web route separately increments a UTC daily aggregate after
|
|
validating the referral code. It stores no IP address, user agent, cookie,
|
|
installation ID, referral code, or other request metadata.
|
|
- No third-party analytics script is permitted.
|
|
|
|
Referral binding, value qualification and reward are derived from server data.
|
|
|
|
## Allowed dimensions
|
|
|
|
`surface`
|
|
|
|
- `APP`
|
|
- `KEYBOARD`
|
|
- `INVITE_WEB`
|
|
|
|
`acquisitionChannel`
|
|
|
|
- `APP_STORE_ORGANIC`
|
|
- `REFERRAL`
|
|
- `SOCIAL_CONTENT`
|
|
- `UNKNOWN`
|
|
|
|
`feature`
|
|
|
|
- `TRANSCRIPTION`
|
|
- `POLISH`
|
|
- `AI_ASSISTANT`
|
|
- `AGENT`
|
|
- `HOTWORD`
|
|
- `OTHER`
|
|
|
|
`executionMode`
|
|
|
|
- `MANAGED`
|
|
- `LOCAL`
|
|
- `BYOK`
|
|
|
|
`failureCategory`
|
|
|
|
- `NETWORK`
|
|
- `PROVIDER`
|
|
- `TIMEOUT`
|
|
- `CANCELLED`
|
|
- `INSUFFICIENT_CREDITS`
|
|
- `VALIDATION`
|
|
- `UNKNOWN`
|
|
|
|
`durationBucket`
|
|
|
|
- `LT_1S`
|
|
- `S1_TO_3`
|
|
- `S3_TO_10`
|
|
- `S10_TO_30`
|
|
- `GTE_30S`
|
|
|
|
`appVersion` and `osVersion` are optional ASCII release identifiers of at most
|
|
32 characters. They may not contain spaces, user-generated values or device
|
|
names.
|
|
|
|
## Client delivery guidance
|
|
|
|
- Persist pending events in an append-only local queue.
|
|
- Retry with exponential backoff after network failures and HTTP 5xx.
|
|
- Drop events rejected with HTTP 400/422 after recording a local diagnostic
|
|
counter; do not retry malformed events indefinitely.
|
|
- Reuse the same `clientEventId` for every retry.
|
|
- Send at most 50 events per batch and remove events only after a successful
|
|
response.
|
|
- Do not block the AI interaction or purchase flow on analytics delivery.
|
|
|
|
## Reporting
|
|
|
|
The admin analytics endpoints combine:
|
|
|
|
- accepted product events for acquisition, local/BYOK usage and client funnel
|
|
detail;
|
|
- settled credit usage for managed AI counts and credit consumption;
|
|
- accounts, StoreKit and referrals for registration, monetization and referral
|
|
outcomes.
|
|
|
|
Metric formulas are defined in
|
|
[`ANALYTICS_METRICS_DICTIONARY.md`](ANALYTICS_METRICS_DICTIONARY.md).
|