PostHog — Session Replay
PostHog's session replay feature:
- captures user sessions in the browser
- ingests and stores encrypted recording blocks,
- replays them in the web app
AWS KMS
External system (AWS)key management service that wraps/unwraps per-session data keys (GenerateDataKey / Decrypt).
End User (Website Visitor)
Persona visitor on the customer's website whose browser session is recorded by the embedded posthog-js SDK.
Product Engineer (PostHog User)
Persona PostHog user who watches session replays to debug issues and understand user behavior.
Replay processing workflows
Scheduled Temporal workflows — jobs that process recordings, not standalone services. Each child is a workflow. Orchestration lives in Python/Temporal; the rasterize job delegates rendering to a Node.js worker activity.
Browser SDK
Container (JavaScript)posthog-js + rrweb embedded in customer websites
records DOM mutations, clicks, console and network, batched as $snapshot / $performance_event events.
Capture Service
Container (Rust)high-throughput /s/ capture endpoint; validates, rate-limits and collapses $snapshot events into $snapshot_items Kafka messages.
Data Store
Container (ClickHouse)kafka_session_replay_events (Kafka engine) → session_replay_events materialized view; stores block metadata, counts, surfacing_score, is_deleted.
Django API
Container (Python/Django)session_recordings REST API;
HogQL list & metadata queries against ClickHouse, snapshots streaming via the Recording API.
Keystore
Container (DynamoDB)keystore of per-session data keys wrapped by AWS KMS.
Web App — Replay Player
Container (React)Session recordings scene
lists/filters recordings and replays rrweb events in a sandboxed iframe via the rrweb Replayer.
Message Broker
Container (Kafka)message bus:
session_recording_snapshot_item_events (capture → ingester), clickhouse_session_replay_events + clickhouse_session_replay_features (ingester → ClickHouse).
Session Replay Ingester
Container (Node.js/TypeScript)- consumes
$snapshot_items - validates headers, resolves retention, gates/rate-limits sessions, resolves per-session data keys, buffers encrypted blocks, streams them to S3 and publishes block metadata to ClickHouse.
Recording API
Container (Node.js)serves encrypted blocks:
S3 byte-range read → sodium decrypt (KMS-unwrapped key) → optional snappy decompress; block lists from ClickHouse; crypto-shred deletes.
Cache
Container (Redis)shared cache:
token-bucketsession gating and 'seen' marking during ingestionRedisCachedKeyStoreused by the Recording API.
Object Store
Container (S3/SeaweedFS)sodium-encrypted, snappy-compressed recording blocks partitioned by retention period.
Delete (crypto-shred)
Workflow: crypto-shreds deleted recordings — deletes S3 blocks, shreds the DynamoDB data key, and purges recording metadata.
Rasterize → MP4/WebM/GIF
Workflow: renders a recording to MP4/WebM/GIF. Python/Temporal orchestrates a Node.js rasterizer activity (chrome-headless-shell + ffmpeg) that replays the session frame-by-frame.
Enforce retention
Workflow: deletes recordings past the team's retention entitlement (30d/90d/1y/5y).
Surfacing scoring (XGBoost)
Workflow: scores recent sessions with an XGBoost model and writes surfacing_score back to ClickHouse.