Search activity is recorded per user for product analytics. Because these rows
contain personal data (SearchAnalytics stores userId, query, filters, and
SearchHistory stores userId + query), they are subject to retention pruning
and per-user opt-out.
Users control tracking via the searchAnalyticsOptOut user preference
(UserPreferences model, exposed through the user-preferences API).
- Opted out: no
SearchAnalyticsorSearchHistoryrow is written for that user's searches. The aggregatedPopularSearchcounter still updates so product quality signals are preserved without per-user tracking. - Default:
false(analytics recorded).
Per-search and per-user search rows are purged by the daily cleanup job
(CleanupService, runs at 02:00 UTC) after a configurable retention window:
| Entity | Env var | Default |
|---|---|---|
SearchAnalytics |
CLEANUP_SEARCH_RETENTION_DAYS |
30 |
SearchHistory |
CLEANUP_SEARCH_RETENTION_DAYS |
30 |
Aggregated PopularSearch rows are intentionally retained (they contain no
personal identifiers) and power the "popular searches" product surface.
- Export:
data-export.service.tsalready includessearchHistoryandsearchAnalyticsrows in the per-user export. - Deletion: deleting a user cascades to
SearchHistory(relationUser,onDelete: Cascade) and nulls the owning user onSearchAnalytics(onDelete: SetNull); opted-out users generate no rows in the first place.