Last updated: March 15, 2026

Every photo your iPhone captures contains embedded metadata, Exchangeable Image File Format (EXIF) data, that reveals more than just the image itself. This metadata includes GPS coordinates, device information, timestamps, and camera settings. For developers and power users handling sensitive photography or building privacy-focused applications, understanding how to strip this location data becomes essential.

This guide covers multiple methods to remove location metadata from iPhone photos, ranging from simple command-line tools to programmatic solutions suitable for automation pipelines.

Prerequisites

Before you begin, make sure you have the following ready:

Step 1 - Understand iPhone Photo Metadata

When you capture a photo on an iPhone, iOS embeds extensive EXIF data within each image file. The most privacy-sensitive fields include:

This data persists even when you share photos through messaging apps or upload to cloud services. Removing metadata before sharing prevents unintended location exposure.

Step 2 - Method 1: Using exiftool (Command Line)

The industry-standard tool for metadata manipulation is Phil Harvey’s exiftool. Install it via Homebrew:

brew install exiftool

Strip all metadata from a single image:

exiftool -all= -overwrite_original photo.jpg

To strip only GPS data while preserving other metadata:

exiftool -gps:all= -overwrite_original photo.jpg

Batch process all JPEG files in a directory:

exiftool -all= -overwrite_original *.jpg

The -overwrite_original flag modifies files in place without creating backup copies. Remove this flag if you need backup versions.

Step 3 - Method 2: Python Script with Pillow

For developers building automated workflows, Python provides programmatic metadata removal. Install the required libraries:

pip install Pillow piexif

Create a script to strip GPS data:

#!/usr/bin/env python3
import os
import piexif
from PIL import Image

def remove_gps_data(image_path):
    """Remove GPS EXIF data from an image file."""
    try:
        exif_dict = piexif.load(image_path)

        # Remove GPS IFD (Interchangeable Field Directory)
        if 'GPS' in exif_dict:
            exif_dict['GPS'] = {}

        # Rebuild EXIF data without GPS
        exif_bytes = piexif.dump(exif_dict)

        # Save the cleaned image
        img = Image.open(image_path)
        img.save(image_path, "jpeg", exif=exif_bytes)

        print(f"Stripped GPS data from: {image_path}")
    except Exception as e:
        print(f"Error processing {image_path}: {e}")

def process_directory(directory_path):
    """Process all JPEG files in a directory."""
    for filename in os.listdir(directory_path):
        if filename.lower().endswith(('.jpg', '.jpeg')):
            filepath = os.path.join(directory_path, filename)
            remove_gps_data(filepath)

if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1:
        process_directory(sys.argv[1])
    else:
        print("Usage - python strip_gps.py <directory>")

Run the script on a directory of photos:

python strip_gps.py /path/to/photos

Step 4 - Method 3: Using ImageMagick

ImageMagick offers another command-line approach for batch processing:

Install ImageMagick
brew install imagemagick

Strip all metadata
mogrify -strip photo.jpg

Strip only GPS data while preserving other metadata
mogrify -sampling-factor 4:2:0 -strip -auto-orient \
  -interlace Plane -quality 85 \
  -define jpeg:remove-gps=true photo.jpg

The -define jpeg:remove-gps=true flag specifically targets GPS data while preserving color profiles and orientation.

Step 5 - Method 4: Shortcuts App (No-Code Solution)

For users preferring a native iOS solution, the Shortcuts app provides automation without scripting:

  1. Open Shortcuts → Create New Shortcut
  2. Add action: Select Photos
  3. Add action: Get EXIF Data (filter for GPS)
  4. Add action: Remove EXIF Metadata (select GPS only)
  5. Add action: Save to Photo Library

This shortcut can be run manually or scheduled via automation.

Step 6 - Method 5: macOS Automator Workflow

Build a drag-and-drop solution using Automator:

  1. Open Automator → New Document → Application
  2. Add Get Specified Finder Items
  3. Add Apply Quartz Filters → Remove Metadata
  4. Save as an app
  5. Drag photos onto the app icon to process them

Step 7 - Verification: Checking Removed Metadata

After processing, verify that GPS data is gone:

exiftool -gps photo.jpg

For a cleaned image, this command returns no GPS tags. You can also use:

exiftool -a -u photo.jpg | head -50

This shows all metadata including previously unknown tags, confirming removal.

Step 8 - Integration Examples

GitHub Actions Pipeline

Automate metadata stripping in CI/CD:

name: Strip Photo Metadata
on: [push]
jobs:
  strip-metadata:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install exiftool
        run: sudo apt-get install -y libimage-exiftool-perl
      - name: Strip GPS data
        run: |
          find ./photos -name "*.jpg" -exec exiftool -gps:all= -overwrite_original {} \;
      - uses: actions/upload-artifact@v4
        with:
          name: cleaned-photos
          path: ./photos

Renaming Scripts for Batch Processing

Combine stripping with organized file naming:

#!/bin/bash
Process all JPEG files and rename with date prefix

