Image Metadata & EXIF Extractor: GPS, Camera, Colors, Hash avatar

Image Metadata & EXIF Extractor: GPS, Camera, Colors, Hash

Pricing

from $3.50 / 1,000 analyzed images

Go to Apify Store
Image Metadata & EXIF Extractor: GPS, Camera, Colors, Hash

Image Metadata & EXIF Extractor: GPS, Camera, Colors, Hash

Read image metadata in bulk: EXIF camera and lens, exposure settings, date taken, GPS location with map link, size, color profile, dominant colors and perceptual hashes to find near-duplicates. Image URLs or a dataset column in. Failed images are free.

Pricing

from $3.50 / 1,000 analyzed images

Rating

0.0

(0)

Developer

Charles Markette

Charles Markette

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Categories

Share

Image Metadata & EXIF Extractor reads the metadata of images in bulk and returns one row per image. Each row has the camera, lens and exposure settings, the date taken (with its timezone when the camera recorded one), the GPS location in decimal degrees with a Google Maps link, and the author, copyright, title, description and keywords from EXIF, XMP, IPTC or PNG text. It also gives size, format, orientation, DPI and colour profile, the dominant colours, a SHA-256 and three perceptual hashes (aHash, pHash, dHash), and can find near-duplicates. Paste image URLs, or point it at any Apify dataset with image links, and the columns are added next to each item.

Why this Actor

  • Readable fields, not a tag dump. GPS degrees/minutes/seconds become signed decimal lat / lon (south and west are negative). Exposure becomes "1/250", the flash code becomes "Auto, fired", and the date becomes ISO 8601. If you want every tag, turn on All EXIF tags (raw).
  • Honest dates. EXIF dates are the camera's local time with no timezone. dateTaken is that local time. dateTakenUtc is only filled when the file records its offset (EXIF OffsetTimeOriginal, or an XMP date with a timezone). It is never guessed.
  • Descriptive metadata from every common place. Author and copyright are read from EXIF Artist / Copyright, then XMP (dc:creator, dc:rights, dc:title, dc:description, dc:subject), then IPTC (By-line, Copyright Notice, Object Name, Caption, Keywords), then PNG text chunks. Keywords are merged from all of them.
  • Find duplicates and re-uploads. sha256 finds exact copies. pHash also matches copies that were resized, re-compressed or lightly edited. With Find near-duplicates, each row says which earlier image it looks like, and the run summary lists every group.
  • Privacy-minded. Camera and lens serial numbers, the camera owner's name and the binary MakerNote are never output. GPS location can be switched off, which removes the coordinates everywhere, including the raw EXIF.
  • Safe with untrusted URLs. Private, loopback, link-local and cloud-metadata addresses are refused, on every redirect hop too. Downloads are capped at 50 MB, and images are size-checked from their header before any pixels are decoded, so a "decompression bomb" can't exhaust memory.
  • One bad image never stops the run. A missing, private, oversized or broken image gets one error row that explains the problem, and that row is free.

Use cases

  • Photo libraries and DAM: camera, lens, settings and date taken for every image, ready for a spreadsheet or database.
  • Copyright and licensing checks: author, copyright and keywords embedded by photographers and agencies.
  • Location audits: find which published images still carry GPS coordinates (hasGps), then strip them with the Image Converter.
  • Duplicate and re-upload detection: group a scraped catalogue's product photos by pHash to find the same picture under different URLs.
  • Colour tagging: dominant and average colours for product images, to filter or sort by colour.
  • Image QA: dimensions, megapixels, aspect ratio, DPI, colour profile, transparency and animation for a whole dataset of images.

How to use it

  1. Add Image URLs (one per line), and/or pick a Dataset to enrich. For datasets, set Image URL fields if your field isn't one of imageUrl, imageUrls, image, images, thumbnailUrl, thumbnail, photo, src or url. A field that holds a list of URLs gives one row per image.
  2. Choose what to extract. GPS, colours and hashes are on by default. Raw EXIF and near-duplicate search are off.
  3. Run it. Export the rows as CSV, Excel or JSON, or chain the run with an integration. The run summary is saved as OUTPUT in the key-value store.

Input example

{
"imageUrls": [
"https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/Canon_40D.jpg",
"https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/gps/DSCN0010.jpg"
],
"includeGps": true,
"includeColors": true,
"includeHashes": true,
"findDuplicates": true,
"duplicateThreshold": 6
}

Output example (one row per image; the values are illustrative)

