Session replay for Flutter

See exactly what your users saw.

Picto replays a real session from your app in your browser, with every exception, frozen frame and rage tap marked on the timeline — so you land on the moment it broke instead of hunting for it.

Sessions from ~8 KB One package, two lines Masked by default
Real recording, replayed in your browser 12s · 8 KB · fully interactive
Early access

Be first in line when we open up.

Picto is opening up in waves. Leave your email and we'll tell you the moment your spot is ready — that is the only mail you will get from us, and the rest of this page is yours to read either way.

More than a recording

Every signal lands on the timeline, one click from the moment it happened.

A screen recording tells you a session went wrong somewhere. Picto captures the four things that actually go wrong and links each one to the exact frame — so "reproduce it" stops being a step.

Exceptions

Every caught and uncaught error, grouped by type and message so one bug is one row rather than four hundred. Carries the stack, the platform, the app version, and which user hit it.

Opens the replay at the throw →

Frozen frames

Frames that took longer than 700ms to build and raster, split into both numbers so you know whether to look at your widget tree or your painting. You watch the freeze happen in the replay, the way your user felt it.

Opens the replay at the stall →

Rage and dead taps

Clusters of repeated taps in one spot, classified as rage, dead or error — the signal that something looked tappable and left the user stuck. Found in the taps your recording already carries, so the SDK you have is all it takes.

Opens the replay at the cluster →

Alerts

Any of the above crossing a threshold inside a rolling window posts to Slack or any JSON endpoint, and optionally emails an on-call address. You stop having to watch the dashboard.

Configured per app →
Two minutes

Add the package, wrap your app. That is the integration.

Pure Dart and Flutter, so your Xcode project, your Gradle config and your build steps all stay exactly as they are. Recording begins on your call, so the package can ship well ahead of the day you switch it on.

1

Add the package

flutter pub add picto. Pure Dart and Flutter — Xcode and Gradle stay exactly as they are.

2

Wrap runApp and point it at your project

One binding and your API key. Recording starts the moment you call it, and runs until you stop.

3

Watch the session back

Sessions appear in the dashboard as they upload, with their signals already cross-referenced.

main.dart
import 'package:picto/picto.dart';

void main() {
  Picto.init(
    apiKey: 'oc_your_key',
    ownerId: 'your_account_id',
  );

  // Records until you stop it. Uploads on stop.
  Picto.startRecording();

  runApp(const MyApp());
}
Privacy

Record the interface. The person using it stays private.

Session replay is a hard sell internally, and it should be. Picto is built so the answer to "what exactly leaves the device?" is short.

  • Layout is what gets stored. A recording carries the shape of your screens — how everything was laid out and how it moved. What your users read and typed stays on the device.
  • Text records as a placeholder. Images mask until you opt in. A placeholder bar is the only shape the recorder can produce for text — that is the whole code path. Images render as blocks too until you opt a widget in, so every new screen ships private by default.
  • ExcludeFromRecording for the rest. Wrap a subtree and it is captured as an empty shape — the layout survives, the content stays on the device.
  • What your app paints is the whole picture. Picto only ever sees what your app puts on screen — keystrokes, the clipboard, the accessibility tree and device identifiers all stay outside it.
checkout_page.dart
// Anything inside is recorded as a solid block.
ExcludeFromRecording(
  child: CardNumberField(
    controller: _card,
  ),
)
Compared with the tools you have heard of

Web replay tools were built for the DOM. Picto was built for Flutter.

That difference is why general-purpose session replay struggles here, and it is the whole reason this exists.

Picto
DOM-based replay Screen video capture
What is captured Every screen your app renders, app-wide HTML mutations Compressed pixels
Fidelity Faithful to the last detail, custom painters and shaders included Approximate; canvas content is typically a blank rectangle Exact, but lossy and heavy
Session size Kilobytes — an interactive 12s session is about 8 KB Small, when it works at all Megabytes per minute
Jump to an error Every exception, freeze and tap cluster is a timeline marker Console logs, correlated by timestamp Scrub and hope
Battery and CPU Light enough to leave on in production Low Continuous video encoding on device
Billing starts when you pick a plan

Watch the bug happen instead of reproducing it.

Add the package, record a session, and watch it back in the time this page took to read.