for file in *.jpg *.jpeg; do
  [ -f "$file" ] || continue

  # Get date from EXIF
  date=$(exiftool -DateTimeOriginal -d "%Y%m%d_%H%M%S" -s -s -s "$file")

  # Strip GPS
  exiftool -gps:all= -overwrite_original "$file"

  # Rename with date prefix
  if [ -n "$date" ]; then
    mv "$file" "${date}_${file}"
  fi
done

Troubleshooting

Configuration changes not taking effect

Restart the relevant service or application after making changes. Some settings require a full system reboot. Verify the configuration file path is correct and the syntax is valid.

Permission denied errors

Run the command with sudo for system-level operations, or check that your user account has the necessary permissions. On macOS, you may need to grant terminal access in System Settings > Privacy & Security.

Connection or network-related failures

Check your internet connection and firewall settings. If using a VPN, try disconnecting temporarily to isolate the issue. Verify that the target server or service is accessible from your network.

Frequently Asked Questions

How long does it take to developers?

For a straightforward setup, expect 30 minutes to 2 hours depending on your familiarity with the tools involved. Complex configurations with custom requirements may take longer. Having your credentials and environment ready before starting saves significant time.

What are the most common mistakes to avoid?

The most frequent issues are skipping prerequisite steps, using outdated package versions, and not reading error messages carefully. Follow the steps in order, verify each one works before moving on, and check the official documentation if something behaves unexpectedly.

Do I need prior experience to follow this guide?

Basic familiarity with the relevant tools and command line is helpful but not strictly required. Each step is explained with context. If you get stuck, the official documentation for each tool covers fundamentals that may fill in knowledge gaps.

Will this work with my existing CI/CD pipeline?

The core concepts apply across most CI/CD platforms, though specific syntax and configuration differ. You may need to adapt file paths, environment variable names, and trigger conditions to match your pipeline tool. The underlying workflow logic stays the same.

Where can I get help if I run into issues?

Start with the official documentation for each tool mentioned. Stack Overflow and GitHub Issues are good next steps for specific error messages. Community forums and Discord servers for the relevant tools often have active members who can help with setup problems.

Related Articles

Stripping metadata after the fact works, but preventing collection at capture time is cleaner. On iOS, disable location access for the Camera app: Settings > Privacy and Security > Location Services > Camera > Never.

With location disabled for Camera, GPS fields are never written to EXIF. You still get DateTimeOriginal and device model embedded, but the privacy-critical coordinates are absent from the start.

For developers building apps that process user photos, always request PHAccessLevel.addOnly rather than full photo library access. When you receive image data in a share extension, strip EXIF before any network upload:

import ImageIO
import CoreImage

func stripExif(from imageData: Data) -> Data? {
    guard let source = CGImageSourceCreateWithData(imageData as CFData, nil),
          let type = CGImageSourceGetType(source) else { return nil }

    let mutableData = NSMutableData()
    guard let dest = CGImageDestinationCreateWithData(mutableData, type, 1, nil) else { return nil }

    let options: [CFString: Any] = [
        kCGImageDestinationMetadata: [:],
        kCGImageMetadataShouldExcludeGPS: true
    ]

    CGImageDestinationAddImageFromSource(dest, source, 0, options as CFDictionary)
    CGImageDestinationFinalize(dest)
    return mutableData as Data
}

Metadata Tool Comparison

Different tools suit different workflows. Here is how the main options compare:

Tool GPS Strip Full EXIF Strip Batch Support Handles HEIC Platform
exiftool Yes Yes Yes Yes macOS, Linux, Windows
ImageMagick Yes Yes Yes Limited macOS, Linux, Windows
Pillow + piexif Yes Yes Scripted No macOS, Linux, Windows
iOS Shortcuts Yes Limited No Yes iOS only
macOS Automator Partial Partial Yes No macOS only

For CI/CD pipelines, exiftool is the clear choice because it handles every image format, including HEIC files produced by modern iPhones. When processing HEIC files directly:

Strip GPS from HEIC files
exiftool -gps:all= -overwrite_original *.heic

Convert HEIC to JPEG while stripping all metadata
exiftool -o output_dir/ -all= -ext heic .

Step 10 - Integrate Metadata Stripping into Upload Pipelines

If you build applications that accept user photo uploads, enforce metadata stripping server-side as defense in depth. Users may upload photos from older apps or devices that ignore client-side stripping:

from PIL import Image
import piexif
import io

def process_upload(file_bytes: bytes) -> bytes:
    """Strip EXIF metadata from uploaded image bytes."""
    img = Image.open(io.BytesIO(file_bytes))
    output = io.BytesIO()

    if img.format == "JPEG" and "exif" in img.info:
        exif_dict = piexif.load(img.info["exif"])
        exif_dict["GPS"] = {}
        exif_bytes = piexif.dump(exif_dict)
        img.save(output, format="JPEG", exif=exif_bytes, quality=90)
    else:
        img.save(output, format=img.format or "JPEG")

    return output.getvalue()

Add this to your upload handler in Django, FastAPI, or any framework before writing to your storage layer. Store the returned bytes, not the original upload.

Built by theluckystrike. More at zovo.one