Skip to content

snapchat-memories-to-photos

Snapchat’s My Data export hands you a pile of files named 2019-06-14_<uuid>-main.mp4 and a JSON file that lists dates and coordinates and never says which entry belongs to which file. Import that folder into Apple Photos as it arrives and everything is dated the day you downloaded it, with no location on anything. This tool reconstructs the link between file and entry, writes real metadata onto copies, and imports the result into a Photos library you choose. It is Python, standard library only, MIT licensed, and macOS only because the last step talks to Photos.

  • It does not guess by date. Matching is 1:1 between a file and a JSON entry, and “nearest entry wins” is exactly the rule it avoids, because two memories seconds apart get silently swapped that way.
  • It does not undo an import. Photos AppleScript can import, create albums and set dates. It cannot delete media items or albums: delete fails with -1700. Import is one directional, which is the argument for a dedicated library.
  • It does not modify your originals. Every step works on copies.
  • It does not write coordinates it does not trust. Entries at exactly 0.000000, 0.000000 are Snapchat saying the location was unavailable, so the GPS tags are left off instead of putting the memory in the Gulf of Guinea.
  • It does not resolve conflicts on its own. Where a video carries its own LocationInformation from the camera and it disagrees with the JSON, snapmem.verify flags it rather than picking.
  • It does not fetch the export for you. Requesting it from Snapchat, and downloading every zip, is your job.
macOS with Photos
python3 >= 3.9 (stdlib only, no packages to install)
exiftool brew install exiftool
ffmpeg brew install ffmpeg (only for overlay merging)

Unpack every zip into one folder first, then:

Terminal window
# match files to JSON entries and write a manifest
python3 -m snapmem.match /path/to/export --out manifest.json
# write dates, time zones and coordinates onto copies
python3 -m snapmem.prepare manifest.json --out /path/to/ready
# optional: burn text and stickers onto copies of their own
python3 -m snapmem.overlays manifest.json --ready /path/to/ready --out /path/to/with-overlays
# check every file against the source JSON before importing anything
python3 -m snapmem.verify manifest.json --ready /path/to/ready
# import into a Photos library of your choice
python3 -m snapmem.import_photos /path/to/ready \
--library "/Volumes/Disk/Snapchat Memories.photoslibrary" \
--album "All memories"

Each module runs standalone with --help.

The match comes from zip timestamps. memories_history.json gives Date in UTC, Media Type and Location, and no filenames. Filenames carry a date with day precision plus a random uuid, so ten memories on one day are ten indistinguishable candidates. When an archive is unpacked, each file keeps the modification time stored in the zip entry, and that value is the original capture time. The gap between it and the JSON date is constant, equal to the UTC offset applied by the unpacker, give or take a second because zip timestamps have two second granularity. snapmem.match derives that offset from your own data, constrains pairs by media type, and resolves contention by smallest gap first.

Photos and videos need different tags.

photos videos
date DateTimeOriginal + OffsetTimeOriginal Keys:CreationDate with offset
location GPSLatitude / GPSLongitude Keys:GPSCoordinates, ISO 6709

Video location is where this gets quiet. ISO 6709 wants two integer digits for latitude and three for longitude. +41.902000+012.496000/ is accepted and +41.902000+12.496000/ is ignored, the item appearing with no location at all. Both read back identically under exiftool. In Python the format is f"{lat:+010.6f}{lon:+011.6f}/". Snapchat’s MP4 files also ship without the metadata handler Photos looks for, so -api QuickTimeHandler=1 is required.

Batching arguments through -@ argfile is far faster than one exiftool launch per file, but options passed as -common_args are dropped once the argfile contains -execute, and the only warning is a line buried in the output. The write appears to succeed and reads back correct. It is wrong only inside Photos. The -api options go inside each block instead. The general rule: check the effect in the destination application rather than the value read back by the tool that wrote it.

snapmem.verify re-reads every prepared file and compares it against the source JSON, and it runs before the import rather than after.

The tool was tested on macOS 26 against an export of a few thousand items spanning several years. Every item matched, and every date was verified against the source JSON. In that export, 4% of entries carried 0.000000, 0.000000 as their location. Altitude and accuracy tags turned out not to be required, established by writing four copies of one file that differed only in that detail.

Some overlay PNGs arrive as 0 bytes in the export itself. snapmem.overlays skips them and reports the count.