Last updated: March 16, 2026

When you capture a photo with your smartphone, the image file contains more than just pixel data. Modern mobile phones embed extensive metadata within each photo, including GPS coordinates, device information, timestamps, and camera settings. This metadata, known as EXIF (Exchangeable Image File Format), can reveal sensitive information about your location, habits, and device. For developers and power users who value privacy, understanding how to strip EXIF location data before sharing photos becomes essential.

Prerequisites

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

Step 1 - Understand EXIF Location Data

EXIF data lives inside image files themselves, added automatically by your phone’s camera application. Location data appears as GPS coordinates stored in specific EXIF tags: GPSLatitude, GPSLongitude, GPSAltitude, and related fields. When you share a photo directly from your phone’s gallery, you may inadvertently transmit this embedded location information to recipients or third-party platforms.

The implications extend beyond simple privacy concerns. Metadata can reveal your home address, workplace, travel patterns, and the exact times you visit specific locations. Social media platforms, messaging apps, and cloud storage services may retain this metadata even after you upload images, creating lasting records of your movements.

Step 2 - Inspecting EXIF Metadata

Before removing metadata, you should understand what information your photos contain. Several tools allow you to examine EXIF data from the command line.

The exiftool utility, created by Phil Harvey, provides metadata inspection:

Install on macOS
brew install exiftool

View all EXIF data from an image
exiftool photo.jpg

Extract only GPS coordinates
exiftool -gps:all photo.jpg

List all tags containing "GPS" in the name
exiftool -s -s -s -gps:all photo.jpg

For a lighter-weight alternative, the identify command from ImageMagick displays basic metadata:

identify -verbose photo.jpg | grep -i gps

Python’s Pillow library offers programmatic access:

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

def get_exif_data(image_path):
    image = Image.open(image_path)
    exif_data = image._getexif()

    if not exif_data:
        return {}

    gps_info = {}
    for tag, value in exif_data.items():
        tag_name = TAGS.get(tag, tag)
        if tag_name == "GPSInfo":
            for gps_tag in value:
                gps_tag_name = GPSTAGS.get(gps_tag, gps_tag)
                gps_info[gps_tag_name] = value[gps_tag]

    return gps_info

gps_data = get_exif_data("photo.jpg")
print(gps_data)

Step 3 - Stripping EXIF Data with Command-Line Tools

Once you identify the metadata, removing it requires several approaches depending on your workflow.

Using exiftool

The most straightforward method uses exiftool with the -all= flag to remove all metadata:

Remove all metadata, creating a new file
exiftool -all= -overwrite_original photo.jpg

Remove 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 the original file. Remove this flag to create copies instead.

Using ImageMagick

ImageMagick’s mogrify command strips metadata by default when converting images:

Convert to PNG (strips EXIF automatically)
mogrify -format png photo.jpg

Explicitly remove metadata during conversion
mogrify -strip photo.jpg

The -strip flag removes all image profiles and metadata.

Using Python

For programmatic batch processing, Pillow handles metadata removal:

from PIL import Image
import os

def strip_exif(input_path, output_path=None):
    image = Image.open(input_path)

    # Create a new image without EXIF data
    data = list(image.getdata())
    clean_image = Image.new(image.mode, image.size)
    clean_image.putdata(data)

    # Save without EXIF
    if output_path is None:
        output_path = input_path

    clean_image.save(output_path, image.format)
    print(f"Stripped EXIF from {input_path}")

Batch process directory
for filename in os.listdir("./photos"):
    if filename.lower().endswith((".jpg", ".jpeg", ".png")):
        strip_exif(f"./photos/{filename}")

A more efficient approach uses the ImageOps.exif_transpose() method, which also corrects orientation:

from PIL import Image, ImageOps

def strip_exif_efficient(input_path, output_path=None):
    with Image.open(input_path) as image:
        # Correct orientation based on EXIF
        image = ImageOps.exif_transpose(image)

        # Save without metadata
        if output_path is None:
            output_path = input_path

        # Preserve format and quality
        save_kwargs = {}
        if image.format == "JPEG":
            save_kwargs["quality"] = 95

        image.save(output_path, save_kwargs)

Step 4 - Platform-Specific Solutions

Android

Android developers can use the androidx.exifinterface library to manipulate EXIF data:

import androidx.exifinterface.media.ExifInterface

fun removeExifFromFile(filePath: String) {
    val exif = ExifInterface(filePath)

    // Clear all GPS-related tags
    exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, null)
    exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, null)
    exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, null)
    exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, null)
    exif.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, null)
    exif.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, null)

    exif.saveAttributes()
}

For complete removal, create a new file and copy only pixel data.

iOS

iOS developers work with CGImageSource and CGImageDestination from the Core Graphics framework:

import ImageIO
import UniformTypeIdentifiers

func stripEXIF(from url: URL) -> Data? {
    guard let source = CGImageSourceCreateWithURL(url as CFURL, nil),
          let uti = CGImageSourceGetType(source),
          let mutableData = CFDataCreateMutable(nil, 0),
          let destination = CGImageDestinationCreateWithData(mutableData, uti, 1, nil) else {
        return nil
    }

    let removeProperties: [CFString: Any] = [
        kCGImageDestinationLossyCompressionQuality: 1.0
    ]

    CGImageDestinationAddImageFromSource(destination, source, 0, removeProperties as CFDictionary)
    CGImageDestinationFinalize(destination)

    return mutableData as Data
}

Step 5 - Automate the Workflow

For developers who frequently share photos, automation scripts improve the process. A simple shell script processes incoming images:

#!/bin/bash

INPUT_DIR="$1"
OUTPUT_DIR="$2"

mkdir -p "$OUTPUT_DIR"

for image in "$INPUT_DIR"/*.jpg "$INPUT_DIR"/*.jpeg; do
    if [ -f "$image" ]; then
        filename=$(basename "$image")
        exiftool -all= -overwrite_original -o "$OUTPUT_DIR/$filename" "$image"
        echo "Processed: $filename"
    fi
done

Git pre-commit hooks can automatically strip metadata from images added to repositories:

.git/hooks/pre-commit
#!/bin/bash

for image in $(git diff --cached --name-only --diff-filter=AM | grep -E '\.(jpg|jpeg|png)$'); do
    if [ -f "$image" ]; then
        exiftool -all= -overwrite_original "$image"
        git add "$image"
    fi
done

Best Practices for Privacy

When handling mobile photo metadata, consider these guidelines:

Default to stripping metadata unless you specifically need it. Remove location data before sharing on social platforms or messaging applications.

Verify after processing by re-inspecting files with exiftool to confirm sensitive data no longer exists.

Preserve originals by keeping unmodified copies in a secure location while distributing stripped versions.

Automate your workflow using scripts or alias shortcuts for commonly-used commands. Adding this to your shell profile:

alias strip-gps='exiftool -gps:all= -overwrite_original'

This allows quick GPS removal from the current directory with a single command.

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 strip?

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.

Is this approach secure enough for production?

The patterns shown here follow standard practices, but production deployments need additional hardening. Add rate limiting, input validation, proper secret management, and monitoring before going live. Consider a security review if your application handles sensitive user data.

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