Skip to content

feat(web-analytics): gate session replay tile behind removal experiment - #70048

Merged
lricoy merged 3 commits into
masterfrom
posthog-code/web-analytics-remove-replay-tile
Jul 14, 2026
Merged

feat(web-analytics): gate session replay tile behind removal experiment#70048
lricoy merged 3 commits into
masterfrom
posthog-code/web-analytics-remove-replay-tile

Conversation

@lricoy

@lricoy lricoy commented Jul 10, 2026

Copy link
Copy Markdown
Member

Problem

The Web analytics dashboard renders a "Session replay" tile that mounts sessionRecordingsPlaylistLogic on every dashboard load to show just its top 5 recordings, so it runs a full session-recordings-list query each time the dashboard opens. Usage analysis shows the tile gets almost no genuine engagement (people reach replays via the left nav and the contextual "View recordings" cross-sell button instead), so we want to test removing it — but validate retention isn't affected before dropping it for good.

Changes

  • Add the web-analytics-remove-replay-tile feature flag (control / test) in frontend/src/lib/constants.tsx.
  • Gate the TileId.REPLAY tile in webAnalyticsLogic.tsx so it renders only when the flag is not test. Default/absent flag keeps the tile (no behavior change for anyone not enrolled); the test variant removes it, which also stops the recordings-list query from running on those loads.

This is scaffolding for experiment #382421:

  • Primary metric: web analytics return retention (7-day).
  • Guardrail: reached Session replay (/replay pageviews) — should not drop.

How did you test this code?

Not manually run by the agent (no dev stack in this environment). The change mirrors the existing WEB_ANALYTICS_TILE_HEADER_V2 === 'test' flag-gating pattern already used in the same selector, and the flag comparison is type-identical to it. CI typecheck/lint will cover the static checks.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Docs update

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Requested from a Slack thread investigating whether the Session Replay tile in Web analytics earns its query cost. The investigation found the tile is barely used, so the ask was to set up an A/B test for removing it and measure retention + whether anyone misses it.

  • Skills invoked: /creating-experiments, /configuring-experiment-analytics.
  • The experiment and its web-analytics-remove-replay-tile flag were created via MCP; this PR only wires the flag into the frontend. control was chosen as the tile-shown baseline so absent-flag behavior is unchanged.
  • Left the Error tracking tile untouched — usage data showed it does get real engagement.

Created from a Slack thread.

Gate the web analytics dashboard's Session Replay tile behind the
`web-analytics-remove-replay-tile` experiment flag. Control keeps the tile
(current behavior, the default when the flag is absent); the `test` variant
hides it.

The tile mounts sessionRecordingsPlaylistLogic on every dashboard load to
render only its top 5 rows, so it runs a full session-recordings-list query
each time. Usage data shows almost no one interacts with it, so this sets up
an A/B test to measure whether removing it affects retention before dropping
it outright.

Generated-By: PostHog Code
Task-Id: 98495d89-d4bb-423c-b2b3-8efd32e3f9c0
@lricoy
lricoy marked this pull request as ready for review July 10, 2026 13:18
@lricoy lricoy added the stamphog Request AI approval (no full review) label Jul 10, 2026
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

🦔 Hogbox preview · ✅ ready

▶ Open the preview

🔑 Login test@posthog.com / 12345678 (demo data)
🧩 Running this PR's backend and frontend, on the PostHog :master base
🔗 Link stable across rebuilds — a re-push swaps the box underneath, the URL stays
🔒 Access tailnet only (PostHog VPN)
💤 Idle sleeps after ~30 min idle (snapshot to S3, zero node cost) and wakes on your next visit in ~30s, behind a brief "waking up" screen

commit eb83a09 · box box-ae3b61cb771f · ready in 567s (push → usable) · build log · rebuilds on every push, torn down on close

@lricoy
lricoy enabled auto-merge (squash) July 10, 2026 13:18
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team July 10, 2026 13:18
@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "feat(web-analytics): gate session replay..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cc220c1a7d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx Outdated
@stamphog

stamphog Bot commented Jul 10, 2026

Copy link
Copy Markdown

Note

