A Python utility to export iMessage chats from your local chat.db database into organized, human-readable files (TXT, JSON, or CSV).
- Organized Export: Groups messages by Contact/Group and then by Date.
- Multiple Formats: Supports
.txt,.json, and.csv. - Smart Naming: Uses contact names, group names, or phone numbers to name folders.
- Filtering:
- Filter by specific contacts.
- Filter by date range.
- Progress Tracking: Shows a progress bar for large databases.
pip install -r requirements.txtThe sync service uses PyYAML for YAML config files. If you prefer JSON configs, PyYAML is still harmless to install.
On macOS, your iMessage database is located at: ~/Library/Messages/chat.db.
Important: For privacy and safety, copy this file to the
messages/folder in this project rather than running the exporter directly against the live database.
mkdir -p messages
cp ~/Library/Messages/chat.db messages/Note: You might need to grant Full Disk Access to your terminal or copy operation if macOS restricts access.
message_sync.py runs as a long-lived process that copies your Messages database into ./messages/ every six hours by default, handling optional WAL/SHM files to keep a consistent snapshot.
python message_sync.py start # Start in the foreground
python message_sync.py start --daemon # Start detached
python message_sync.py stop # Stop the running service
python message_sync.py status # Check if the service is running
python message_sync.py sync-now # Run an immediate one-off syncIf you start the service with a custom configuration file, use the same
--configflag when callingstoporstatusso the PID file can be located.
Key behaviors:
- Syncs immediately on startup, then every
sync_intervalhours. - Handles SIGINT/SIGTERM for graceful shutdown and cleans up its PID file.
- Prevents multiple instances by tracking
message_sync.pid. - Uses exponential backoff when files are locked and verifies file sizes after copy.
- Creates optional timestamped backups and prunes old ones.
- Logs to both console and
./logs/sync.logwith rotation (5 MB, 3 files by default).
You can configure the service with config.yaml or config.json (auto-discovered), or via CLI flags that override file values.
Default config.yaml (created in the repo):
sync_interval: 6 # hours
source_path: ~/Library/Messages/chat.db
destination_dir: ./messages
keep_backups: 3 # number of backup copies to retain (0 to disable)
log_level: INFO
log_dir: ./logs
pid_file: ./message_sync.pid
state_file: ./message_sync_state.json
log_max_bytes: 5242880 # 5 MB
log_backup_count: 3Examples:
python message_sync.py start --interval 3
python message_sync.py start --source-path "/Volumes/Backup/chat.db"
python message_sync.py sync-now --destination-dir ./messages --keep-backups 5The last successful sync timestamp is recorded in message_sync_state.json.
Use the provided sample plist to run the service when you log in:
./install.sh # writes ~/Library/LaunchAgents/com.user.messagesync.plist and loads itinstall.sh assumes macOS and defaults to /usr/bin/python3; override with PYTHON_BIN=/path/to/python3 ./install.sh. The generated LaunchAgent:
- Starts the service at login in daemon mode
- Keeps it alive if it exits
You can also manually copy com.user.messagesync.plist to ~/Library/LaunchAgents/ and run:
launchctl load ~/Library/LaunchAgents/com.user.messagesync.plistRun the script from the command line:
python imessage_export.py| Argument | Description | Default |
|---|---|---|
--db-path |
Path to the chat.db file. |
messages/chat.db |
--output-dir |
Directory to save exported chats. | imessage_export |
--format |
Output format: txt, json, or csv. |
txt |
--contacts |
Filter by specific contact names or numbers (space separated). | (All contacts) |
--date-range |
Filter by date range (YYYY-MM-DD YYYY-MM-DD). |
(All dates) |
--contacts-file |
Path to a .vcf vCard file for resolving phone numbers to contact names. |
contacts/contacts.vcf |
Export all chats to JSON:
python imessage_export.py --format jsonExport chats with specific people:
python imessage_export.py --contacts "Alice" "Bob"Export chats from January 2024:
python imessage_export.py --date-range 2024-01-01 2024-01-31Custom paths:
python imessage_export.py --db-path ./my_backup/chat.db --output-dir ./my_exportResolve phone numbers to contact names with vCards:
Place your exported contacts at contacts/contacts.vcf (or provide a custom path with --contacts-file) to have chat folders and message senders labeled with the matching contact names whenever available.
If you want to store exported messages in Qdrant, use qdrant_setup.py to create a collection with columns for the message text, message date, sender name, and chat name stored as payload fields.
python qdrant_setup.py --host 127.0.0.1 --port 6333 \
--collection-name messagesThe script:
- Connects to Qdrant (optionally with
--api-keyand--httpsfor TLS). - Creates the collection (or replaces it with
--overwrite) with a minimal vector stub. - Adds payload indexes for:
message(text)sent_at(keyword, e.g., ISO 8601 string)sender_name(keyword)chat_name(keyword)
Use --vector-size to adjust the placeholder vector size if you plan to add embeddings later.
To run Qdrant locally via Docker with sensible defaults, use the helper script:
./qdrant_docker_setup.shThe script:
- Checks that Docker is installed and running.
- Pulls
qdrant/qdrant:latest. - Starts (or restarts) a container named
qdrant-localthat maps ports6333(HTTP) and6334(gRPC) and persists data in theqdrant_storagevolume.
You can override defaults with environment variables:
CONTAINER_NAME=my-qdrant HTTP_PORT=7000 GRPC_PORT=7001 VOLUME_NAME=my_qdrant_storage ./qdrant_docker_setup.shThe exported data is organized as follows:
imessage_export/
├── Alice/
│ ├── 2024-01-15/
│ │ └── messages.txt
│ ├── 2024-01-16/
│ │ └── messages.txt
└── Family Group/
├── 2024-01-15/
│ └── messages.txt
- Database not found: Ensure you copied the
chat.dbto the correct path. - Permission errors: If copying
chat.dbfrom~/Library/Messages/fails, make sure your terminal application has "Full Disk Access" in macOS System Settings > Privacy & Security.