Engineering note
It would be, done naively. Feeding raw event streams to a model is the obvious implementation and the one that makes margin collapse the moment anyone actually uses the product. Here is what GhostView does instead.
The reduction pipeline
rrweb DOM mutations plus named interaction events, streamed from the embed. Inputs are masked at the source and no IPs are stored, so the sensitive material never enters the pipeline in the first place.
computeSessionAnalytics() walks each event stream in plain code — no model involved — and emits one compact summary per session: duration, page visits, idle gaps, click count, error count, and rage-click detection. Rage-clicks are found by a timing heuristic, not by asking an LLM to notice them.
A single model call reads every session summary together and returns structured JSON — friction points, behavioural clusters, a prioritised fix list, and an executive summary. It is the only stage that sees the whole corpus, and it never sees a raw event.
The important property: the expensive stage sees a fixed-size input no matter how long your users stayed. A 40-minute session and a 40-second one cost the same to reason about, because both arrive as a trace.
What it actually costs
Stages 1–2 are deterministic code. The model only ever receives computed per-session summaries — which is simultaneously the cheap path and the smaller privacy surface.
Prompt size grows with the number of sessions, not with how long anyone stayed. A 40-minute session and a 40-second one reduce to summary objects of the same size.
A synthesis run over a few dozen sessions is a single call with a few thousand tokens of input and a 4k output cap. The expensive naive design — streaming raw events into context — is the one we specifically do not do.
Replay payloads, not inference, are the cost that grows with usage. That is why retention is a published number rather than an unbounded promise.
Published because “AI feature with unexamined inference cost” is a fair thing to be suspicious of. These are structural properties of the pipeline, not projections \u2014 you can read the shape of it in the reduction stage above.
The output is for machines too
If an LLM generated your checkout flow, a human copying findings out of a dashboard and back into a prompt is a silly place for the loop to break. Synthesis findings are structured, cite their evidence, and are retrievable as JSON — so the coding agent can consume the friction report directly and propose the fix.
Findings, structured for a consumer that isn't a person:
POST /api/synthesis { "projectId": "…" }
{
"projectId": "…",
"sessionCount": 9,
"synthesis": {
"frictionPoints": […],
"patternClusters": { "strugglers": […], "completers": […] },
"prioritizedFixes": […],
"executiveSummary": "…"
}
}Same findings you see on the demo page, addressed to a different reader.