How Flutter web renders
Flutter web can render through different paths. The production default for most apps is CanvasKit, a WebAssembly build of Skia that draws the entire UI to a WebGL canvas. The newer Skwasm renderer paints to canvas via WebAssembly too. Either way, the output is pixels on a canvas, not an element tree.
This is by design: it gives Flutter pixel-perfect, platform-consistent rendering and the same drawing engine as native. The trade-off for observability tooling is that the semantic structure of the UI is not present in the DOM.
Why DOM recorders return a blank box
rrweb-style recorders (the engine behind PostHog, and conceptually similar to Clarity, Hotjar, FullStory, and LogRocket replay) walk the DOM, snapshot it, and stream subsequent mutations. Open your browser inspector on a CanvasKit app and you can see the problem yourself: under the host element sits a <flt-glass-pane> and a <canvas>, and that is essentially it. The recorder snapshots that one opaque element and has nothing else to stream.
Flutter does expose a semantics tree for accessibility. But it is sparse, tuned for screen readers rather than visual fidelity, and nowhere near enough to reconstruct what the user saw. Even tools that try to read it cannot produce a faithful replay.
The frame-capture approach
The approach that works on CanvasKit is to capture the rendered frames directly, the same pixels Skia draws, and encode them efficiently off the main thread, with privacy masking applied at capture time before anything leaves the device.
Pixeltrace is built around exactly this model for Flutter web. It's in development; join the waitlist to be notified when it's available.