-
Notifications
You must be signed in to change notification settings - Fork 3
Session replay: discovery, fetch, analyzer, and bundle analytics (044) #193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 12 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
5487dd9
Add session-replay foundation (044, Phase 1 + Phase 2/T011-T021)
jaredmixpanel f50844e
Complete US1: ReplaysService + Workspace replay surface (044/T015-T032)
jaredmixpanel e35cc55
Add mp replays CLI commands + PR 1 ready (044/T033-T042)
jaredmixpanel bf4a246
Ship US2 + US4 + Phase 6 polish — PRs 2 and 3 ready (044/T043-T094)
jaredmixpanel 85ba556
Rework rrweb_analyzer + fix events_for query shape (044/T055 follow-up)
jaredmixpanel 015e14d
Add focused rrweb analyzer coverage (043 tests, all synthetic fixtures)
jaredmixpanel 0762f40
Fix session-replay discovery: parse series, not the lossy .df (044)
jaredmixpanel 06fb25d
Harden replay fetch + scope events window (044 QA findings #2–#4)
jaredmixpanel e27e5e6
Batch replay-fetch Insights queries (044 QA finding #5, MCP parity)
jaredmixpanel 287fa22
QA the pm4py/tslearn extras: fix event_log contract, cluster crash, m…
jaredmixpanel 77a8336
Remove pm4py + tslearn process-mining / clustering from session repla…
jaredmixpanel d7f96fa
Cut dead replay projections, harden the deterministic core (044)
jaredmixpanel 416bcd1
Document the session-replay surface across README, docs, and plugin (…
jaredmixpanel 0109796
Resolve PR #193 review: replay discovery, security, and doc fixes (044)
jaredmixpanel e128091
Resolve PR #193 review: public replay labels, docstrings, typed CLI e…
jaredmixpanel 9de9de7
Address PR #193 review round 2: fix selector_label_fn + replay cleanu…
jaredmixpanel 7a11354
Fix DOMTracker MAX_NODES guard: cap held only on first over-limit nod…
jaredmixpanel 2512ac2
Address PR #193 Copilot review + strip session-replay phase residue (…
jaredmixpanel ad193f3
Type mobile-replay rejection as UnsupportedReplayFormatError (044)
jaredmixpanel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| { | ||
| "feature_directory": "specs/043-frictionless-auth" | ||
| "feature_directory": "specs/044-session-replay" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # Changelog | ||
|
|
||
| All notable changes to `mixpanel-headless` are recorded here. The format | ||
| loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); | ||
| this project follows semver but is currently pre-1.0, so minor versions | ||
| may include API changes. | ||
|
|
||
| ## Unreleased — Session Replay (044, PRs 1–3) | ||
|
|
||
| ### Added (PR 1 — Phase 1: discovery + signed CDN access) | ||
|
|
||
| - `Workspace.list_replays(distinct_id|replay_ids, from_date, to_date, limit)` | ||
| — discover replays for a user, or hydrate explicit IDs. | ||
| - `Workspace.sign_replay(id)` / `Workspace.sign_replays(ids, env)` — | ||
| sign replay IDs for CDN access via the | ||
| `/app/projects/<id>/replays/sign[/bulk]` endpoint. | ||
| - `Workspace.fetch_replay(id, env, retention_days, max_files, | ||
| include_mixpanel_events, event_properties, cdn_concurrency)` — sign + | ||
| parallel CDN walk + return a fully materialized `Replay`. | ||
| - `Workspace.stream_replay(id, …)` — sync iterator wrapping the async | ||
| CDN walker; re-signs on expiry by default. | ||
| - `Workspace.events_for_replay(id, event_properties)` and | ||
| `Workspace.events_for_replays(ids, event_properties)` — Mixpanel | ||
| events that overlap a replay's time window. | ||
| - New result types: `ReplaySummary`, `SignedReplay` (with | ||
| `query_string` masked in `__repr__`/`__str__` per FR-008/9), | ||
| `ReplayEvent`, `UserAction`, `Replay`. | ||
| - New exceptions: `SessionReplayError` (base) plus | ||
| `SessionReplayAccessError` (sensitive-data 403), | ||
| `SignedURLExpiredError`, `ReplayNotFoundError`. CLI exit-code mapping | ||
| added: sensitive-data → 2, replay-not-found → 4. | ||
| - New CLI commands: `mp replays list`, `mp replays events`, | ||
| `mp replays sign` (with `--reveal-signed-urls` opt-in that emits a | ||
| stderr warning on every invocation), `mp replays fetch [-o FILE]`. | ||
| - Depends on the undocumented `/app/projects/<id>/replays/sign[/bulk]` | ||
| endpoint — the same endpoint Mixpanel's own MCP server uses. | ||
|
|
||
| ### Added (PR 2 — Phase 2: analyzer + ReplayBundle) | ||
|
|
||
| - `Workspace.fetch_replays(ids, …)` — parallel multi-replay fetch | ||
| returning a `ReplayBundle`. | ||
| - `Workspace.replays_for_user(distinct_id, from_date, to_date, …)` — | ||
| composition of `list_replays` + `fetch_replays`; defaults | ||
| `include_mixpanel_events=True`. | ||
| - `Workspace.analyze_replay(id)` — sugar for | ||
| `fetch_replay(id).summary_markdown`. | ||
| - `RrwebAnalyzer` (`_internal/replays/rrweb_analyzer.py`) — rrweb | ||
| event-stream analyzer producing normalized `UserAction` records + | ||
| markdown timeline. Handles click / input / scroll / navigate / | ||
| select / console_error event families with per-source debouncing | ||
| (scroll / input / selection at 1s each), plus a DOM tracker with | ||
| ancestor traversal and descriptive-attrs extraction for | ||
| human-readable target descriptions. Pure stdlib. | ||
| - `ReplayBundle` (`types.py`): seven DataFrame projections | ||
| (`sessions_df`, `actions_df`, `events_df`, `mixpanel_df`, `pages_df`, | ||
| `elements_df`, `transitions_df`); two graph projections | ||
| (`page_graph`, `element_graph` — `networkx.DiGraph`); one tree | ||
| projection (`path_tree` — `anytree.AnyNode`); seven aggregations | ||
| (`top_paths`, `top_pages`, `top_clicks`, `dead_clicks`, `rage_clicks`, | ||
| `long_pauses`, `error_sessions`); six chainable filters | ||
| (`filter`, `where`, `find_pattern`, `error_sessions`, `head`, | ||
| `sample`); `join_mixpanel_events`, `summary_markdown`, `compare`. | ||
| - Label functions: `default_label_fn`, `selector_label_fn`, | ||
| `url_normalizer` (`_internal/replays/labels.py`). The URL | ||
| normalizer collapses numeric / hex path segments to `:id` so | ||
| parameterized URLs aggregate cleanly across users. | ||
| - Module-level aggregators (`_internal/replays/aggregators.py`) | ||
| re-exposed via `ReplayBundle` methods. | ||
| - New CLI commands: `mp replays analyze` (markdown timeline / | ||
| `--format json` for action list) and `mp replays for-user | ||
| --include analyze --include events --out-dir DIR`. | ||
|
|
||
| ### Security | ||
|
|
||
| - `SignedReplay.query_string` is a 5-minute bearer credential and is | ||
| masked in `__repr__`/`__str__`. The `--reveal-signed-urls` CLI opt-in | ||
| emits a stderr warning on every invocation (FR-008/9). The pre-merge | ||
| security audit greps the source tree for `Signature=` / `URLPrefix=` | ||
| / `Expires=`; no leaks were found. | ||
|
|
||
| ### Notes | ||
|
|
||
| - Mobile session replays are detected by the CDN walker (first event | ||
| lacks rrweb's `type`/`data`/`timestamp` keys) and surface as a | ||
| forward-compat `NotImplementedError` per error-messages.md §9. | ||
| - Live integration tests (`tests/integration/test_replays_live.py`) are | ||
| marked `@pytest.mark.live` and deselected by default; set | ||
| `MP_LIVE_TESTS=1` plus `MP_REPLAY_FIXTURE_DISTINCT_ID` to run them | ||
| against a fixture project. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.