Repository navigation
feat(video): add a preserveMetadata option to drop source metadata - #432
Conversation
Video.compress copies the source video's metadata into the output on both platforms: Android writes the location as a udta/©xyz box, and iOS forwards every source metadata item to the writer. An app that uploads the compressed video has no way to leave the location out. preserveMetadata defaults to true, so the output is unchanged unless the caller opts out. With false, Android skips the location lookup and writes no ©xyz box, and iOS forwards no source metadata. The option takes the same path as stripAudio.
There was a problem hiding this comment.
🟡 Changes recommended
On Android and iOS, videos at or below the compression-size threshold bypass preserveMetadata: false, returning originals with GPS metadata intact and risking location disclosure.
2 open issues
What changed in this PR
Adds preserveMetadata to Video.compress, allowing callers to opt out of copying source metadata such as GPS location while preserving existing behavior by default.
Changes:
- Exposes and documents the option in the JavaScript API.
- Threads it through Android and iOS compression paths to control metadata copying.
- Adds a JavaScript test for option forwarding.
Native behavior was not runtime-verified during this review.
| File | Description |
|---|---|
src/Video/index.tsx |
Defines and forwards the metadata opt-out. |
README.md |
Documents the option and default behavior. |
ios/Video/VideoMain.swift |
Conditionally forwards source metadata to the exporter. |
android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.kt |
Parses and forwards the option for manual compression. |
android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/VideoCompressorClass.kt |
Passes the option through the compression pipeline. |
android/src/main/java/com/reactnativecompressor/Video/VideoCompressor/compressor/Compressor.kt |
Skips source location extraction when opted out. |
android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression.kt |
Forwards the option for automatic compression. |
android/src/main/java/com/reactnativecompressor/Utils/Utils.kt |
Threads the option into the native compressor. |
__tests__/compressor.test.ts |
Tests forwarding of explicit metadata preferences. |
Review effort: Balanced
A video at or under minimumFileSizeForCompress skipped compression and came back as the source file, with its location still in it. That happened on iOS in both modes and on Android in auto mode, so preserveMetadata: false did not hold when a caller set a threshold. With preserveMetadata false, the size check no longer short-circuits, and the export runs without the source metadata. The option is new and defaults to true, so no existing caller changes.
Review follow-up: with |

Summary
Since #399,
Video.compresscopies the source video's metadata into the output on both platforms: Android writes the location as audta/©xyzbox, and iOS forwards every source metadata item to the writer. An app that uploads the compressed video has no way to leave the location out. We drop GPS from photos before they leave the device, and right now we carry a local patch to do the same for video.This adds
preserveMetadata?: booleanto the video options. It defaults totrue, so the output is unchanged unless a caller opts out. Withfalse:MediaMetadataRetrieverandLocationExtractor), soMP4Builderwrites no©xyzbox.The option takes the same path as
stripAudio: throughVideoCompressorHelperon Android, and the compression helpers inVideoMain.swifton iOS. Options are already anAnyMap, so there's no spec change, andyarn nitrogenproduced no diff. The README has a new entry undervideoCompresssionType.Closes #431
Changelog
[GENERAL] [ADDED] - Add a
preserveMetadataoption toVideo.compressto leave the source metadata, such as the GPS location, out of the outputTest Plan
yarn test:pr. 14 tests pass, including a new one for the option forwarding. Typecheck is clean, and lint has 0 errors (the 9 warnings are already onmain).yarn test:harness:androidoryarn test:harness:ios. Not run: the harness spec has noVideo.compresscase, so it wouldn't exercise this. I ran it in an app instead, below.I packed this branch (
yarn prepack, thennpm pack) into an Expo SDK 58 / React Native 0.88 app. Then I compressed two phone clips that carry a location, a Pixel.mp4and an iPhone.MOV, withcompressionMethod: 'manual',bitrate: 2_000_000andmaxSize: 1280: once withpreserveMetadata: falseand once with the option unset. I read each output's metadata with AVFoundation:false©xyz©xyz©xyzlocation©xyzlocationfalse©xyzlocationlocilocation anddateOn Android the log also shows the lookup skipped:
source location resolved: hasLocation=false source=not preserved. The video staysavc1720×1280 at about 2 Mbps in every case.Review follow-up: with
preserveMetadata: false, theminimumFileSizeForCompresscheck no longer returns the source file untouched, on iOS (both modes) or on Android (auto mode, the only one with the check).yarn test:prstill passes. I re-ran it with the threshold set above the clip size, using a fresh Pixel clip that carries a location:falsegave a new file with no metadata on the iOS 26.5 simulator (manual) and an Android emulator (auto), and with the option unset the original file came back as before.