Install
openclaw skills install @globalcaos/chatgpt-exporterExport all your ChatGPT conversations instantly — full context, timestamps, and metadata in seconds. Built for the TinkerClaw fork — github.com/globalcaos/tinkerclaw. Invoke it BY NAME — "chatgpt-exporter-ultimate: export my conversations" — so ordinary talk about ChatGPT cannot trigger it. Rides the ChatGPT session your browser already holds — browser relay or a bookmarklet you paste yourself. It reads NO access token, no cookie jar and no credential file. It enumerates your conversations — including ones inside Projects, found by running searches against your history — and writes JSON and Markdown copies to a private directory. Defaults to index-only (titles and timestamps, no message text); full content needs an explicit confirmation. Destinations are resolved through symlinks before anything is written, so an export cannot land in a synced folder or a git repo. A validated --purge deletes an export again. Off switch documented in the skill.
openclaw skills install @globalcaos/chatgpt-exporterOne of dozens of skills and plugins in TinkerClaw — a self-improving OpenClaw fork that's been running 24/7 for months.
Your entire ChatGPT history, exported in seconds — not tomorrow.
--purgeAn export is a plaintext copy of every conversation you have had. Leaving it on disk is usually a
bigger risk than the API call that created it, so cleanup is a first-class command rather than an
rm -rf you are trusted to type correctly:
./scripts/export.sh --purge -o ~/.local/share/chatgpt-export/2026-01-31
./scripts/export.sh --purge-expired # everything past the expiry in its own manifest
This is destructive, so the target is validated rather than trusted. The directory that gets deleted is the exact one you named — no parent is ever derived from it — and it is deleted only if all of the following hold:
realpath (so every symlinked component is resolved first);$HOME, at least two levels
deep — $HOME itself, /, and anything one level down are refused outright;.chatgpt-export-manifest.json that this tool wrote. An arbitrary folder that
happens to hold an index.json is not accepted as proof of ownership;PURGE at the prompt, in an interactive terminal. It refuses to run headless;It removes local copies only — your ChatGPT account is untouched. These rules are not a
promise in a README; they are covered by scripts/purge-selftest.sh, which runs the refusals
against a throwaway $HOME and never touches your real one.
Install the skill. Run it. Get your full export. That's it.
ChatGPT's built-in export makes you wait a day and hands you raw JSON. This skill respects your time.
Won't: email you a ZIP file 24 hours later like you requested declassified government documents.
👉 Explore the full project: github.com/globalcaos/clawdbot-moltbot-openclaw
Clone it. Fork it. Break it. Make it yours.
An export is a plaintext copy of everything you have ever said to ChatGPT, sitting on your disk. Whatever you pasted into a chat is in there: API keys, passwords, medical questions, legal problems, salary numbers, your employer's confidential material, other people's personal data.
Once written, those files are ordinary files. Anything running as your user can read them, your backup tool will pick them up, and a sync client will happily push them to a cloud you did not think about. So:
~/.local/share/chatgpt-export/<date>), and a destination that looks synced, sits inside a
git repo, or leaves your home directory is refused — with no override. The check resolves
symlinks first, so a link named exports that points into Dropbox is judged on where it
actually goes../scripts/export.sh --purge -o <dir>.
Every export records an expiry (30 days by default); --purge-expired clears the ones past it.This skill will not export anything until you say yes, and it tells you what it is about to do before it asks.
Short version: your conversations travel from chatgpt.com to your disk, and nowhere else. There is no server of ours in this picture. Longer version, because you should not take that on trust:
Where the data goes. Each path fetches from chatgpt.com/backend-api and writes files
locally. There is no upload, no telemetry, no analytics, no third-party endpoint of any kind.
The only network destination in the entire package is chatgpt.com.
What gets written, and where.
| Path | Default output | Files |
|---|---|---|
scripts/export-conversations.ts (relay) | ~/.local/share/chatgpt-export/<date> | index.json, summary.md, .chatgpt-export-manifest.json, per-conversation .json + .md |
scripts/export.sh (token) | ~/.local/share/chatgpt-export/<date> | index.json, .chatgpt-export-manifest.json, per-conversation .json + .md |
scripts/bookmarklet.js (browser) | your browser's Downloads folder | one chatgpt-export-<date>.json |
Directories are 0700 and files 0600 — enforced on every run, not only when they are first
created, so reusing an export directory that is already world-readable cannot leave your
conversations exposed. You can choose the destination, but one that looks synced (Dropbox, Drive,
OneDrive, iCloud, Nextcloud…), sits inside a git repository, or resolves outside your home
directory is refused, with no override.
The check runs on the resolved path, not the one you typed: ~/exports that is a symlink to
~/Dropbox/exports is refused. The destination is canonicalized through every symlinked
component — including ancestors that exist while the export directory does not yet — before
anything is written, and re-verified after the directory is created. The default is a dedicated
private directory rather than the top of $HOME, because that is where sync clients look.
./scripts/export.sh --check-dest <dir> vets a destination and prints what it resolves to,
without writing anything.
Every export drops a .chatgpt-export-manifest.json marker recording when it was written and when
it expires. That marker is what makes the export deletable by --purge, and nothing without it
will be deleted.
How it authenticates — and the honest part. ChatGPT has no public API for reading your own conversation history. The only way to do this is to talk to the same private endpoints the web app uses, as you. That is the skill's core mechanism, and there is no version of it that avoids touching your session. What we can do is minimise it, and we do:
credentials: 'include'. Reads no token at all.scripts/export.sh does not export at all. It makes no network call and
handles no credential; it is the cleanup half (--purge, --purge-expired, --check-dest).No bearer token, anywhere. Nothing in this package reads, stores, forwards or replays one;
scripts/dest-safety-selftest.sh fails if any script regains the ability. The cost is headless
export — there is no unattended path. If you need one, use ChatGPT's own 24-hour export.
Capabilities, and why each one is needed.
| Capability | Why | Scope |
|---|---|---|
| Network | List and fetch your conversations | chatgpt.com/backend-api only. No other host, ever |
| Browser session (cookie) | Authenticate as you — there is no other way in | Same-origin, inside the page; not copied out |
| Session token | None. No path reads, stores or replays one (removed in 1.9.1) | — |
| File write | The export itself | The output directory. 0700 dir, 0600 files, re-applied on every run. Destinations that resolve to synced/git/outside-$HOME are refused, no override |
| File delete | --purge / --purge-expired, so an export is not left lying around forever | The exact validated directory only: canonical, under $HOME, two levels deep, carrying our manifest, typed confirmation, interactive only |
| Shell exec | export.sh runs realpath/readlink, grep, sed and coreutils for path validation and purging | Fixed binaries, fixed arguments. No network binaries |
| Search endpoint | Find conversations inside Projects, which the list endpoint omits | ~65 short queries against your own history. Opt-in, skippable |
| Credentials on disk | None. Reads no keyring, no .env, no config, no cookie jar | — |
| Third-party services | None. No telemetry, no upload, no analytics | — |
| Privilege escalation | None. No sudo, no writes outside the output directory | — |
The consent step — every path has one, in code.
export.sh no longer exports, so it has no export consent step. Its destructive path does:
--purge validates the target, refuses to run non-interactively, and requires you to type
PURGE.bookmarklet.js opens a dialog stating that the file may contain credentials and other
sensitive material. Cancel and nothing happens. Two further dialogs let you skip the Projects
search and drop message bodies.exportChatGPTConversations() throws unless the caller passes confirmed: true, and the
thrown message is the structured confirmation itself — destination, scope, cap, redaction,
network and sensitivity — so the agent shows you the terms rather than paraphrasing them. An
agent has to ask you first; installing this skill cannot turn into an unattended dump of your
chat history.The off switch. Both scripted paths check this before any network call or file write:
CHATGPT_EXPORT_DISABLE=1 # disable for one command or one shell
touch ~/.openclaw/chatgpt-export.disabled # disable permanently, machine-wide
rm ~/.openclaw/chatgpt-export.disabled # allow again
With either in place, export.sh prints a notice and exits 0, and the TypeScript path throws.
Neither fetches anything. In the browser, the off switch is cancelling the first dialog.
Scope controls. Full export is a choice, not the default behaviour you get by accident:
| Control | relay (.ts) | bookmarklet |
|---|---|---|
| Must be asked for by name | confirmed: true (else it throws) | the first dialog |
| Cap how many | limit: N | — |
| No message bodies (DEFAULT) | indexOnly: true | Cancel the third dialog |
| Scrub common secrets | redact: true — applies to every file, summary.md included | — |
| Skip Projects search | n/a (never searches) | Cancel the second dialog |
| Choose destination | outputDir | browser Downloads |
| Refuse a risky destination | always on, no override | n/a |
| Set the expiry | expireDays: N (default 30) | n/a |
| Delete it again | via export.sh --purge | delete the download |
export.sh is absent from this table because it no longer exports — it has no scope to control.
There is no unattended export path at all: the relay needs a caller that has confirmed with you,
and the bookmarklet needs you in the browser clicking through its dialogs. Deletion always asks,
every time.
Prerequisites: Node with tsx, an OpenClaw browser relay attached to a Chrome/Chromium where you
are logged into chatgpt.com.
Invoke it by name, so ordinary conversation about ChatGPT cannot start an export: "chatgpt-exporter-ultimate: export my conversations." The agent must then echo the destination, the scope (index-only or full) and the sensitivity warning back to you, and get a yes, before calling:
await exportChatGPTConversations({
browserEvaluate, // supplied by the agent's browser tool
confirmed: true, // only after the user has actually agreed
outputDir: "~/.local/share/chatgpt-export/2026-01-31", // this is also the default
format: "both", // "json" | "md" | "both"
limit: 50, // optional cap
indexOnly: false, // true = titles/timestamps only, no message text (DEFAULT is true)
redact: true, // best-effort scrub of common secret formats
});
Without confirmed: true it throws — and the error it throws is the confirmation script itself:
destination, scope, cap, redaction state and the sensitivity warning, so the agent has something
exact to show you rather than a summary of its own. It also refuses — unconditionally, with no
override — a destination that resolves to something synced, inside a git repo, or outside your
home directory, and re-checks after creating the directory. Exports written here carry the same
ownership marker, so export.sh --purge can clean them up.
Prerequisites: Chrome DevTools, logged into chatgpt.com.
Open the console on chatgpt.com, paste scripts/bookmarklet.js, press Enter, and answer the three
dialogs: export or not, search Projects or not, include message text or not. The result lands in
your Downloads folder as a single JSON file. This is the only path that finds conversations inside
Projects, and it does so by running ~65 short searches against your own history — that is the
trade, and the dialog says so before it starts.
Prerequisites: bash and coreutils. No network, no credential.
./scripts/export.sh --check-dest ~/private/chatgpt # vet a destination, write nothing
./scripts/export.sh --purge -o ~/private/chatgpt # validated delete, asks you to type PURGE
./scripts/export.sh --purge-expired # delete every export past its expiry
This script does not export and handles no credential. The relay and the bookmarklet drop an
ownership manifest into every export; --purge is what validates and deletes it later, and
--check-dest vets a destination before you point the relay somewhere new.
| File | Purpose |
|---|---|
scripts/export-conversations.ts | Browser-relay exporter. Consent-gated, off-switchable, no token read |
scripts/bookmarklet.js | Console/bookmarklet exporter. Three consent dialogs, cookie-first auth, finds Projects |
scripts/export.sh | Cleanup and destination vetting. No network, no credential. Off switch, validated --purge, --check-dest |
scripts/purge-selftest.sh | Regression tests for --purge (14): runs its refusals against a throwaway $HOME, no network |
scripts/dest-safety-selftest.sh | Regression tests for destination vetting (19): symlink bypasses, and that the removed overrides stay removed |
scripts/relay-selftest.ts | Regression tests for the relay (22): file modes on reused paths, summary redaction, no-token guarantee. Stubbed browser, no network |
That is the whole package — six scripts, no binaries, no installers, nothing that runs on its own. Everything the documentation above describes is in these files, and everything in these files is described above. If you find a claim here that the code does not do, that is a bug — open an issue on the repo.