Picto
Home Features Pricing Docs
Join waitlist
Home Features Pricing Docs
Join waitlist

Privacy Policy

Last updated 14 August 2026

Picto records what a Flutter app draws so you can watch a session back and see what went wrong. This policy explains what that recording contains, what it structurally cannot contain, what we store about you as a customer, and how long any of it survives.

It is written to be checkable. Where the answer is that we do not do something yet, it says so, rather than leaving the impression that we do.

Contents
  1. Who this policy is for
  2. Our two roles: controller and processor
  3. What we collect about you
  4. What a recording contains — and what it cannot
  5. The parts you control, and we do not filter
  6. Where it is stored, and who else sees it
  7. Cookies and this website
  8. How long we keep things
  9. Deletion and your choices
  10. If you are an end user of an app that uses Picto
  11. Security
  12. Changes to this policy
  13. Contact us
  1. Who this policy is for

    This policy covers picto.dev, the dashboard at picto.dev/dashboard, the API at api.picto.dev, and the picto SDK you add to your Flutter app. It does not cover your own app, which is yours.

    Two different groups of people are described below, and they have different relationships with us. You — the developer or company with a Picto account — deal with us directly. Your end users, whose sessions your app records, do not; they deal with you.

  2. Our two roles: controller and processor

    For your own account information — your name, your email address, your organization, your subscription — we decide what is collected and why. Under the GDPR and comparable laws we are the controller for that data, and this policy is our notice to you about it.

    For everything your app uploads about your end users, you decide what your app records, when it records, which parts of your UI are excluded, and what strings you attach. We only store it and show it back to you. You are the controller for that data and we are your processor. Deciding what is lawful to record from your users, and telling them about it in your own privacy notice, is your responsibility, not ours.

  3. What we collect about you

    When you create an account and use the dashboard, we store:

    • Your name and email address, and a hash of your password — never the password itself.
    • The organizations and client apps you create: their names, their API keys, and which account owns them.
    • Collaborators you invite to an organization, by the email address you enter.
    • Your subscription: which plan you are on, its status, your recorded-minutes usage for the current period, and the customer and subscription identifiers Lemon Squeezy gives us. We do not receive or store your card number, expiry or security code — Lemon Squeezy is the merchant of record and takes the payment; our billing code only ever sees their identifiers.
    • Alert rules you configure, including the webhook URL and optional email address you tell us to notify.
    • If you join the waitlist, your email address. If you send an enterprise enquiry, the name, work email, company, volume estimates and free-text notes you type into that form.

    Our API applies per-IP rate limits to sign-up, sign-in, recording upload and enquiry endpoints, so your IP address is processed for abuse prevention when you make those requests.

  4. What a recording contains — and what it cannot

    Picto is not a screen recorder. It does not capture video, take screenshots, or read your app's widget tree for its contents. It records the drawing commands your app issues, and replays them.

    On-screen text is never recorded as characters. When Flutter draws a paragraph, the recorder captures only the bounding boxes of each laid-out line — an offset and a list of rectangles. This is structural rather than a policy we apply on top: dart:ui exposes no API to read the glyphs back out of a laid-out paragraph at all, so there is no code path that could record the text even by mistake. On replay, each line of text is drawn back as a translucent grey bar.

    There is one deliberate exception, and we would rather state it precisely than round it up into a guarantee we cannot keep. Small, square-ish glyphs — roughly 10 to 128 logical pixels, the shape of a back arrow or a hamburger menu — are rasterized as real pixels, because they are interface chrome and a grey box in their place makes a replay unreadable. That check works on size and on how many glyph clusters the line contains, never on the character itself. A genuine single-character input — a user who has typed exactly one letter into a field — is indistinguishable from an icon by that check and is also rasterized. Anything two characters or longer stays a placeholder.

    Images are recorded as a same-sized grey placeholder rectangle by default. Real image bytes are only captured when your app explicitly opts a subtree in with CaptureRealImages or CaptureVectorGraphics, or when the image resolves to an asset already bundled with your app that you have uploaded to us separately.

    Anything wrapped in ExcludeFromRecording is not captured at all — not its contents, not its position, not its size. Live rendering in your app is unaffected.

    Alongside the drawing commands, a recording carries the platform name, your app version, a session identifier, a sequence number, the session's duration and size, whether an error occurred, frame timing statistics, and any metadata your app attached.

    Our servers never decode a recording. They store and serve the byte stream opaquely; every render happens on a device you control — the replay app on the recording device, or the replay viewer running in your own browser when you watch a session in the dashboard.

  5. The parts you control, and we do not filter

    The protections above are about what your app draws. Several other channels carry strings your app hands us directly. We do not scan, redact or mask any of them, and ExcludeFromRecording has no effect on them, because they are not drawing at all:

    • Exception type, message and stack trace, captured automatically once you install the error hooks. If your app interpolates a value into an error message — an email address, an order number, a user's name — that text is uploaded exactly as written.
    • Tags you set with setTag: arbitrary key/value strings of your choosing.
    • The end-user identifier you pass to Picto.identify. It is stored as given, on recordings, exceptions, jank events and rage-tap events alike, and shown in the dashboard.
    This is the main way personal data reaches Picto. If you pass an email address as the identifier, we store an email address. Passing an opaque, internal identifier instead is the single most effective thing you can do to keep personal data out of this service.

    Network capture is off unless you opt in by routing requests through PictoHttpClient. Even then, only the request method, the URL, the response status code and the duration are recorded. Headers and request and response bodies are never recorded. The query string is stripped from the recorded URL by default; your app can turn that off, in which case whatever your query strings contain is recorded.

  6. Where it is stored, and who else sees it

    Picto runs on Fly.io. As configured today the application runs on a single machine in Fly's us-east (iad) region, with the database on one volume attached to that machine. All data described in this policy is stored there, in the United States. Traffic to the service is served over HTTPS and plain HTTP requests are redirected.

    We use these subprocessors, and no others:

    • Fly.io — hosting, compute and storage for the entire service (United States).
    • Lemon Squeezy — payments and merchant of record. They handle checkout, card details, invoices and the billing portal; we receive subscription status and identifiers back from them.
    • Google — this website loads its typeface from fonts.googleapis.com on every page, and the replay viewer connects to www.gstatic.com to fetch the Flutter web engine it runs on. Both requests disclose your IP address, and the browser headers that accompany any request, to Google. We would rather not be telling you this; self-hosting the font is a known, planned change.

    If you configure an alert rule with a webhook URL — a Slack incoming webhook, say — we will POST alert notifications to it on your instruction. That destination is chosen by you and is not our subprocessor. What happens to the data once it arrives is between you and whoever runs that endpoint.

    We do not sell personal data, we do not share it for advertising, and we do not use recordings, exceptions or any end-user data to train machine-learning models.

  7. Cookies and this website

    There is no analytics on this site. No Google Analytics, no tracking pixel, no session-replay script — we do not run our own product on our own marketing pages either.

    We set exactly one cookie, and only after you sign in: it holds your authentication token so you stay signed in between visits. It is set with SameSite=Lax and lasts up to a year, or until you sign out. You cannot use the dashboard without it.

    The font and replay-engine requests described in section 6 are made by your browser directly to Google and are not cookies we set.

  8. How long we keep things

    Session recordings are deleted 30 days after they are uploaded. A job runs daily and removes every recording older than that. This is not configurable, and there is no way to extend it or to recover a recording afterwards — plan around it.

    Exceptions, jank events and rage-tap events are kept for as long as your account exists. They are stored separately from recordings and the 30-day job does not touch them, so an exception outlives the session recording it came from. If your app puts personal data into exception messages or tags, that is the retention period it gets.

    Asset images you upload for replay are kept until you delete them or your account is closed.

    Account, organization, client-app and subscription records are kept for as long as your account is open, and afterwards only where we need them for a legal or accounting obligation. Waitlist and enterprise enquiries are kept until we have finished dealing with them.

  9. Deletion and your choices

    You can delete a client app or an organization from the dashboard at any time. Doing so deletes the recordings, exceptions, jank events and rage-tap events stored under it.

    You can close your account yourself, from the Account section of the dashboard. We ask for your current password first, even though you are already signed in, because the action cannot be undone.

    Deleting your account deletes every organization you own, and everything inside it: client apps, session recordings, exceptions, jank events, rage-tap events and uploaded assets. This includes data uploaded by collaborators you invited, which they can currently see and will lose. Those collaborators are not asked and are not notified. Before you confirm, we show you each organization by name with the number of collaborators, client apps and recordings that will be destroyed, and you have to type an organization name to proceed.

    If you are a collaborator on somebody else’s organization, your membership is removed and that organization is left untouched.

    If your organization has a paid subscription, we cancel it at Lemon Squeezy before deleting anything. If that cancellation fails, we stop and delete nothing, rather than leave you paying for an account you can no longer reach.

    Deletion is immediate and permanent. There is no grace period, no disabled state and no way for us to restore an account afterwards. We keep no backups and no archive, so there is no copy to age out later and nothing to recover from if you change your mind.

    Two things survive, and neither contains anything that identifies you. We keep a record that a deletion happened — the date, how many organizations, apps and recordings were removed, whether it was self service, and a one-way hash of the account id, which cannot be turned back into your identity. Separately, Lemon Squeezy is the merchant of record for payments and keeps its own invoice and tax records, which we cannot delete on your behalf.

    We do not send a confirmation email, because we do not send email at all yet. The dashboard confirms the deletion on screen at the time.

    You can access, correct or export the account information in section 3 by asking us, and we will not charge you for it. If you are in the UK, the EEA or a jurisdiction with comparable law, you also have the right to complain to your data protection authority.

  10. If you are an end user of an app that uses Picto

    We hold your data only on behalf of the developer whose app recorded your session, and we cannot identify you from what they send us unless they have chosen to send an identifier that means something to them. We have no relationship with you and no way to verify who you are.

    So requests to see, correct or delete your data have to go to that developer — the operator of the app you used. If they instruct us to delete it, we will. If you contact us directly, we will forward your request to them if we can work out which of our customers it concerns, and tell you if we cannot.

  11. Security

    Traffic to and from the service is encrypted in transit over HTTPS. Dashboard access requires a signed token; recording uploads require a per-app API key. Rows are scoped to the organization that owns them so one customer cannot read another's data.

    We are a small team running a small service, and we would rather be plain about the limits of that than imply certifications we do not hold. We hold no security certification. We add no encryption at rest of our own on top of whatever our hosting provider applies to its disks, and we do not currently keep an audit log of administrative access to customer data. If either of those matters to your deployment, tell us before you send us production sessions.

    The single most reliable protection available to you is not to send us the data in the first place: exclude sensitive subtrees, keep personal data out of error messages and tags, and identify users by an opaque identifier.

  12. Changes to this policy

    If we change this policy in a way that materially affects what we collect, how long we keep it, or who else processes it, we will email the address on your account before the change takes effect. Smaller clarifications will show up as a new date at the top of this page.

  13. Contact us

    The controller for the data described in section 3 is [legal entity name], at [registered address]. Privacy questions, deletion requests and anything else about this policy go to [privacy contact email].

© 2026 Picto
Home Features Pricing Enterprise Docs
Privacy Terms