{
"url": "https://example.com/photos/IMG_4127.jpg",
"finalUrl": "https://cdn.example.com/photos/IMG_4127.jpg",
"statusCode": 200,
"format": "jpeg",
"mimeType": "image/jpeg",
"width": 4000,
"height": 6000,
"megapixels": 24.0,
"aspectRatio": 0.6667,
"orientation": 6,
"mode": "RGB",
"hasAlpha": false,
"animated": false,
"frames": 1,
"fileBytes": 8251334,
"colorProfile": "sRGB IEC61966-2.1",
"dpi": 72,
"hasExif": true,
"camera": {"make": "Canon", "model": "Canon EOS R6", "lens": "RF24-105mm F4 L IS USM"},
"settings": {"exposureTime": "1/250", "exposureSeconds": 0.004, "fNumber": 8.0, "iso": 200, "focalLength": 50.0,
"focalLength35mm": null, "flash": "Off, did not fire", "flashFired": false, "whiteBalance": "Auto"},
"dateTaken": "2024-05-01T14:03:22+02:00",
"dateTakenUtc": "2024-05-01T12:03:22Z",
"timezoneOffset": "+02:00",
"software": "Adobe Lightroom Classic 13.0",
"author": "Jane Photographer",
"copyright": "© 2024 Jane Photographer",
"title": "Harbour at dawn",
"description": "Fishing boats in the harbour",
"keywords": ["harbour", "boats", "dawn"],
"hasGps": true,
"gps": {"lat": 52.3700944, "lon": 4.8838889, "altitude": 58.5,
"mapsUrl": "https://www.google.com/maps?q=52.3700944,4.8838889", "timestampUtc": "2024-05-01T12:03:21Z"},
"dominantColors": [{"hex": "#2f5d8a", "percent": 31.4}, {"hex": "#d9c7a0", "percent": 22.0},
{"hex": "#1c2a33", "percent": 18.7}, {"hex": "#8fa9bf", "percent": 15.2},
{"hex": "#5e4a36", "percent": 6.1}],
"averageColor": "#6b7a84",
"hashes": {"sha256": "9f2b…", "aHash": "ffc3810000183cff", "pHash": "b696446969490fbd", "dHash": "042c6c9c1f638801"},
"duplicateOf": null,
"duplicateDistance": null,
"rawExif": null,
"error": null,
"analyzedAt": "2026-10-21T12:00:00Z"
}
  • width and height are the size as displayed: the EXIF orientation is applied, so a portrait phone photo stored sideways (orientation 6 or 8) is reported as portrait. megapixels is the stored pixel count.
  • camera, settings and gps are null when the file has none of those fields. Other fields are null when the file doesn't contain them.
  • hasGps says whether the file contains a GPS position, even when GPS location is off.
  • rawExif (with All EXIF tags) is an object of tag name → value. Rationals become numbers, and binary values become "<N bytes>".
  • A failed image has error set and the metadata fields null. When you enrich a dataset with Keep the item's original fields on, the item's own fields come first in each row.

Near-duplicates

With Find near-duplicates on, each image's pHash is compared with every image analyzed before it (in this run, and in the earlier part of a resumed run):

  • Per row: duplicateOf is the URL of the first earlier image within the Near-duplicate threshold, and duplicateDistance is how many of the 64 bits differ (0 = the same picture to the hash). The first image of a group has duplicateOf: null.
  • Groups, in the run summary: OUTPUT → duplicateGroups lists every group as {"group": 1, "count": 3, "images": [{"url": "…", "index": 0}, …]}, where index is the row's position in the dataset (0-based). Groups chain: if A matches B and B matches C, all three are in one group even if A and C are further apart. Up to 20,000 images are listed (duplicateGroupsTruncated says when more were found).
  • Threshold: 0 matches visually identical images. 6 (the default) also catches resized, re-compressed and slightly edited copies. Values above about 10 start to match different photos of similar scenes. Flat, single-colour images all hash alike and group together.

Rows can't be changed after they are stored, so the group number isn't a column. Use duplicateOf in the rows, or duplicateGroups in OUTPUT.

How much does it cost?