🤖 stamphog reviewed cc220c1a7d0b3443066ec4259c748a0bd61389c8 — verdict: REFUSED

Unresolved Codex comment on the current head correctly flags that the flag is read for bot-analytics tab users too, polluting the experiment's retention/guardrail metrics — a substantive, unaddressed concern that undermines the PR's stated purpose.

  • Author wrote 0% of the modified lines and has 112 merged PRs in these paths (familiarity MODERATE).
  • chatgpt-codex-connector[bot] reviewed the current head.
  • Unresolved inline comment from @chatgpt-codex-connector[bot]: featureFlags[WEB_ANALYTICS_REMOVE_REPLAY_TILE] is read in the allTiles selector before the bot-analytics-tab early return, so bot-tab users get enrolled in the experiment even though neither arm affects them, diluting/corrupting the retention and replay guardrail metrics.
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list no deny categories matched
size 3L, 2F substantive — within ceiling
tier T1-agent / T1a-trivial (3L, 2F, single-area, feat)
stamphog 2.0.0b3 .stamphog/policy.yml @ 729ace2 · reviewed head cc220c1

@stamphog stamphog Bot removed the stamphog Request AI approval (no full review) label Jul 10, 2026
allTiles is also constructed for the bot-analytics tab (then discarded via
an early return), so reading the removal experiment flag unconditionally
enrolled bot-tab users the experiment can't affect, diluting the retention
and replay guardrail metrics. Only read the flag when productTab is the
analytics tab, where the tile actually renders.

Generated-By: PostHog Code
Task-Id: 98495d89-d4bb-423c-b2b3-8efd32e3f9c0
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

Bundle size — 🟢 -61.5 KiB (-0.1%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 70.02 MiB · 🟢 -61.5 KiB (-0.1%)

File Size Δ vs base
render-query/src/render-query/render-query.js 24.17 MiB 🔺 +5.0 KiB (+0.0%)
posthog-app/_parent/products/dashboards/frontend/widgets/experiments/ExperimentsListWidget.js 5.5 KiB 🔺 +1018 B (+22.0%)
posthog-app/_parent/products/dashboards/frontend/widgets/experiments/ExperimentResultsWidget.js 7.1 KiB 🔺 +1017 B (+16.3%)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.21 MiB · 22 files no change ███░░░░░░░ 28.1% of 4.29 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.10 MiB · 2,972 files 🔺 +19.6 KiB (+0.2%) █████████░ 87.6% of 9.25 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.5 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
3.9 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.4 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
789 B src/scenes/ChunkLoadErrorBoundary.tsx
668 B src/index.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
277.3 KiB ../node_modules/.pnpm/posthog-js@1.399.1/node_modules/posthog-js/dist/rrweb.js
266.9 KiB ../node_modules/.pnpm/@posthog+icons@0.37.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
224.6 KiB src/taxonomy/core-filter-definitions-by-group.json
221.5 KiB ../node_modules/.pnpm/posthog-js@1.399.1/node_modules/posthog-js/dist/module.js
164.0 KiB src/queries/validators.js
154.2 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
105.9 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

⚠️ Dist folder size — 🔺 +203.3 KiB (+0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 1438.40 MiB · 🔺 +203.3 KiB (+0.0%)

Playwright — all passed

All tests passed.

View test results →

Comment thread frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx
@trunk-io

trunk-io Bot commented Jul 10, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

The replay tile is also hidden whenever a conversion goal is set (the
!conversionGoal guard), so reading the removal experiment flag for
analytics-tab viewers with a conversion goal enrolled users neither variant
affects. Gate the flag read on !conversionGoal as well, so enrollment only
happens on the code path where the tile is actually shown or removed.

Generated-By: PostHog Code
Task-Id: 98495d89-d4bb-423c-b2b3-8efd32e3f9c0
@lricoy
lricoy merged commit 17c56b9 into master Jul 14, 2026
193 checks passed
@lricoy
lricoy deleted the posthog-code/web-analytics-remove-replay-tile branch July 14, 2026 19:48
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 14, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-14 20:22 UTC Run
prod-us ✅ Deployed 2026-07-14 20:47 UTC Run
prod-eu ✅ Deployed 2026-07-14 20:49 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants