Legal and privacy

What we store

Per storage mode: what reaches our servers, what never does, and how long we keep it. Numbers come from the code's own constants, and tests fail if this page and the code disagree.

Every remote playtest passes a little metadata through our broker (codes, session state, upload authorisation), whatever bucket the footage itself goes to. What differs by mode is where the recording goes, and whether our servers can read it.

Private bucket (S3 or R2)

Your own Amazon S3 or Cloudflare R2 bucket, set up and verified project by project.

A lent read key (Private bucket, opt-in per project)

One switch, all-or-nothing, asked with a named statement (mulno_reads_this_projects_sessions/v1): "Mulno's servers will read this project's sessions — video, audio, events, notes and transcripts — to index them, show them in the browser and answer AI questions. The files stay in your bucket."

Mulno Cloud

Our own Cloudflare R2, one sessions bucket and one builds bucket per region (mulno-sessions-<region>, mulno-builds-<region>) — never shared with a Private project's own bucket.

Every mode: the broker's own records

Whatever bucket the recording goes to, a remote playtest's invite code, session and upload state pass through our broker, which keeps, the same in every mode:

HeldRetention
Invite codes, as a one-way hash, plus a 4-character hint90 days after the campaign closes, expires or is killed
A session's state (including whether the tester withdrew), the yes/no age answer, times, byte counts, which files it uploaded90 days after the campaign closes, expires or is killed
An NDA acceptance: the NDA's version, a SHA-256 of its text and when, stored against the invite code's hash (never the text, never a name)90 days after the campaign closes, expires or is killed
Which version of the studio's privacy notice for its testers the Launcher showed a tester: the notice's version, a SHA-256 of its text and when, stored against the session (never the text, never a name; it records that the notice was shown, not that anyone agreed to it)With the session's row, above: 90 days after the campaign closes, expires or is killed
Upload tickets, as a one-way hashValid until the session closes, at most 72 hours; the hash itself is deleted with the session's row (above)
A capture-health record: recorder/encoder versions, Windows build, GPU vendor (a closed set), capture and upload numbers90 days
A keyed, truncated hash of the tester's IP address, for rate limitingAbout an hour
When a tester asked on our deletion page for the session to be deleted (shown to the studio, which can restore a hidden Mulno Cloud session within 30 days; for one in the studio's own storage, the studio decides)With the session's row, above, or until the studio deletes the session; for a Mulno Cloud session the broker's record of it goes when Mulno's copy of the recording does, 30 days after the request
Mulno's own traffic log (Thailand's Computer-Related Offences Act s.26): per request, the time, method, route pattern, status and the readable source IP address. It holds no session, campaign or studio id, so it can't be joined to a recording; Mulno keeps it as its own legal obligation, not for the studio90 days
The campaign itself: its name, settings and limits — filed under the workspace's own opaque id, never the name your members typedWhile the workspace exists; when it is closed, deleted with everything above within 30 days (below)
The studio's own NDA text, when the campaign has one — its plain wording, not a hash (unlike the acceptance record above, which keeps only a SHA-256 of it)Same as the campaign itself, above
The studio's own privacy notice for its testers, when the campaign has one — its plain wording and version, which the Launcher shows before a build downloads. It is the studio's notice (the studio is the controller of its testers' data); we keep only the current text, a SHA-256 of it and when it was savedSame as the campaign itself, above
The broker's audit log of campaign actions (codes minted or revoked, campaigns killed, bucket changes, redemptions and uploads, without a person's name)1 year, also after the workspace is closed

A campaign with no end date never starts its 90-day clock: set an expiry, or close it when the playtest ends.

Separately, each workspace has its own audit log in its own region (sign-ins, member changes, storage and lent-key changes), kept a year. Every read our servers make of a Private project's recordings under a lent key is written there too (D114). Reads of a Mulno Cloud project's own storage aren't logged one by one.

Never held, in any mode: a tester's name, e-mail address or birth date, or their IP address in readable form anywhere but the traffic log above. Deleted rows can remain in Cloudflare's point-in-time database backups for up to 30 more days, which cannot be turned off.

When a workspace is closed

An owner closes a workspace in its settings; it can't be closed while a subscription still bills. At once, every member, invitation and AI connection is removed, its campaigns are stopped, and testers can no longer upload to it or download its builds. Then:

WhenWhat we delete
From day 14 after the closing (a job that runs every hour)Every Mulno Cloud recording and build of its projects, each project's session index (including what a lent key let us derive), and every row our api holds for the workspace: projects, builds, branches, campaigns, sessions, storage and billing records, its legal name and its Terms record
Right after that, retried until done, within 30 days of the closingEverything our broker holds for it: campaigns and their NDA text, invite-code hashes, sessions with their upload records and ticket hashes, NDA acceptances, the records of which privacy notice was shown, capture-health records, sealed bucket credentials and the workspace's broker tokens

What stays, and why:

KeptUntil
The workspace's audit log, and the broker's audit log of its campaigns (fixed fields: the action, the id of what it touched, the outcome, the time). The workspace's own entries name the member who acted until we delete the workspace's rows; then every member's address, account id and IP-address hash is taken off themEach entry's own year ends
A record at the broker that the workspace existed and was deleted: its opaque id, plan and dates, marked suspended, with the name "deleted" and no contact, so the id can never be given access againAs long as the broker runs
A record that the closing was asked for and done: the workspace's id, the id of the account that asked, the timesUp to 3 years
The traffic log (it holds no workspace, campaign or session id)90 days from each request
Rate-limit counters (keyed hashes)About an hour
Cloudflare's point-in-time database backupsUp to 30 more days

Not ours to delete: the recordings in your own Private bucket. We delete our sealed copy of its key, never its objects.

One caveat that applies to region, in every mode

A workspace can choose where its own rows live (Asia-Pacific, the EU's guaranteed jurisdiction, or the US). Everything in the broker table above — the campaign, invite-code hashes, sessions and their upload records, NDA acceptances, privacy-notice records, capture-health records and the broker's audit log — still lives in one Asia-Pacific database today (a Singapore location preference, not a guarantee), whatever the workspace's region, until the broker itself becomes regional. The broker never learns a workspace's typed name either way: it files a campaign under the workspace's own opaque id, not the name your members chose for it.

An EU workspace cannot create a campaign at all today. Rather than run one whose rows would sit outside the EU regardless of your choice, we refuse the request outright, in plain words, until the broker itself is regional. Every other feature (projects, builds, branches, members, storage) is unaffected — only creating a *new* campaign is blocked for an EU workspace.

Where Mulno is a controller, not your processor

What changed on 2026-10-18

What changed on 2026-10-08

What changed on 2026-10-04