Most of your Facebook isn't yours
The Facebook importer was built against a real "Download Your Information" export. The first useful thing it told me was a number I did not expect.
On that export, 95 % of the posts were not written on Facebook. They were mirrored in — from Twitter, from Posterous, from the whole crosspost era when every service politely offered to repost you everywhere else.
They are skipped, and counted
Those posts do not import. Not because they are worthless, but because the platforms they actually came from have their own exports, and those carry the originals: the full text, the real timestamps, the media at the size it was uploaded. A Facebook mirror of a tweet is a worse copy of something you can import properly from the Twitter archive sitting in the same folder.
Import both and your archive doubles, with the lesser version winning half the time. So they are recognized and skipped with a count in the summary, and FACEBOOK_CROSSPOSTS=1 overrides it if you disagree. Wordless check-ins and app stories are counted skips too.
That leaves your own posts, with the photos and videos from the archive itself.
Both formats read the same
Meta lets you choose JSON or HTML on the way out, and people pick without knowing it matters. Here it doesn't: both are read, and they come out epoch-identical, down to the ids minted for re-import matching.
Getting there was the fiddly part. The JSON carries plain timestamps. The HTML prints a wall clock — with seconds, in the account's own timezone, daylight saving observed — which had to be measured against the JSON of the same account to be sure. And the HTML's dates arrive localized, so Czech and English are both understood, and a language the importer does not recognize skips what it cannot date and says so rather than guessing a month name.
Threads, the twenty-second
Threads closes the social-network roster, and its export has the strangest shape of the family: every post is a media list even when there is no media, with the text riding in a title field. The HTML page is read back into that same odd shape so both formats walk one mapping.
Ask for JSON where you get the choice. Only the JSON marks replies — an HTML run ends by saying so every time, because it cannot know whether there was anything to miss — and only the JSON carries seconds. The HTML page prints minutes, in Meta's fixed no-daylight-saving Pacific clock, which converts back exact to the minute against the same account's JSON.
One flag in that export is a trap worth naming: cross_post_source looks like the crosspost marker, and on real exports it also marks posts written directly in the Threads app. It records where a post was shared to. Skipping on it would empty your archive.
The encoding, finally
Meta's exports have mangled non-ASCII text for years — the bytes are UTF-8 read as Latin-1 and re-encoded, so every accented letter arrives as gibberish. The Instagram importer proved out a repair for it; it now lives in a shared module the whole Meta family uses.
Which means Czech, German, French and everyone else gets their own words back, instead of an archive of ÄŤ and é.
The part that stayed with me
Nineteen out of twenty posts on that account were copies of things written somewhere else — somewhere that has usually since closed. The crosspost era felt like insurance at the time. It turned out to be the opposite: the copies outlived the originals, in a worse form, on a platform that will not hand them back in one piece.
Ask for the export. From all of them.

Comments