Pay per event, Apify platform usage included:

  • $0.005 per analyzed image (image-analyzed): each image that was downloaded and decoded, and got its metadata row.
  • $0.005 run start per GB of Actor memory (minimum one; at the default 1 GB that's $0.005 a run). The run start applies to every run, even one where every image fails.

Apify Store discounts: the price above is for Apify's Free plan. Paid plans pay less per analyzed image: $0.0045 on Starter, $0.004 on Scale, $0.0035 on Business. The "from" price at the top of the Store page is the Business price.

Free: images that fail (download errors, HTTP errors such as 404 or 403, blocked private addresses, invalid URLs, files over 50 MB, pages or files that aren't images, images over the size limit, damaged files) and repeats skipped by Analyze each URL once. Near-duplicate search, raw EXIF, colours and hashes cost nothing extra.

Worked examples:

Examples use the Free-plan rate.

  • 1,000 product photos at the default 1 GB: 1,000 × $0.005 + $0.005 run start = $5.005.
  • 200 image links where 20 return 404: 180 × $0.005 + $0.005 = $0.905. The 20 failed rows are free.
  • A daily run on 50 new images: 50 × $0.005 + $0.005 = $0.255 per run, about $7.65 per month (30 runs).
  • 2,000 large camera photos with the memory raised to 4 GB: 2,000 × $0.005 + 4 × $0.005 = $10.02.

If you set a maximum cost per run, the Actor stops cleanly at that limit: images beyond it are neither stored nor charged.

Privacy and lawful use

GPS coordinates, dates, camera details and author names in image metadata can be personal data, for example under the GDPR in the EU and UK, and under similar laws elsewhere. A photo's location can reveal where someone lives or was at a given time. You are responsible for having a lawful basis to collect and use this data, and for using it in line with the law and the image owners' rights. Turn off GPS location if you don't need it. Camera and lens serial numbers and the camera owner's name are never output. To publish images without their metadata, strip it with the Image Converter.

FAQ and limits

Why are camera, date and GPS empty for my image?

The metadata isn't in the file you linked. Social networks (Instagram, Facebook, X, WhatsApp), most image CDNs, and many CMSs remove EXIF and GPS when they resize or re-encode an image. Phones also often leave out the location when you share a photo. Link the original file where you can. The Actor's request doesn't list WebP or AVIF among the formats it accepts, so CDNs that pick a format from the request are less likely to send a re-encoded copy.

Which formats are supported?

JPEG, PNG (and APNG), WebP, GIF, AVIF, TIFF and BMP. HEIC / HEIF (iPhone photos) isn't supported: the decoder needed for it isn't included, for licensing reasons. Convert HEIC to JPEG first (iPhones can share as JPEG, Most Compatible). RAW camera files, SVG and PDF aren't supported either. For animations and multi-frame files, frames counts the frames and the colours and hashes come from the first frame.

What isn't read?

Vendor MakerNotes (shutter count, some lens names that only appear there), and XMP fields beyond the common descriptive ones listed above. All EXIF tags shows every standard EXIF tag except serial numbers, the owner name and the MakerNote.

How do the hashes compare with other tools?

aHash, pHash and dHash use the same definitions as the popular Python imagehash library (8×8 grid, 64 bits, hex with the first pixel as the most significant bit). They are computed from a reduced copy of the image with the EXIF orientation applied, so values can differ from other tools by a bit or two. Compare hashes with a Hamming distance, not with equality. sha256 is of the downloaded file's bytes.

Is 0,0 a location?

Many devices write 0,0 when they have no GPS fix, so 0,0 (and missing or 0/0 values) is treated as "no position".

Limits

  • Download size: 50 MB per image. The file is downloaded in full (the pixels are decoded to check the image and compute colours and hashes).
  • Image size: JPEG up to 150 megapixels (decoded at reduced scale); other formats up to 60 megapixels. Larger images get a free error row.
  • No proxy, cookies or browser: images behind sign-ins, bot protection or hotlink protection can fail with HTTP 403.
  • Google Drive and Dropbox share links to a single file are turned into download links. Folder links aren't supported.
  • If the platform restarts a run, already stored rows are skipped and the run continues after them. Near-duplicate search reloads the earlier rows' hashes.
ActorUse it to
Image Converter & ResizerStrip EXIF and GPS before publishing, or convert and resize the images you analyzed.
Dataset Filter & TransformKeep only the rows you need (for example hasGps: true), or flatten camera and settings into columns.
Merge & Deduplicate DatasetsKeep only new image links between runs before analyzing them, or deduplicate rows by hashes.sha256.
Google Sheets Import & ExportPut the metadata rows into a Google Sheet.

Image decoding: Pillow. Hash definitions: imagehash (not a dependency; implemented here).