How to Read EXIF Data from Images: Python, JavaScript, and Quick Browser Check
- Python: use the exifread library for simple reads, piexif for editing
- JavaScript: use exifr (browser + Node.js, modern) or exif-js (browser only)
- For quick manual checks without writing code: free browser tool handles any JPEG instantly
- All code examples output GPS coordinates, camera info, and timestamps
Table of Contents
If you're building a photo upload pipeline, image analysis tool, or any app that needs to extract camera data, you'll need code that reads EXIF. This guide covers the two most common languages — Python and JavaScript — with working code examples for GPS coordinates, camera info, and timestamps. For one-off manual checks while developing, the free browser EXIF viewer is faster than writing a script.
Reading EXIF Data in Python
Option 1: exifread (simplest, read-only)
pip install exifread
import exifread
with open('photo.jpg', 'rb') as f:
tags = exifread.process_file(f)
# Print all tags
for tag, value in tags.items():
print(f"{tag}: {value}")
# Get specific fields
gps_lat = tags.get('GPS GPSLatitude')
gps_lon = tags.get('GPS GPSLongitude')
date_taken = tags.get('EXIF DateTimeOriginal')
camera = tags.get('Image Model')
print(f"Camera: {camera}")
print(f"Taken: {date_taken}")
print(f"GPS: {gps_lat}, {gps_lon}")
Option 2: Pillow + piexif (read + write)
pip install pillow piexif
from PIL import Image
import piexif
img = Image.open('photo.jpg')
exif_dict = piexif.load(img.info.get('exif', b''))
# Read DateTimeOriginal
zeroth = exif_dict.get('Exif', {})
dt = zeroth.get(piexif.ExifIFD.DateTimeOriginal, b'').decode()
print(f"Date taken: {dt}")
# GPS coordinates
gps = exif_dict.get('GPS', {})
if gps:
lat = gps.get(piexif.GPSIFD.GPSLatitude)
lon = gps.get(piexif.GPSIFD.GPSLongitude)
print(f"GPS: {lat}, {lon}")
Reading EXIF Data in JavaScript
exifr — recommended for both browser and Node.js
npm install exifr
In Node.js:
const exifr = require('exifr')
async function readExif(filePath) {
const output = await exifr.parse(filePath, {
pick: ['Make', 'Model', 'DateTimeOriginal', 'GPSLatitude', 'GPSLongitude', 'ISO', 'FNumber', 'ExposureTime']
})
console.log('Camera:', output.Make, output.Model)
console.log('Date:', output.DateTimeOriginal)
console.log('GPS:', output.GPSLatitude, output.GPSLongitude)
console.log('ISO:', output.ISO, 'f/', output.FNumber)
}
readExif('./photo.jpg')
In the browser (from a file input):
import exifr from 'exifr'
document.querySelector('input[type=file]').addEventListener('change', async (e) => {
const file = e.target.files[0]
const exif = await exifr.parse(file)
console.log('GPS:', exif.latitude, exif.longitude)
console.log('Taken:', exif.DateTimeOriginal)
})
Note: exifr parses the EXIF data entirely client-side when running in the browser — the file is not uploaded anywhere. This is the same approach our browser tool uses.
Sell Custom Apparel — We Handle Printing & Free ShippingConverting GPS EXIF to Decimal Coordinates
GPS in EXIF is stored as degrees, minutes, seconds (DMS) — you usually need to convert to decimal degrees for maps:
def dms_to_decimal(dms_array, ref):
"""Convert EXIF GPS DMS tuples to decimal degrees."""
degrees = float(dms_array[0].num) / float(dms_array[0].den)
minutes = float(dms_array[1].num) / float(dms_array[1].den)
seconds = float(dms_array[2].num) / float(dms_array[2].den)
decimal = degrees + (minutes / 60) + (seconds / 3600)
if ref in ['S', 'W']:
decimal = -decimal
return decimal
# Usage with exifread:
lat = dms_to_decimal(
tags['GPS GPSLatitude'].values,
tags['GPS GPSLatitudeRef'].values
)
lon = dms_to_decimal(
tags['GPS GPSLongitude'].values,
tags['GPS GPSLongitudeRef'].values
)
print(f"https://maps.google.com/?q={lat},{lon}")
The exifr library in JavaScript does this conversion automatically — it outputs decimal values directly. exifread returns raw DMS tuples that need the above conversion.
When to Write Code vs. Use the Browser Viewer
Writing code makes sense when you need to:
- Process many files in a batch (100+ photos)
- Integrate EXIF extraction into an upload pipeline
- Store metadata in a database alongside files
- Trigger logic based on metadata (e.g., sort by GPS region, reject photos without timestamps)
- Read formats beyond JPEG: RAW, HEIC, video metadata
The free browser EXIF viewer is faster for:
- Checking a single file during development
- Verifying your code outputs the correct fields
- Debugging why a specific photo is failing your pipeline
- Sharing results with non-technical colleagues (send them to the URL)
The browser tool uses the same underlying EXIF parsing approach as exifr — piexif-based browser parsing. Drop a file to see all raw field names and values, which helps when you're figuring out which fields to request in your code.
Quick EXIF Check While You Code — Free
Debugging EXIF parsing? Drop a photo in our viewer to see the raw field names and values — confirm your library is reading what you expect.
Open Free EXIF ViewerFrequently Asked Questions
What's the best Python library for reading EXIF data?
For read-only use, exifread is simple and reliable. For reading and writing EXIF (editing metadata), piexif is the most common choice. For working with both images and metadata in one library, Pillow with piexif is a common combination. ExifTool also has a Python wrapper (pyexiftool) if you need to handle every file format and every metadata standard.
Does JavaScript have a good EXIF library for React apps?
Yes — exifr is the best modern option. It works in both browser and Node.js environments, handles async correctly, supports tree-shaking to minimize bundle size, and returns GPS as decimal degrees (no DMS conversion needed). For browser-only projects, exif-js is also commonly used though less actively maintained.
Why does my EXIF code return empty GPS values for some photos?
Photos taken with location services disabled, on cameras without GPS, or downloaded from platforms that strip EXIF (Instagram, Twitter/X, Facebook) will have no GPS fields. Your code should handle the case where GPS is absent. Also check that you're opening the file in binary mode (rb) in Python — opening in text mode corrupts the EXIF block.

