Product View: live embedded browser with a PostHog analytics overlay - #4054
Draft
DanielVisca wants to merge 10 commits into
Draft
Product View: live embedded browser with a PostHog analytics overlay#4054DanielVisca wants to merge 10 commits into
DanielVisca wants to merge 10 commits into
Conversation
…istry Stage 1 of the Product View: a top-level Product tab that embeds the user's own site (live origin or localhost dev server) in a sandboxed WebContentsView. - @posthog/platform: IEmbeddedBrowser interface + EMBEDDED_BROWSER token, HostCapabilities.embeddedBrowser flag (desktop true, web false) - apps/code: ElectronEmbeddedBrowser adapter (own cookie partition, http(s)-only navigation, window.open denied → external browser) - @posthog/core: ProductViewService (main container) — navigation guards, page-state stream, product-URL suggestions from app_urls + $pageview hosts - @posthog/workspace-server: product_environments sqlite table + service (per-project page-origin/data-project registry, tab restore via currentUrl) - host-router: productView router (one-line forwards + event subscription) - @posthog/ui: /product route, ProductView (toolbar, URL bar, environment switcher, data-project badge), environment picker with data-derived suggestions; Product appView tab target + command palette entry Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
Stage 2: the analytics overlay, driven end to end by real PostHog data. - product-view preload (isolated world, closed shadow root): enumerates interactive elements, reports capped descriptors to the host, paints green/amber/red halos + inspect-mode hover/select — no credentials or page access ever cross the boundary - core elementMatching: parses /elements/stats/ rows (fixture captured from the live posthog.com project) and attributes autocapture/rage/dead click counts to live DOM descriptors, keyed data-attr > id > href > tag+text with ambiguity dropping - core healthScore: frustration-share health (rage+dead clicks) with a min-sample guard, and a clutter budget (all unhealthy + top-usage healthy) - ProductViewService overlay pipeline: inspector reports → per-page cached elements/stats fetch against the environment's data project → matched halos pushed back into the page - UI: Inspect toggle; view opens with the environment's dataProjectId Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
Stage 3: select an element, see its full story. - core detail queries (all shapes validated against the live posthog.com project first): 30-day usage trend, exceptions correlated via shared sessions, recent replay sessions, page web-vitals p75 — built from the element's strongest chain key (data-attr > id > href > text) with HogQL string/LIKE escaping of all page-derived values - LatencySampleBuffer: bounded rolling p50/p95/p99 over live requests - adapter CDP capture: fetch/XHR timing + traceparent trace ids only (never cookies/auth headers); requests within 2s of a click are attributed to that element; degrades cleanly when a debugger is already attached - preload: ambient (non-blocking) interaction reporting for attribution - ElementDetailsPanel: usage sparkline, frustration, error issues, live latency percentiles, request waterfall with trace markers, replay links — deep links open in PostHog cloud scoped to the environment's data project Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
Stage 4: act on what the overlay shows. - ProductCodeContextService (workspace-server): grep the local checkout for the element's stable keys (data-attr/id/text via git grep), surface recently-merged PRs from squash-commit subjects in `git log -- <files>` (pure parsing, tested) and open PRs whose diff touches those files via the gh CLI — degrading to git-only history when gh is unavailable - buildInvestigatePrompt (core, tested): verify-then-conclude prompt seeding page URL, element keys, usage/frustration totals, correlated error issue IDs, session IDs, live trace IDs, source files, and implicated PRs, with an ordered procedure over the posthog MCP tools and explicit drift caveats - InvestigateSection in the details panel: open/merged PR list + Investigate button that starts an auto-mode cloud task via the shared inbox task runner Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
|
React Doctor found 1 issue in 1 file · 1 warning. 1 warning
Reviewed by React Doctor for commit |
…rkline a11y role The quality check runs `biome ci` repo-wide, which is stricter than the scoped `biome check` used during development: import/export sorting in the DI wiring files and shared index, formatting in the host containers, and role="img" so aria-label is valid on the sparkline div. Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
Google (and other IdPs) reject OAuth from anything identifying as an
embedded webview, and popup-based SSO can't complete when window.open is
bounced to the system browser (no shared session).
- strip Electron/app tokens from the view's user agent (plain Chrome UA),
fixing Google's disallowed_useragent rejection
- allow http(s) popups as sandboxed, preload-less child windows on the same
persist:product-view partition so popup SSO completes; child windows get
the same clean UA, still block non-web schemes, and can't nest popups
Verified with an Electron harness: UA drops the Electron token, and
window.open('https://accounts.google.com/…') creates a shared-partition
child window with a clean UA.
Generated-By: PostHog Code
Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
…lbar menus The environment dropdown opened underneath the embedded page — the native WebContentsView paints above every renderer popover, so any menu over the page area was invisible. - environments are now inline toolbar pills: one click switches instantly (each environment keeps its own live view, so page state is preserved), nothing opens over the page in the hot path; "+" adds an environment and right-click on a pill removes it - new productViewObscuredStore: renderer popovers that can overlap the page (the pill context menu, alongside the existing command-menu case) hide the native view while open, with an unmount guard so a leaked acquire can't keep the page hidden Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
- parseGithubRemote: trim the remote URL — `git remote get-url` output ends with a newline, which stopped the ".git" suffix from being stripped, so merged-PR links pointed at github.com/<owner>/<repo>.git/pull/N (404) and the gh open-PR lookup got a garbage --repo value. Also accept ssh:// remotes. - toolbar: flex-wrap the row and truncate pill labels / the data badge so environments flow to a second line instead of crushing the URL bar. - stop resetting the embedded page mid-session: create() no longer navigates an existing view back to the environment's debounce-persisted URL, and the slot effect no longer tears down/reopens when the environments query refetches — either could yank a multi-step login back to a stale page. Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
…on, log popup decisions - saveEnvironment now updates in place when the project already has an environment with the same normalized origin — running the picker twice created duplicate pills (no way to end up with three identical us.posthog.com entries anymore) - each environment pill gets a visible ✕ (right-click remove stays) — closing was undiscoverable - the embedded view's window-open handler logs each popup request and verdict so "the SSO popup never opened" is diagnosable from main logs Generated-By: PostHog Code Task-Id: 1120fcea-fc07-4c54-8dbb-50b7b712f9cb
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Problem
Product owners using PostHog Code have all the data about their product — events, errors, latency, sessions, PRs — but no way to see it on the product itself. Answering "is this button healthy? who uses it? what breaks for them? which PR touched it?" means hopping between the app, PostHog cloud, and GitHub.
Changes
A new Product tab: a live embedded browser showing your own site (or a local checkout, e.g.
hogli start) with your PostHog project's analytics overlaid per element, and a one-click Investigate that starts an agent task seeded with everything the panel knows.How it flows (page source and data source are decoupled — a localhost checkout can render production analytics):
/elements/statschains matched against live DOM descriptors, keyeddata-attr > id > href > tag+text, with ambiguous keys dropped. Health comes from rage/dead-click share with a minimum-sample guard.git log -- <files>), open PRs viagh pr list(degrades to git-only without gh).traceparent(never cookies/auth headers); http(s)-only navigation,window.opendenied.@posthog/platformcapability (IEmbeddedBrowser+HostCapabilities.embeddedBrowser, stubbed false on web), newproduct-viewmodules in core/workspace-server/host-router/ui, one additive sqlite migration, aproductappView tab target, and a command-palette entry. No existing behavior changed.How did you test this?
/elements/statsendpoint, health thresholds, HogQL builders incl. escaping of hostile page-derived values, overlay pipeline (reported elements → project-scoped stats fetch → halos pushed), environments persistence through the real sqlite migration, PR-subject parsing, investigate prompt content.productViewPreload.jsin a realWebContentsViewloading live posthog.com under Xvfb, matched the reported DOM against real project element stats with the real matcher, and screenshotted both ambient halos and inspect-mode badges rendering correctly. (Screenshots carry usage figures, so they're in the task thread rather than this public PR; the steps below reproduce them.)pnpm typecheck(24/24 incl. web portability),biome lint packages/core(zeronoRestrictedImports),node scripts/check-host-boundaries.mjs(no new violations),electron-vite build(both preload bundles), Playwright e2e: 12/13 passed, the one failure ("window minimum dimensions") reproduces on a clean tree under Xvfb — pre-existing environment issue, not this change.Validate it yourself
gh pr checkout <this PR> && pnpm install && pnpm devapp_urls+ pageview hosts) — e.g. posthog.com for the PostHog App + Website project. Green/amber/red halos appear on elements with autocapture history within a few seconds.traceparentis present).hogli start), addhttp://localhost:8010as an environment via the switcher — the same production halos overlay the local page.Automatic notifications
Created with PostHog Code