Desktop app for exporting iMessage chats to ChatToMap.com.
ChatToMap Desktop reads your iMessage database directly and exports conversations for processing by ChatToMap. The app provides a simple UI for selecting chats and uploading them securely.
- macOS only: Requires Full Disk Access permission to read
~/Library/Messages/chat.db
Download the latest release from the Releases page.
macOS unsigned binary note: The macOS binary is currently unsigned while we wait for Apple Developer Program enrollment. macOS may show an extra warning before opening it, so only download ChatToMap Desktop from the GitHub Releases page linked above.
On first launch, you'll be prompted to grant Full Disk Access in System Preferences.
# Install dependencies
bun install
# Install git hooks
task hooks:install| Command | Description |
|---|---|
task dev |
Development mode (uses chattomap.com API) |
task dev:local |
Development mode (uses localhost:5173 API) |
For most development, use task dev which connects to the production API.
Use task dev:local only when testing against a local SaaS server.
| Command | Description |
|---|---|
task build |
Production build (points to chattomap.com) |
task build:dev |
Release build pointing to localhost (for testing) |
# Run all tests (Rust + TypeScript)
task test
# Run only Rust tests
task test:rust
# Run only TypeScript tests
task test:ts
# Run TypeScript tests in watch mode
task test:watch# Run ALL checks (required before commits)
task ciThis runs: typecheck, lint, rust-lint, duplication check, file-length check, and all tests.
| Command | Description |
|---|---|
task lint |
Biome linter (check only) |
task lint:fix |
Biome linter with auto-fix |
task lint:rust |
Clippy (Rust linter) |
task typecheck |
TypeScript type checking |
task duplication |
Check for code duplication |
task file-length |
Check file length limits |
A command-line tool is available for debugging and testing:
# Build the CLI (requires --features cli)
cd src-tauri && cargo build --bin ctm-cli --features cli
# List all chats
./target/debug/ctm-cli list-chats
# List chats with message counts
./target/debug/ctm-cli list-chats --show-counts
# Export specific chats (by ID)
./target/debug/ctm-cli export --chat-ids 1,5,12 --output export.zip- Permission flow: Launch app without Full Disk Access, verify permission screen appears
- Grant access: Open System Preferences, grant FDA, click "Check Again"
- Chat list: Verify chats load with correct names and message counts
- Selection: Test select all/none, individual selection, filtering
- Export flow: Select chats, click Export, verify progress stages
- Browser open: Verify browser opens to results page on completion
chat_to_map_desktop/
├── src/ # Frontend (TypeScript)
│ ├── index.html # Main HTML
│ ├── main.ts # Frontend logic & state
│ ├── main.test.ts # Frontend tests
│ └── styles.css # Styling
├── src-tauri/ # Backend (Rust)
│ ├── src/
│ │ ├── lib.rs # Library exports
│ │ ├── main.rs # Tauri commands (GUI)
│ │ ├── cli.rs # CLI tool
│ │ ├── contacts.rs # AddressBook integration
│ │ ├── export.rs # Message export to JSON/zip
│ │ ├── upload.rs # Server communication
│ │ └── test_fixtures.rs # Test database builders
│ ├── Cargo.toml # Rust dependencies
│ └── tauri.conf.json # Tauri configuration
├── Taskfile.yml # Build commands
└── reference/ # Schema documentation
└── imessage_schema.sql # iMessage database schema
| Module | Purpose |
|---|---|
contacts.rs |
Resolves phone/email to contact names via macOS AddressBook |
export.rs |
Reads iMessage DB, exports selected chats to JSON zip |
upload.rs |
Fetches pre-signed URLs, uploads to R2, creates processing jobs |
| Flag | Effect |
|---|---|
desktop |
Enables Tauri GUI (default) |
dev-server |
Points to localhost:5173 instead of chattomap.com |
cli |
Enables the ctm-cli binary for debugging (not included in release builds) |
This project follows strict quality standards:
- Zero code duplication (jscpd)
- No
anytypes in TypeScript - No
biome-ignorecomments - File length limits: 500 lines (code), 1000 lines (tests)
- Cognitive complexity: max 15
All checks must pass before committing. Git hooks enforce this automatically.
This app collects anonymous usage analytics via Google Analytics to help us improve the user experience.
- Screen views: Which screens you visit (permission, chat selection, progress, success, error)
- Funnel events: Whether you complete the export flow, and where drop-offs occur
- Aggregate counts: Number of chats loaded, number of chats selected for export
- No chat content: Your messages are never sent to analytics
- No personal data: No names, phone numbers, or identifiers
- No contact information: Your address book data stays on your device
Analytics data helps us understand which parts of the app work well and where users encounter issues.
GPL-3.0 - See LICENSE for details.