Data export
A person downloads everything Gemmein holds about them.
What it is. A "download my data" button for the people in your app. One call returns everything a person holds in your app, so you can meet a request for their data (GDPR right of access and portability) without building it.
What it does.
- Collects.
g.account.export()returns one JSON document: their profile; the records they wrote or that name them, grouped by collection; their likes and flags; their files as download links; purchases, plan, credits and the credit ledger; access grants; AI calls and runs; the emails your app sent them; their conversations with your support inbox; their sessions, with the IP address each signed in from and was last seen on, and their sign-ins, sign-outs, checkouts started and exports, each with its time and IP address. An address is there for 30 days. - Opens with a cover. The
aboutobject at the top says what the document is, your app's name, when it was generated, whether the person or you produced it, the sections it holds (their caps are inlimits), what it leaves out and why (your tool prompts, your team's identities, other people's data, and on the person's own copy the notes your team wrote, which they ask you for), your Terms of Service link if Payments has one (termsUrl), your support address if you have one (ownerContact), and one line on their rights: they can ask you to correct or delete their data. - Stays bounded. Each section has a cap: 5,000 records; 1,000 files, likes
and flags, purchases and AI calls; 199 runs and credit ledger lines; 99 emails; 500
sessions and sign-ins; 200 support conversations. Records, AI calls, runs and support
messages together stop at 25 MB. A section is named in
limits.truncatedonly when something in it was left out. Sign-ins are read from the newest 10,000 entries of the person's account history, and named when the history runs longer. - Follows your rules. It holds what that person may read under your safety rules, and nothing another person keeps private: no tool prompt of yours, no note you wrote, no sender address on your replies. People named on a group message appear as ids, as they do on the record.
- Works from the dashboard. On a customer's page, Export their data
downloads the same document, plus
ownerNotes: the notes your team wrote about the person (a comp's note, an access grant's note, the reason your server or an automation gave on a credit change), with when each was written and never who wrote it. The notes stop at 199 (limits.caps.ownerNotes), andownerNotesis named inlimits.truncatedwhen one was left out. They are flagged for review: they are usually the person's data, but you may withhold one case by case, for example where it reveals someone else. In Live it asks for a code from your email first, and the export is recorded on their history: who exported it, and when. - Has a limit. A person exports their own data once every 30 days, counted from their last export; an attempt that fails or is never handed out does not count. You export a person's data from the dashboard once a day, counted from the last export, on a separate count, so you can always answer a formal access request.
What it does not do.
- Keep file links. A private file's link works for 5 minutes; a file in a collection anyone can read keeps its permanent public link. The file stays in your app.
- Run from your server with a secret key. A person exports their own data, or you export it from the dashboard.
When you need something else.
- To delete the data rather than copy it:
g.account.delete(), below.
Example. A settings screen with a download button.
const data = await g.account.export()
const file = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" })
// hand it to the browser as my-data.json
What happens if…
| If… | What happens | What you do |
|---|---|---|
A person runs account.export() | One JSON document of their data comes back, and the export is on their history in Logs | Save it as a file for them |
| A collection is locked to a plan they no longer hold, or a rule hides it from them | Those records and files are left out of the export | Nothing |
| A section passes its cap, or the 25 MB of text is reached | The export stops there, and limits.truncated names each section that was cut | Nothing |
| They export again within 30 days of their last export | 429 export_rate_limited with resetAt, a sentence giving the date and saying they can still ask you for their data, and ownerContact: your support address, or null when you have none. The refused export is in Logs. Your exports from the dashboard count separately, once a day per person | Show the message; try again after resetAt |
| They ask again while their export is still being prepared | 429 export_rate_limited at once, with resetAt a couple of minutes away and a sentence saying an export is already being prepared. One export of a person is prepared at a time on each side, theirs and the dashboard's | Wait for the first to arrive, or try again after resetAt |
| The export's row in Logs cannot be written | 503 audit_unavailable, and nothing is handed out | Try again |
| A private file's link in the export has expired | The link no longer opens after 5 minutes. The file is unchanged. A file in a collection anyone can read has a permanent link and no expiry | Export again, or open the file in the app |
account.export() is called while signed out | 401 authentication_required | Sign the person in first |
| You export them from the Customers page | The same document downloads. In Live, it asks for a code from your email first. Logs shows who exported it and when | Nothing |
| The person has deleted their account | There is nothing to export: their own export is 401, and the Customers page no longer lists them | Nothing |
Was this page helpful?
Thanks for telling us.
Thanks for telling us.
Last updated