How I Transferred WhatsApp Chat History from Android to iPhone When Every Tool FailedBack to BlogI got a new iPhone 17 recently. Moving everything from my Android, a POCO phone running Android 16, was easy, except for one thing: WhatsApp. Years of chat history, 325,647 messages, and the official transfer refused to move any of it.
WhatsApp does have an official Android to iPhone transfer. It scans a QR code, the Android creates a temporary hotspot named something like WHATSAPP-90, and the iPhone joins it to pull your chats over. In my case the iPhone 17 would see the network created by the POCO, ask to join, and fail instantly. Every single time. I tried all the usual fixes: mobile data off, VPN off, network settings reset, 2.4GHz hotspot band, rebooting both phones. Nothing worked.
So I searched the internet, and the results were grim. Every article and YouTube video pushed the same handful of paid "phone transfer" tools, mostly through affiliate links, all closed source, all requiring you to hand your entire chat history to an app you cannot inspect. Some of the videos were suggesting software so shady I would not install it on a throwaway machine, let alone give it years of private conversations. That was not going to happen. So I did what any reasonable person would do at 1 AM: I decided to do the migration myself with open source tools.
Fair warning before you start: this method moves messages only. Media comes across as placeholders like and , though captions are preserved. Also, this involves modifying an iPhone backup and restoring it, so read everything first and keep safety copies at every step.
Here is the full recipe.
Prerequisites
A Mac with Xcode installed (the full app, not just command line tools)
adb working with your Android phone
Full Disk Access granted to your terminal (System Settings, Privacy & Security)
WhatsApp activated on the iPhone with your number, with one or two test messages sent
ipatool-rs (Kosthi) and wa-crypt-tools
Step 1: Get the Decrypted Android Database
The old tricks for extracting msgstore.db involved rooting your phone or downgrading to an ancient APK. There is a much cleaner way now, but the order of the steps matters:
In WhatsApp on Android, go to Settings, Chats, Chat backup, End-to-end encrypted backup. Turn it on.
Choose "Use 64-digit encryption key instead" and save that key somewhere safe. This is what decrypts the database later, so do not skip it.
Now go back to the Chat backup screen and tap Back Up to trigger a fresh local backup.
That last step is not optional. The msgstore.db.crypt15 file only exists, encrypted with your new key, after you run a backup following the key setup. If you pull an old backup file, or forget to trigger a new one, the decryption will fail.
The backup lands at a path that is readable over adb without root:
bash
mkdir ~/wa-migration && cd ~/wa-migration
adb pull /sdcard/Android/media/com.whatsapp/WhatsApp/Databases/msgstore.db.crypt15 .
pip install wa-crypt-tools<br>wadecrypt your-64-digit-key> msgstore.db.crypt15 msgstore.db
Sanity check:
bash
sqlite3 msgstore.db "select count(*) from message;"
Mine printed 325647. The hard part was already done, or so I thought.
Step 2: Build watoi
watoi (WhatsApp Android To iOS Importer) is the core tool here. It reads the Android database and injects the messages into the iOS ChatStorage.sqlite using WhatsApp's own CoreData model. I used the kwvg fork since it supports a newer schema than the original.
bash
git clone https://github.com/kwvg/watoi<br>cd watoi<br>xcodebuild -project watoi.xcodeproj -target watoi
Step 3: Back Up the iPhone and Extract ChatStorage.sqlite
Connect the iPhone, open Finder, select the phone, choose "Back up all of the data on your iPhone to this Mac", and make sure "Encrypt local backup" is unchecked. The scripts cannot work with encrypted backups.
bash
scripts/bedit.sh list-backups<br>export BACKUP_ID=""
# safety copy, do not skip this<br>cp -R ~/Library/Application\ Support/MobileSync/Backup/${BACKUP_ID} ~/wa-migration/backup-original
export ORIGINALS="originals/$(date +%s)"<br>mkdir -p $ORIGINALS<br>scripts/bedit.sh extract-chats $BACKUP_ID $ORIGINALS/ChatStorage.sqlite<br>scripts/bedit.sh extract-blob $BACKUP_ID Manifest.db $ORIGINALS/Manifest.db<br>cp $ORIGINALS/ChatStorage.sqlite ./ChatStorage.sqlite
sqlite3 ./ChatStorage.sqlite "select count(*) from ZWAMESSAGE;"
If that last command prints a small number (my fresh install had 118 rows), you are good.
Step 4: Get the WhatsApp IPA
watoi needs the CoreData model files from the WhatsApp iOS app bundle. Apple Configurator is the commonly suggested way to get the IPA, but it kept failing for me with AMSErrorDomain error 100.
ipatool is a much nicer way. It downloads the IPA directly from the App Store using your Apple ID. The original majd/ipatool from homebrew did not work for me (the upstream project has gone stale and auth kept failing), so I used ipatool-rs, the actively maintained Rust rewrite by...