Inspiration
As AI adoption increases and the industry rapidly evolves, the possibilities users switch AI providers, lose their data or data sovereignty increases. The odds an AI provider could shutdown in the near future due to infrastructure costs is a real risk to mitigate. I felt the need to export and back-up my own chats to preserve the context built-up of years of usage. All the popular LLM providers have a data export process, which is a great opportunity for users to lower their risk of data loss. An app to unlock the value of those exports is the idea that led to developing Chatelope.
## What it does
Chatelope imports AI chat exports, stores them locally, and makes them searchable and continuable.
- Import from ChatGPT, Claude, and Gemini, plus public share links. Accepts JSON, ZIP, and HTML up to 500 MB, extracting attachments and message structure.
- Organize with nested folders, tags, starring, and cross-platform search. Re-importing the same export is idempotent.
- Continue any imported conversation. Re-use previous context by adding your own LLM provider API key and send a new message into an old thread, with streaming responses and support for images and PDFs.
- Generate and edit images, transcribe audio (including from another
browser tab), and produce speech from text. - Compare costs. Record what you pay for ChatGPT Plus or Claude Pro,
and Chatelope contrasts it with what the same token volume would have cost at API rates.
Providers are bring-your-own-key: OpenAI, Anthropic, Google, DeepSeek, Qwen,
Z.ai, Moonshot, and MiniMax, plus upcoming feature to use self-hosted Ollama and LM Studio. Keys are
stored client-side and sent only to the provider they belong to.
The archive is free.
## How we built it
Chatelope ships as a Flutter Android app backed by a Next.js web app and a future Electron desktop app. The
Android build is where the product is monetized, so that is where most of
the design work went.
Import. Each platform has a parser extending a shared BaseParser that
returns a unified ParsedConversation[], so the import service handles
deduplication and insertion without knowing the source. ChatGPT's export is
a mapping of nodes with parent pointers and a current_node; the parser
walks backwards to the root and reverses to reconstruct the active branch.
Claude's content is typed blocks, including tool_use and tool_result.
Gemini is regex over Takeout HTML.
AI layer. Ten providers behind one interface. The four newer ones route
through an OpenAI-compatible client with explicit base URLs. A model
registry resolves in four layers: live API fetch, bundled fallback lists, a
remote editorial overlay, then sensible defaults for unknown models, so a
newly released model works before we ship an update.
Continuation. Two routes, buffered and streaming. The streaming one is
hand-rolled SSE over a ReadableStream with four event types. The API key
arrives per request from the client rather than sitting on a server.
Mobile. Flutter with Riverpod, Drift, and Go Router across 24 screens.
The database is encrypted at rest by default using SQLite3MultipleCiphers,
with a flag tracking on-disk state so plaintext and encrypted transitions
migrate rather than failing to open.
Monetization. RevenueCat via purchases_flutter. The app defines four
entitlements rather than gating whole screens: addApiKeys,
continueChats, generateMedia, and aiAssistant. A FeatureLockedCard
renders the upgrade path where a locked feature is used, so the free tier
stays fully usable as an archive.
## Challenges we ran into
Every export format is different, and one is not a data format. Gemini
ships as My Activity.html from Takeout: markup meant for a browser. There
is no schema to code against, so the parser sniffs for marker strings, runs
a regex over activity cells, and converts HTML to text. It is the least
stable parser in the project and it is that way because the source gives us
nothing better.
Branching conversations Chats have to branch when a user continues a conversation with a new provider, so a standard system of IDs had to be implemented.
API keys in a client app. Keys live in localStorage, base64-encoded.
That prevents casual inspection but is obfuscation, not encryption, and the
code says so rather than dressing it up. The property that does hold is
architectural: keys go only to the provider they belong to.
## Accomplishments that we're proud of
- Five conversation parsers behind one interface
- OpenAI Gizmo sidebar mapping for project folder name capture. ChatGPT gives you hashed project IDs; Chatelope gives you back the names, colors, and emoji.
- Conversations that continue. A thread imported from months ago accepts a
new message and streams a response. - Ten providers including with upcoming self-hosted options, so a user running a local model
needs no external account. - Entitlement-level gating instead of tier-level, which keeps the archive
free and complete. - Cost comparison engine that answers a question nobody else answers: is the subscription cheaper than the API?
## What we learned
Developing for multiple platforms is still very time consuming and complex even with modern frameworks such as Flutter and languages such as Kotlin.
Normalizing data from systems you do not control makes the parser boundary
the most important design decision in the project. Everything downstream
depends on it.
Subscription state is more complex than imagined, and RevenueCat
exposes what is necessary to wire it up. Mapping multiple states onto a
domain model made the UI logic simpler (paywall).
Bring-your-own-key moves inference cost to the user, so the product is priced as software rather than resold tokens.
## What's next for Chatelope
- Possibility of adding containers and an agent harness
- Full-text search. Search is currently
LIKEover titles and message content, which cannot use an index. SQLite FTS5 is the next step. - Branch creation in the continue flow, plus a UI for switching branches on
imported conversations. - iOS release. The RevenueCat iOS key is still a placeholder pending App
Store registration. - Broadening the sync engine beyond Google Drive.
- Adding more OAuth providers
Built With
- android
- anthropic
- better-sqlite3
- dart
- drift
- drizzle-orm
- fal-ai
- flutter
- go-router
- google-drive-api
- google-gemini
- gradle
- kotlin
- lmstudio
- nextjs
- ollama
- openai
- puppeteer
- react
- revenuecat
- riverpod
- shadcn-ui
- sqlite
- tailwindcss
- typescript
Log in or sign up for Devpost to join the conversation.