{
 "slug": "downloaded-photo-location-metadata",
 "method": "lab + primary-docs",
 "checkedAt": "2026-10-26",
 "question": "Do downloaded photos still have location data in them?",
 "tools": {
  "exiftool": "13.55",
  "sips": "sips-316",
  "python": "3.9.6",
  "Pillow": "9.5.0"
 },
 "inputs": {
  "lab": [
   "one 2400x1800 JPEG generated by check.py and tagged with exiftool (Make=Apple, Model=iPhone 15 Pro, SerialNumber=F2LX90ABCDEF, a GPS coordinate at 28.586 N, 80.651 W), then derived in a temporary directory into: stored.jpg, display-noflag.jpg, display-carry.jpg, thumb-400.webp, base.heic, heic-sips.jpg, block-no-gps.jpg, zero-gps.jpg"
  ],
  "pages": [
   "https://commons.wikimedia.org/wiki/Commons:EXIF",
   "https://developer.android.com/reference/android/Manifest.permission",
   "https://developer.android.com/reference/android/provider/MediaStore",
   "https://developer.android.com/training/data-storage/shared/media",
   "https://docs.joinmastodon.org/admin/config/",
   "https://phabricator.wikimedia.org/T360589",
   "https://www.mediawiki.org/wiki/API:Imageinfo"
  ],
  "files": [
   "file:apps/api/src/uploads/uploads.service.ts"
  ]
 },
 "results": {
  "lab": [
   {
    "id": "stored-original",
    "path": "Uploaded file stored unchanged, offered for download",
    "exif_block": "yes",
    "camera_make": "Apple",
    "camera_model": "iPhone 15 Pro",
    "serial_number": "F2LX90ABCDEF",
    "coordinate_strict": "yes",
    "coordinate_naive": "yes",
    "width": 2400,
    "height": 1800,
    "input": "stored.jpg",
    "url": null,
    "quote": "Make=Apple, Model=iPhone 15 Pro, SerialNumber=F2LX90ABCDEF, GPSLatitude=28 deg 35' 9.60\", GPSLongitude=80 deg 39' 3.60\""
   },
   {
    "id": "display-noflag",
    "path": "Resized to 1600 px, metadata not carried forward",
    "exif_block": "no",
    "camera_make": "no",
    "camera_model": "no",
    "serial_number": "no",
    "coordinate_strict": "no",
    "coordinate_naive": "no",
    "width": 1600,
    "height": 1200,
    "input": "display-noflag.jpg",
    "url": null,
    "quote": "exiftool returned no EXIF tags"
   },
   {
    "id": "display-carry",
    "path": "Same resize, metadata carried forward",
    "exif_block": "yes",
    "camera_make": "Apple",
    "camera_model": "iPhone 15 Pro",
    "serial_number": "F2LX90ABCDEF",
    "coordinate_strict": "yes",
    "coordinate_naive": "yes",
    "width": 1600,
    "height": 1200,
    "input": "display-carry.jpg",
    "url": null,
    "quote": "Make=Apple, Model=iPhone 15 Pro, SerialNumber=F2LX90ABCDEF, GPSLatitude=28 deg 35' 9.60\", GPSLongitude=80 deg 39' 3.60\""
   },
   {
    "id": "thumb-400",
    "path": "400 px WebP thumbnail",
    "exif_block": "no",
    "camera_make": "no",
    "camera_model": "no",
    "serial_number": "no",
    "coordinate_strict": "no",
    "coordinate_naive": "no",
    "width": 400,
    "height": 300,
    "input": "thumb-400.webp",
    "url": null,
    "quote": "exiftool returned no EXIF tags"
   },
   {
    "id": "heic-sips-jpeg",
    "path": "HEIC converted to JPEG by macOS sips",
    "exif_block": "yes",
    "camera_make": "Apple",
    "camera_model": "iPhone 15 Pro",
    "serial_number": "F2LX90ABCDEF",
    "coordinate_strict": "yes",
    "coordinate_naive": "yes",
    "width": 2400,
    "height": 1800,
    "input": "heic-sips.jpg",
    "url": null,
    "quote": "Make=Apple, Model=iPhone 15 Pro, SerialNumber=F2LX90ABCDEF, GPSLatitude=28 deg 35' 9.60\", GPSLongitude=80 deg 39' 3.60\""
   },
   {
    "id": "block-no-gps",
    "path": "Same original with the GPS block removed",
    "exif_block": "yes",
    "camera_make": "Apple",
    "camera_model": "iPhone 15 Pro",
    "serial_number": "F2LX90ABCDEF",
    "coordinate_strict": "no",
    "coordinate_naive": "no",
    "width": 2400,
    "height": 1800,
    "input": "block-no-gps.jpg",
    "url": null,
    "quote": "Make=Apple, Model=iPhone 15 Pro, SerialNumber=F2LX90ABCDEF"
   },
   {
    "id": "zero-gps",
    "path": "Same original with the GPS values all zero",
    "exif_block": "yes",
    "camera_make": "Apple",
    "camera_model": "iPhone 15 Pro",
    "serial_number": "F2LX90ABCDEF",
    "coordinate_strict": "no",
    "coordinate_naive": "yes",
    "width": 2400,
    "height": 1800,
    "input": "zero-gps.jpg",
    "url": null,
    "quote": "Make=Apple, Model=iPhone 15 Pro, SerialNumber=F2LX90ABCDEF, GPSLatitude=0 deg 0' 0.00\", GPSLongitude=0 deg 0' 0.00\""
   }
  ],
  "statements": [
   {
    "id": "android-hides-location",
    "statement": "On Android 10 and later, an app that reads photos through the shared media collection gets a redacted copy by default.",
    "url": "https://developer.android.com/training/data-storage/shared/media",
    "quote": "If your app uses scoped storage, the system hides location information by default.",
    "fetch": "ok",
    "found": true
   },
   {
    "id": "android-access-media-location",
    "statement": "The location is returned only if the app declares the ACCESS_MEDIA_LOCATION permission.",
    "url": "https://developer.android.com/training/data-storage/shared/media",
    "quote": "If your app targets Android 10 (API level 29) or higher and needs to retrieve unredacted EXIF metadata from photos, you need to declare the ACCESS_MEDIA_LOCATION permission in your app's manifest, then request this permission at runtime.",
    "found": true
   },
   {
    "id": "android-require-original",
    "statement": "The app also has to ask for the original bytes through MediaStore.setRequireOriginal.",
    "url": "https://developer.android.com/reference/android/provider/MediaStore",
    "quote": "This can be useful when the caller wants to ensure they're backing up the exact bytes of the underlying media, without any Exif redaction being performed.",
    "fetch": "ok",
    "found": true
   },
   {
    "id": "android-permission-definition",
    "statement": "ACCESS_MEDIA_LOCATION governs access to the location stored in the shared collection.",
    "url": "https://developer.android.com/reference/android/Manifest.permission",
    "quote": "Allows an application to access any geographic locations persisted in the user's shared collection.",
    "fetch": "ok",
    "found": true
   },
   {
    "id": "android-file-untouched",
    "statement": "The redaction is applied to the copy the app receives, and the method returns an EXIF redacted Uri.",
    "url": "https://developer.android.com/reference/android/provider/MediaStore",
    "quote": "Returns an EXIF redacted version of uri i.e. a Uri with metadata such as location, GPS datestamp etc. redacted from the EXIF headers.",
    "found": true
   },
   {
    "id": "imageinfo-iiurlwidth",
    "statement": "MediaWiki documents iiurlwidth, the parameter the study used to pick the display copy.",
    "url": "https://www.mediawiki.org/wiki/API:Imageinfo",
    "quote": "If iiprop=url is set, a URL to an image scaled to this width will be returned.",
    "fetch": "ok",
    "found": true
   },
   {
    "id": "imageinfo-width-not-guaranteed",
    "statement": "The API records that the returned thumbnail URL is not guaranteed to match the requested width.",
    "url": "https://www.mediawiki.org/wiki/API:Imageinfo",
    "quote": "Since T360589, it is no longer guaranteed that the thumbnail URL returned by the API matches the requested thumbnail width (iiurlwidth).",
    "found": true
   },
   {
    "id": "t360589-pregenerated",
    "statement": "Wikimedia serves a pregenerated thumbnail of the same width or larger (T360589).",
    "url": "https://www.mediawiki.org/wiki/API:Imageinfo",
    "quote": "The thumbnail, which will be fetched from a pregenerated list, is either of the same width or larger.",
    "found": true
   },
   {
    "id": "commons-exif-gps",
    "statement": "Commons says a photograph carries location coordinates if the device has a GPS receiver.",
    "url": "https://commons.wikimedia.org/wiki/Commons:EXIF",
    "quote": "Photos taken with a digital camera are likely to be JPEG images with embedded Exif data, with automatically recorded date and time the photo was taken, exposure settings, focal length, and so on, and location coordinates if the device has a GPS.",
    "fetch": "ok",
    "found": true
   },
   {
    "id": "commons-exif-inside-file",
    "statement": "Commons says that metadata travels inside the file.",
    "url": "https://commons.wikimedia.org/wiki/Commons:EXIF",
    "quote": "Exif information helps us by keeping all kinds of meta information directly within the file",
    "found": true
   },
   {
    "id": "mastodon-image-library",
    "statement": "The Mastodon configuration reference names the image library used to process uploads.",
    "url": "https://docs.joinmastodon.org/admin/config/",
    "quote": "By default, Mastodon uses ImageMagick to process images in posts.",
    "fetch": "ok",
    "found": true
   },
   {
    "id": "t360589-task",
    "statement": "The Wikimedia task T360589 is \"De-fragment thumbnail sizes in mediawiki\".",
    "url": "https://phabricator.wikimedia.org/T360589",
    "quote": "T360589 De-fragment thumbnail sizes in mediawiki",
    "fetch": "ok",
    "found": true
   },
   {
    "id": "heic-converter-strips-exif",
    "statement": "Viallo's HEIC converter strips EXIF, so the upload path reads the camera fields before converting.",
    "url": "file:apps/api/src/uploads/uploads.service.ts",
    "quote": "Extract EXIF from original HEIC before conversion (heic-convert strips EXIF)",
    "found": true,
    "source": "repository"
   }
  ]
 },
 "notes": [
  "The lab measures files the script makes. It says nothing about Wikimedia Commons, Mastodon or any published photo; those samples are the 10 September 2026 study, whose published data this post links, and were not fetched again.",
  "display-carry is the control for display-noflag: the same resize and quality, only the metadata carried forward, so the difference is the flag and not the smaller size.",
  "zero-gps is the control for the strict coordinate rule: the GPS tags are present with zero values, so coordinate_strict is no while coordinate_naive is yes.",
  "heic-sips-jpeg is macOS sips, not Viallo's converter (heic-convert). It shows that a HEIC to JPEG conversion does not lose the fields by itself; Viallo's converter does, which the code records and the post states.",
  "The device UI steps an earlier draft gave (Google Photos, iPhone, Windows, Mac) were removed: no vendor page fetched on the checked date states them."
 ]
}
