A video's metadata is not one thing, and no single command removes all of it. An MP4 keeps the picture in one box and the records about the file in several others, so "remove the metadata" is really a question about which boxes you are willing to rewrite. Measured on a 102,295-byte test file: a plain ffmpeg -c copy drops the C2PA provenance box and leaves all ten tags; adding -map_metadata -1 removes four of those ten; rewriting the container in place removes all ten and the provenance box as well. In every one of those methods the compressed video is byte-for-byte identical afterwards — 100,307 bytes with the same MD5 — because removing metadata is not a re-encode, whatever a tool may imply.
The tool below does the third of those. Everything quoted on this page is a real run on this machine, reproducible with the scripts named at the end.
This is the box list read straight out of the test file, not the list the format permits. An ISO base media file is a flat sequence of boxes at the top level, each with a size and a four-character type, and some of those boxes contain more boxes.
| Path | Size | What it holds |
|---|---|---|
ftyp | 32 B | The brand: which specification the file follows, and which readers it expects |
free | 8 B | Padding. Carries nothing, exists to keep other boxes aligned |
mdat | 100,315 B | Every frame of video and every sample of audio, compressed |
uuid | 153 B | The C2PA content credential — a signed record of origin |
moov | 1,787 B | The index: timing, track layout, and the offsets a player needs |
moov/mvhd | 108 B | Timescale and duration for the whole movie |
moov/trak | 1,475 B | One track: its handler, its sample table, its sample entry |
moov/udta | 196 B | User data — this is where descriptive metadata lives |
moov/udta/meta/ilst | 143 B | Four tags: (c)nam, (c)ART, (c)too, (c)cmt |
Note where the interesting things are not. There is no EXIF block, no XMP packet and no IPTC record — those are still-image structures. A video carries the equivalent information under different names in different places, which is why a tool built for photos finds nothing to remove here.
People search for this because they know what metadata did to their photos, and the honest answer is that a video does not store it the same way. The mapping is roughly this:
| What you want gone | Where a photo keeps it | Where a video keeps it |
|---|---|---|
| Location | A GPS IFD inside the EXIF block | A (c)xyz atom under moov/udta, holding coordinates as text |
| Creation time | DateTimeOriginal in the EXIF block | A timestamp in mvhd, plus a date tag in ilst |
| Device identity | Make, model and body serial number | The handler_name and vendor id on each track |
| The software used | A Software tag | A (c)too tag, plus a compressor name inside the sample entry |
| Provenance | A C2PA segment in APP11 | A C2PA uuid box at the top level |
The provenance row is the one that matches exactly: both formats put a C2PA record in a structure of its own, which is why it is the one that comes off cleanly in both. A real file that arrives carrying one is a Sora export, where the credential is a 14,358-byte box at byte 32: measured, box by box → The still-image side, segment by segment →
C2PA is the one kind of video metadata people search for by name, and it is worth separating from everything else on this page. It is not a tag and it is not EXIF. It is a box in the container, and Amazon's MediaConvert documentation states the placement exactly: "The manifest is embedded in the MP4 file using a standard C2PA UUID box, placed after the FTYP box and before the MOOV box."
Being a box is precisely what makes it removable without touching the picture. On this site's own test file, a plain remux dropped it and left the compressed video byte-identical:
input 102295 bytes boxes = ftyp free mdat uuid moov after ffmpeg -c copy 102142 bytes boxes = ftyp free mdat moov mdat (the compressed video): 100307 bytes in both, identical = True
153 bytes gone and not one video byte changed. Two honest notes on that run. First, no metadata flag was needed: ffmpeg keeps the streams it understands and drops top-level boxes it does not, so this is a side effect rather than a feature you asked for. It cuts both ways — it is the fastest way to shed the record, and it is also how provenance disappears from a file somebody meant to preserve. Second, the placement matters a great deal. Deleting a box that sits before mdat shifts every sample while the chunk-offset table inside moov keeps its old numbers, and measured on a clip built that way, 0 of 72 frames decoded. The same cut on a file where the box sits after mdat, or with the offset table corrected, decodes 72 of 72.
To check whether a file you have carries one, list the container's top-level boxes. A uuid box sitting between ftyp and moov is the provenance record, and it is either there or it is not. Where that box sits among the three layers →
Here is the same test file put through each method. The tag count is what ffprobe reports; the mdat line is the compressed video, taken from the bytes rather than from the tool that wrote them.
| Method | Size | C2PA box | Tags removed | mdat |
|---|---|---|---|---|
| Untouched | 102,295 B | present, 153 B | — | 100,307 B, 3b11cb33… |
ffmpeg -c copy | 102,142 B | gone | 0 of 10 | identical |
-c copy -map_metadata -1 | 102,043 B | gone | 4 of 10 | identical |
| In-place rewrite (this tool) | 102,295 B | gone | 10 of 10 | identical |
Three things in that table are worth pausing on, because each one contradicts something a metadata cleaner usually tells you.
The provenance box comes off whether you ask or not. A plain -c copy does not preserve the uuid box, because ffmpeg keeps the streams it understands and discards top-level boxes it does not. That is worth knowing in both directions: it is the fastest way to shed a credential, and it is how one disappears from a file somebody meant to keep it on.
Stripping the tags does not strip the software string. After -map_metadata -1 the file still reports encoder=Lavc63.1.101 libx264. The reason is that this string is not a tag at all — it lives at offset 100,984 inside the sample entry moov/trak/mdia/minf/stbl/stsd/avc1, as a fixed 32-byte compressor name field sitting next to the frame width and height. It is a field of a structure rather than a box, so no metadata flag can reach it. Clearing it means editing the sample entry, whose fixed header length depends on the track type, which is why this tool leaves it alone and names it here instead.
Nothing here is a re-encode. The mdat MD5 is the same string in all four rows. If a tool changes the picture while claiming to remove metadata, it is doing something else to your file.
That line is exactly where this page stops. Everything above is an edit to the container, and it leaves the picture alone. A logo you can see on the frames is the opposite problem: it is the picture, so it cannot be removed without re-encoding and the pixels it covers are not recoverable. The costs of each way of hiding one are measured on the logo page.
Every method above changes the container. Two of them make the file shorter, which is the obvious thing to do and also the thing that can destroy it.
A player does not scan a video looking for frames. It reads stco inside moov, which is a list of absolute byte positions — "sample one starts at offset 40". Those are positions in the file itself. Delete a box that sits before mdat and every sample slides, while the table keeps the old numbers. The decoder then reads frames from the wrong bytes.
The C2PA box belongs right after ftyp and before moov, so it sits before the media. Inserting it there shifts the media by 158 bytes. On a test file where the offset table was left alone:
box inserted, offset table not corrected 0 of 72 frames decode same insertion, offset table corrected 72 of 72 frames decode
Zero frames is not a subtle artefact; it is a file that no longer plays. That is why this tool rewrites boxes in place instead of deleting them: the record is destroyed, the box no longer claims to be a credential, and no byte in the file changes position. The price is that the file does not shrink. The tool, and how to check its output →
Every number above comes from commands you can run on your own file. The tags:
ffprobe -v error -show_format -show_streams yourfile.mp4
The compressed video, so you can prove nothing was re-encoded:
ffmpeg -i original.mp4 -f framemd5 - > before.txt ffmpeg -i cleaned.mp4 -f framemd5 - > after.txt diff before.txt after.txt
And the box list, which is what tells you whether a credential was ever there:
python dev/video_meta_report.py yourfile.mp4
The scripts behind this page are dev/video_meta_report.py, dev/video_metadata_methods.py and dev/make_video_fixtures.py, and the tool itself is tested by _selftest/video.js across seven fixtures. Where a video watermark can hide, and which layer comes off →
Not in the same form, and this trips people up when they go looking. EXIF is a JPEG and TIFF structure. A video stores its records in ISO base media boxes instead, so the same information turns up in different places with different names: a location is a (c)xyz atom under moov/udta rather than a GPS IFD, a title is a (c)nam or an ilst entry, and the software that wrote the file is a (c)too tag plus a compressor name field. When ffprobe prints TAG: lines for a video, those are the box values being surfaced under familiar names, not EXIF.
Measured on a 102,295-byte test file: a plain ffmpeg -c copy drops the C2PA provenance box but leaves all ten tags. Adding -map_metadata -1 removes four of those ten. An in-place rewrite of the container removes all ten tag values and the provenance box. Nothing removes the ftyp brand fields, and nothing removes the compressor name inside the sample entry unless a tool edits that structure field by field.
It should not, and on this machine it does not. The compressed video sits in the mdat box, and every method tested here leaves mdat byte-for-byte identical: 100,307 bytes with the same MD5 before and after. That is the line between removing metadata and removing a watermark. If a tool re-encodes, the file gets smaller or softer and the picture changes; if it only edits the container, mdat does not move at all.
Because the chunk offset table stores absolute byte positions. The stco box inside moov lists where each sample starts in the file, as a raw offset. Delete a box that sits before mdat and every sample slides backwards while the table keeps the old numbers, so the decoder reads frames from the wrong bytes. Measured here: inserting the C2PA box where the format puts it, without correcting that table, left zero of 72 frames decodable. Correcting the table restored all 72.
The output was read back with ffprobe, which reports the same codec, resolution, stream count and duration, and every frame decoded to an identical MD5. Because nothing in the file changes position, there is no offset for a player to get wrong. That is the reason this tool rewrites boxes in place rather than deleting them: it costs the file-size reduction and buys back the guarantee that the index is still correct.
Yes, and it is worth insisting on. This is a byte-level edit of the container, so it needs no decoder, no encoder and no server — it runs in the page you are already on, and the file never leaves the machine. A site that asks you to upload a video before cleaning its metadata is sending your file somewhere to do arithmetic it could have done locally.