# Image Metadata Remover — Strip EXIF, GPS & Serials, Lossless (`hermeskd/image-metadata-remover`) Actor

Remove EXIF, GPS location, camera serials, names and edit history from JPEG, PNG, WebP, HEIC, AVIF and TIFF, and thumbnails from JPEG, PNG and WebP, without re-encoding: pixels stay identical, checked on every file. Content Credentials and AI labels are kept. $0.001 per image.

- **URL**: https://apify.com/hermeskd/image-metadata-remover.md
- **Developed by:** [Logan Parker](https://apify.com/hermeskd) (community)
- **Categories:** AI, Developer tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 image processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Remove the metadata that gives a photo away — GPS location, camera and phone serial numbers, names and contact details, captions and editing history — from JPEG, PNG, WebP, HEIC, AVIF and TIFF images, and embedded thumbnails from JPEG, PNG and WebP, without re-encoding them: the pixels stay identical, and every file is checked before it is returned. It is for anyone publishing, sending or selling photos, and for AI agents, which can call and pay for it through Apify's MCP server and agentic payments; Content Credentials (C2PA) and AI-generation labels are always kept, never stripped. It costs $0.001 per image, and an image that fails is never charged.

### Example result

Example record for the minimal input under How to use it, as this Actor's code returned it in a local run on 2026-10-27 (the cleaned 835-byte JPEG is in the run's key-value store; `outputUrl` is shown in its platform form, the store id written as `STORE_ID`). The record names the fields it found — never their values:

```json
{
  "url": "https://raw.githubusercontent.com/python-pillow/Pillow/262e8e48229197ef08792de41a6bdd94e42219a0/Tests/images/exif_gps.jpg",
  "ok": true,
  "format": "jpeg",
  "width": 8,
  "height": 8,
  "reportOnly": false,
  "removedGroups": [
    "location",
    "device",
    "thumbnails",
    "otherMetadata"
  ],
  "keptGroups": [
    "timestamps",
    "structure"
  ],
  "fieldsRemoved": 17,
  "fieldsKept": 1,
  "found": {
    "location": [
      "GPS:GPSAltitudeRef",
      "GPS:GPSDateStamp",
      "GPS:GPSDifferential",
      "GPS:GPSLatitude",
      "GPS:GPSVersionID"
    ],
    "device": [
      "ExifIFD:LensInfo",
      "ExifIFD:LensMake",
      "IFD0:Make",
      "IFD0:Model",
      "IFD0:Software"
    ],
    "timestamps": [
      "ExifIFD:DateTimeOriginal"
    ],
    "thumbnails": [
      "IFD0:OtherImageLength"
    ],
    "otherMetadata": [
      "ExifIFD:ExposureCompensation",
      "ExifIFD:ExposureTime",
      "ExifIFD:ISOSpeed",
      "ExifIFD:Opto-ElectricConvFactor",
      "ExifIFD:Sharpness",
      "IFD0:BlackLevelDeltaH"
    ]
  },
  "aiLabel": false,
  "digitalSourceTypes": [],
  "contentCredentials": null,
  "bytesBefore": 1097,
  "bytesAfter": 835,
  "pixelsIdentical": true,
  "notes": [],
  "key": "cleaned-000-81d9594089.jpg",
  "outputUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/cleaned-000-81d9594089.jpg",
  "sha256": "1c0ad852a7d2944f3decdbfe8b9bad08f9c6263296926740c98ce42bdb1bb90b"
}
```

### How to use it

Start a run in Apify Console, by API or from an agent with an input like this one — it is the input Apify runs every day to test this Actor:

```json
{"urls": ["https://raw.githubusercontent.com/python-pillow/Pillow/262e8e48229197ef08792de41a6bdd94e42219a0/Tests/images/exif_gps.jpg"]}
```

| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
| `urls` | array of strings | yes | — | Image URLs (JPEG, PNG, WebP, HEIC/HEIF, AVIF, TIFF), http or https, 1–100 per run, up to 100 MB each. Each URL becomes one record and, unless reportOnly is set, one cleaned file. |
| `removeLocation` | boolean | no | `true` | GPS position, altitude and direction, and place names (city, state, country, sub-location) in EXIF, XMP and IPTC. |
| `removeDevice` | boolean | no | `true` | Camera and phone make, model and serial numbers, lens details and serial, owner name, unique image ID, the maker's private notes (MakerNotes), and the software and computer that wrote the file. |
| `removePeople` | boolean | no | `true` | Artist, creator, author and by-line names, the creator's address, phone, email and website, people shown, and the AI prompt writer's name. |
| `removeTimestamps` | boolean | no | `false` | When the photo was taken, digitized and modified, with time-zone offsets and sub-seconds, in EXIF, XMP, IPTC and PNG. Kept unless set. |
| `removeThumbnails` | boolean | no | `true` | Embedded thumbnails and preview images in JPEG, PNG and WebP (EXIF, Photoshop, XMP, MPF previews) and anything appended after a JPEG's end (a motion-photo video, an appended image). A thumbnail can show the photo before it was cropped or edited. A HEIF or AVIF thumbnail item and a TIFF's reduced-resolution image are kept. |
| `removeDescriptions` | boolean | no | `true` | Titles, captions, descriptions, keywords, comments (EXIF, XMP, IPTC, JPEG and PNG comments) and ratings. |
| `removeEditingHistory` | boolean | no | `true` | XMP document and instance IDs, the editing history (which software did what, sometimes with file paths), Lightroom and Camera Raw settings, and Photoshop layers. |
| `removeRights` | boolean | no | `false` | Copyright notices, rights, usage terms, licence and credit lines. Kept unless set: they are rights-management information. |
| `removeColorProfile` | boolean | no | `false` | The embedded ICC colour profile. Kept unless set: removing it can change how colours look. |
| `removeOtherMetadata` | boolean | no | `true` | Everything else not listed: exposure, flash, focus and scene settings, lens corrections, unknown tags, Photoshop print settings. |
| `reportOnly` | boolean | no | `false` | List what each image carries, group by group, without changing or storing it. Charged like a cleaned image. |

Every limit above is enforced by the input schema and again in code. The groups, in more detail:

- Always kept, with no switch: **provenance** — Content Credentials (the C2PA manifest store: JPEG APP11, PNG `caBX`, WebP `C2PA`, the HEIF/AVIF box), the IPTC digital source type and AI-system fields in XMP, the remote-manifest link, and the text an image generator writes into a PNG (AUTOMATIC1111 and Forge `parameters`, ComfyUI `prompt` and `workflow`, InvokeAI, Fooocus, NovelAI); and **structure** — orientation, resolution, colour space, the coded image's own parameters, an MPF stereo pair and an HDR gain map.
- A field ExifTool reads but that no group above names (exposure, flash, scene, unknown tags, a Print Image Matching block) is `otherMetadata`, and so is an APPn segment of a JPEG outside the standard set (JFIF, EXIF, XMP, ICC, MPF, Content Credentials, Photoshop/IPTC, Adobe): a maker's private block that the Actor cuts out itself. Face and person regions (Lightroom, digiKam, Picasa, Microsoft Photo, IPTC image regions) are `people`; drone flight altitudes and attitude are `location`; ImageMagick's `exif:` PNG keywords follow the EXIF field they copy. Every field lands in exactly one group.

### Events and prices

Pay per event; platform usage is included in the price, never passed through.

| Event | Title | Charged when | FREE / BRONZE | SILVER | GOLD / PLATINUM / DIAMOND |
|---|---|---|---|---|---|
| `image-processed` | Image processed | One image cleaned and stored, or with reportOnly read and reported. | $0.001 | $0.0009 | $0.0008 |

One event per image, charged only after the cleaned file is stored (or the report written) and its record written; whatever the format, size and number of fields removed. Apify also charges its standard `apify-actor-start` event: $0.00005 per GB of run memory (1 event, $0.00005, at the default 1,024 MB). The minimum maximum-charge a caller can set is $0.01.

Worked example on the FREE tier: the photo above costs $0.001 plus $0.00005 for the start, $0.00105 in all; a run of 100 photos costs 100 × $0.001 = $0.10 plus the start. Nothing is charged for an image that fails.

### Call it from an agent

Through Apify's MCP server (`https://mcp.apify.com`), tool `call-actor`:

```json
{"actor": "hermeskd/image-metadata-remover", "input": {"urls": ["https://raw.githubusercontent.com/python-pillow/Pillow/262e8e48229197ef08792de41a6bdd94e42219a0/Tests/images/exif_gps.jpg"]}, "callOptions": {"maxTotalChargeUsd": 0.01, "timeout": 1800}, "waitSecs": 30}
```

The call returns the run's status and its `defaultDatasetId`. Read the records with `get-dataset-items`:

```json
{"datasetId": "<defaultDatasetId from the call>", "limit": 100}
```

Each record's `outputUrl` is the cleaned image itself (also readable with `get-key-value-store-record` and the record's `key`). As a dedicated tool, add `https://mcp.apify.com?tools=hermeskd/image-metadata-remover` to your MCP client. A photo finishes in about a second of work, so one call returns the result inside the 30-second wait; `maxTotalChargeUsd` caps what the run can charge, and when it is reached the remaining URLs come back as `charge_limit_reached` records and are not charged. To see what a photo reveals without changing it, add `"reportOnly": true`.

### Output fields

One record per input URL, and one cleaned image per successful record in the run's default key-value store (none with `reportOnly`).

| Field | Meaning |
|---|---|
| `url` | The input URL; null only on the one invalid_input record of a run given no input. |
| `ok` | true when the image was cleaned and stored (or, with reportOnly, read); false with error. |
| `format` | The image format read from the file's bytes; the cleaned file keeps it. |
| `width` | Width in pixels as stored (before EXIF orientation is applied). |
| `height` | Height in pixels as stored. |
| `reportOnly` | true when the run only listed the metadata; nothing was changed or stored. |
| `removedGroups` | The field groups found in the image and removed from it. |
| `keptGroups` | The field groups found in the image and kept: the ones switched off, plus provenance (Content Credentials and AI labels, always kept) and structure (orientation, resolution, colour space). |
| `fieldsRemoved` | How many metadata fields were removed. |
| `fieldsKept` | How many metadata fields were kept, structure fields not counted. |
| `found` | Every metadata field found, by group: field names as directory:name (GPS:GPSLatitude, IFD0:Make, XMP-dc:Creator). Names only — values are never returned. structure is not listed. |
| `aiLabel` | true when the image carries a label saying it was generated by AI (an IPTC digital source type such as trainedAlgorithmicMedia, or an image generator's PNG text). Always kept. |
| `digitalSourceTypes` | IPTC digital source type codes found in the Content Credentials or XMP, such as trainedAlgorithmicMedia or digitalCapture. |
| `contentCredentials` | null when the image has none; otherwise {present, kept (always true), stateBefore and stateAfter (Trusted, Valid or Invalid), verifiesAfterEdit, generator, digitalSourceTypes, carriesPersonalData, personalAssertions}. Removing any metadata makes a credential fail verification: it stays in the file, showing the file was edited after signing. carriesPersonalData is true when the kept credential holds an assertion that can name a person or place (an author or creator, an identity, embedded EXIF or IPTC); personalAssertions lists those assertions' labels, never their values. The Actor never removes them. |
| `bytesBefore` | Size of the downloaded image. |
| `bytesAfter` | Size of the cleaned image. |
| `pixelsIdentical` | true: the coded image data (JPEG, PNG, WebP) or the decoded pixels (TIFF, HEIF, AVIF) were checked equal after the rewrite. A file that fails the check is never returned. |
| `notes` | Anything kept that a caller may not expect (bytes after the end of a JPEG, a HEIF thumbnail image). |
| `key` | Key of the cleaned image in the run's default key-value store. |
| `outputUrl` | The cleaned image's key-value store record URL (API). |
| `sha256` | SHA-256 of the cleaned file. |
| `error` | {code, message} when ok is false. |

### Limits and run time

- 1–100 URLs per run; files up to 100 MB each. The format is read from the file's bytes, never from its name or the server's content type; GIF, BMP, SVG, raw camera files and PDF are refused as `not_image`.
- Nothing is re-encoded: ExifTool rewrites only the metadata. Before a file is returned, the Actor checks that every field of every removed group is gone, that every kept field is still there, that the coded image (JPEG, PNG, WebP) is byte-for-byte unchanged or the decoded pixels of every frame (TIFF, HEIF, AVIF) are equal, and that Content Credentials are carried byte-for-byte. A file that fails any check is never returned. TIFF, HEIF and AVIF images over 100 megapixels across their frames are refused as `too_large`, because their check decodes them. A TIFF, HEIF or AVIF image the decoder cannot read is `not_image`, found before anything is written. Every image build of this Actor runs the same checks on planted images of all six formats and on Content Credentials fixtures where its ExifTool is installed, and a build where any check fails is never deployed; each run logs the ExifTool version.
- Content Credentials: a credential signs every byte of the file outside itself, so removing any metadata from a signed image makes the credential fail verification. It stays in the file, showing the file was edited after signing, and the record says so (`contentCredentials.verifiesAfterEdit: false`). With every switch off nothing is removed, and the file comes back byte for byte with its credential still verifying. Where a rewrite would drop the credential (a TIFF that carries one, with the ExifTool release this Actor was tested on), the image is refused as `metadata_not_removable` rather than returned without it. A kept credential can name its author or carry other personal assertions (a CreativeWork author, an identity, embedded EXIF or IPTC); the Actor does not remove it, and the record says so in `contentCredentials.carriesPersonalData`, naming the assertions by label. A damaged credential that reads differently once the file around it changes is refused as `metadata_not_removable`, so it is never altered.
- A metadata block the Actor finds in the file but ExifTool cannot read (a PNG whose EXIF chunk follows a Content Credentials chunk) is refused as `metadata_not_removable`, never passed over as empty.
- Thumbnails and previews are removed from JPEG, PNG and WebP. A HEIF or AVIF thumbnail is its own image item, not metadata, and a TIFF's second and later images are its pages or reduced-resolution copies: both are kept, and the record's `notes` say so. Bytes after the end of a JPEG (a motion-photo video, an appended image or preview) go with `removeThumbnails`; kept, they are noted. An MPF stereo pair and an HDR gain map are part of the picture and always kept. A Print Image Matching block inside a camera maker's notes is kept with them when `removeDevice` is off.
- Removing the colour profile can change how colours look; the copyright notice, the licence and the dates are kept unless you switch them off.
- Downloads: files download at 2 MB/s or faster — each download has a budget of 30 s plus 1 s per 2 MB of its declared size (or of the 100 MB cap when the server declares none), and stops when no byte arrives for 30 s; at most 2 requests a second go to one host. GitHub release links are refused (github.com's robots.txt disallows them); give a raw.githubusercontent.com address or your own storage.
- Typical run time, measured on 2026-10-27 on one CPU core: about 0.6 to 1 second of work per photo; the 15 benchmark images, from 1 KB to a 51-megapixel HEIC, took 12.9 seconds in all. The default 1,024 MB is enough for a 51-megapixel HEIC (569 MB at peak); the default run timeout is 1,800 seconds.

### Errors

Errors are records with `ok: false` and `error.code`; none is charged and no file is stored.

| `error.code` | Meaning |
|---|---|
| `download_failed` | The URL did not return the file (status, network error, a stall of 30 s, or slower than its download budget). |
| `not_image` | Not a JPEG, PNG, WebP, HEIC/HEIF, AVIF or TIFF image (read from its bytes), an empty body, or a damaged file the container walk, ExifTool or the decoder cannot read. |
| `too_large` | Over 100 MB, or a TIFF, HEIF or AVIF image over 100 megapixels across its frames. |
| `metadata_not_removable` | A field could not be removed without rewriting the image, a metadata block could not be read, the metadata is too damaged to rewrite, removing it would also remove the Content Credentials or AI label, or a damaged credential reads differently after the edit; the message names the reason. |
| `robots_disallowed` | robots.txt forbids fetching the URL. |
| `blocked_host` | The host is on the deny-list, or resolves to a private or local address. |
| `timeout` | The image did not finish within the run's time budget. |
| `internal_error` | Unexpected failure, including a rewrite that failed the Actor's own checks; message carries the class. |
| `charge_limit_reached` | The run's maximum total charge cannot pay for this image; it was not processed. |
| `invalid_input` | The run input passed the input schema but cannot be used (for example a switch that is not true or false, or no URL at all); the message names the field. One record per input given, or one with `url: null` when none was given; nothing is processed. |

The run fails only when every input failed with an Actor-side code (`internal_error`, `timeout`), so a broken Actor is visible. Every other run succeeds — including one where nothing was cleaned because of the caller's own inputs, or where those and Actor-side failures are mixed.

### Sources and terms

The source is the caller's image. Process only images you have the right to process. The Actor removes metadata; it never removes Content Credentials, AI-generation labels, watermarks or signatures, and it is not a way to pass an AI image off as a photograph. Its records never contain a metadata value — not a position, serial number, name, address or caption, and not the author or signer named inside a credential — only field names, counts, the credential's verification state, its generator software, its IPTC digital source type and the labels of its personal assertions. A kept Content Credential can name its author, and the Actor does not remove it. The cleaned image is returned to the caller in the run's own key-value store. Fetching follows the Hermes fetch policy: robots.txt is obeyed for the user-agent `HermesBot` (and `*`), and a disallowed URL is refused without a request; platforms whose terms forbid automated access, and people-search sites, are on a deny-list and refused without a request; private and local addresses are refused, after DNS and on every redirect; the user-agent is `HermesBot/1.0 (+https://apify.com/hermeskd)`; no login, cookies, credentials, CAPTCHA solving, evasion or proxies are used.

The tools are ExifTool by Phil Harvey (the Debian package, Perl Artistic Licence or GPL), c2pa-python from the Content Authenticity Initiative's C2PA project (Apache-2.0 or MIT) to read Content Credentials, and Pillow with pillow-heif (HPND; BSD-3-Clause, with libheif under LGPL) to decode images for the pixel check.

### Not affiliated

This Actor is not affiliated with ExifTool or its author, with the C2PA, the Content Authenticity Initiative or Adobe, with the Pillow project, whose public test images the examples use, with the pillow-heif project, or with IPTC. ExifTool, c2pa-python, Pillow and pillow-heif are used under their open-source licences.

### Related Hermes Actors

- [Article Extractor — Clean Text, Title & Date, $0.001 an Article](https://apify.com/hermeskd/article-extractor) — an article's clean text, title and publish date, without the rest of the page.
- [Career Site Job Search — Verified Greenhouse & Lever Boards](https://apify.com/hermeskd/ats-job-search) — search open jobs in the Hermes directory of Greenhouse and Lever boards, each confirmed live.
- [Speech to Text — Transcribe & Translate to English, SRT/VTT](https://apify.com/hermeskd/audio-to-transcript) — speech to text with SRT and VTT subtitles.
- [Video Converter & MP4 to MP3 — Trim, GIF; Audio $0.001 a Minute](https://apify.com/hermeskd/audio-video-convert) — audio and video conversion: MP4 to MP3, trim, GIF.
- [Broken Link Checker That Never Charges for the Broken Links](https://apify.com/hermeskd/broken-links) — broken links, 404s and redirects on a site.
- [Company ATS Finder — Which Hiring System & Job Board It Uses](https://apify.com/hermeskd/company-ats-board) — which hiring system and job board a company uses.
- [DNS Lookup & SPF, DKIM, DMARC Check — Findings by Severity](https://apify.com/hermeskd/dns-and-email-auth) — DNS records and SPF, DKIM and DMARC checks.
- [Word, Excel & PowerPoint to Markdown — $0.002 per Document](https://apify.com/hermeskd/document-to-markdown) — Word, Excel, PowerPoint and other office files to Markdown.
- [Domain Availability Checker — Registry RDAP, No Contact Data](https://apify.com/hermeskd/domain-availability) — whether domain names are available, from registry RDAP.
- [File Downloader — Save Files & Images from URLs, $0.001 a File](https://apify.com/hermeskd/file-downloader) — files and images from URLs, saved with a public link each.
- [Greenhouse Job Board Scraper — Open Jobs, Live, Any Company](https://apify.com/hermeskd/greenhouse-jobs) — every open job on a company's Greenhouse board.
- [Image to Text OCR — Lines & Words with Boxes, $0.002 an Image](https://apify.com/hermeskd/image-to-text) — OCR: the text in images.
- [Image Upscaler & Photo Restorer — AI 2x/4x, Agent-Payable](https://apify.com/hermeskd/image-upscale) — image upscaling 2x or 4x, and photo restoration.
- [Lever Jobs Scraper — Postings from Any Lever Site, US & EU](https://apify.com/hermeskd/lever-jobs) — every published job on a company's Lever site, global or EU.
- [Lighthouse Audit, No API Key — Lab Core Web Vitals & SEO Scores](https://apify.com/hermeskd/lighthouse-audit) — Lighthouse scores and Core Web Vitals.
- [Page Change Monitor — Detect Website Changes, $0.001 a Check](https://apify.com/hermeskd/page-change-monitor) — what changed on a page since the last check.
- [PDF to Markdown & PDF to Text — PDF Text Extractor with OCR](https://apify.com/hermeskd/pdf-to-markdown) — PDF to Markdown and text, with OCR for scanned pages.
- [Remote Jobs Scraper — Remote OK Listings, Salary Filter, Links](https://apify.com/hermeskd/remote-jobs) — current remote jobs from Remote OK, with salary and listing links.
- [RSS Feed Reader — RSS, Atom & JSON Feeds to JSON, $0.001 a Feed](https://apify.com/hermeskd/rss-feed-reader) — every item of an RSS, Atom or JSON feed.
- [SEO Audit — On-Page Checks, Schema & Hreflang, $0.004 a Page](https://apify.com/hermeskd/seo-page-audit) — an on-page SEO audit: meta tags, schema, headings and links.
- [Sitemap URL Extractor — Indexes, Gzip, RSS; $0.0003 per URL](https://apify.com/hermeskd/sitemap-urls) — the URLs in a site's sitemaps.
- [URL to Markdown for LLMs — From $0.001 a Page, Agent-Payable](https://apify.com/hermeskd/url-to-markdown) — a public job page as clean Markdown where the site allows it (deny-listed job sites are refused).
- [Video Frame Extractor — by Scene, Interval or Timestamp](https://apify.com/hermeskd/video-frames) — frames, thumbnails and scenes from a video.
- [Website Screenshot API — Elements, HTML, Dark Mode & PDF Print](https://apify.com/hermeskd/website-screenshot) — screenshots and PDF prints of web pages.
- [Website Tech Stack Lookup — Live Detection, $0.001 a Site](https://apify.com/hermeskd/website-tech-stack) — the technologies a website runs, detected live.
- [Crossref DOI Metadata — Titles, Dates & Citation Counts](https://apify.com/hermeskd/crossref-doi-metadata) — crossref doi metadata.
- [JSON Dataset Cleaner — Merge, Dedup & Export Rows](https://apify.com/hermeskd/dataset-json-cleaner) — json dataset cleaner.
- [Public HTTP GET — Response Body, Status & Hash](https://apify.com/hermeskd/http-get-response) — public http get.
- [Image Format Converter — Resize & Save WebP, PNG or JPEG](https://apify.com/hermeskd/image-format-converter) — image format converter.
- [Website Icon Finder — Favicons, Touch Icons & Theme Colors](https://apify.com/hermeskd/website-icon-manifest) — declared website icons, theme colors and manifest links.

### Changelog

- 1.0 (2026-10-27) — before release, from the QA sweep: camera photos with a Print Image Matching block cleaned; an unreadable HEIF, AVIF or TIFF metadata block refused, never passed as empty; damaged or oversize TIFF, HEIF and AVIF files reported as `not_image` and `too_large`; a TIFF's pages kept; face regions, drone positions and ImageMagick's EXIF keywords in their groups; appended images and unknown APPn segments removed; `carriesPersonalData` on kept credentials; the image checks itself at build.
- 1.0 (2026-10-27) — first release: lossless removal of location, device, people, timestamp, thumbnail, description, editing-history, rights, colour-profile and other metadata from JPEG, PNG, WebP, HEIC/HEIF, AVIF and TIFF, one switch per group; Content Credentials and AI labels always kept; a report-only mode; every file checked before it is returned.

# Actor input Schema

## `urls` (type: `array`):

Image URLs (JPEG, PNG, WebP, HEIC/HEIF, AVIF, TIFF), http or https, 1–100 per run, up to 100 MB each. Each URL becomes one record and, unless reportOnly is set, one cleaned file.

## `removeLocation` (type: `boolean`):

GPS position, altitude and direction, and place names (city, state, country, sub-location) in EXIF, XMP and IPTC. Default: true.

## `removeDevice` (type: `boolean`):

Camera and phone make, model and serial numbers, lens details and serial, owner name, unique image ID, the maker's private notes (MakerNotes), and the software and computer that wrote the file. Default: true.

## `removePeople` (type: `boolean`):

Artist, creator, author and by-line names, the creator's address, phone, email and website, people shown, and the AI prompt writer's name. Default: true.

## `removeTimestamps` (type: `boolean`):

When the photo was taken, digitized and modified, with time-zone offsets and sub-seconds, in EXIF, XMP, IPTC and PNG. Kept unless set. Default: false.

## `removeThumbnails` (type: `boolean`):

Embedded thumbnails and preview images in JPEG, PNG and WebP (EXIF, Photoshop, XMP, MPF previews) and anything appended after a JPEG's end (a motion-photo video, an appended image). A thumbnail can show the photo before it was cropped or edited. A HEIF or AVIF thumbnail item and a TIFF's reduced-resolution image are kept. Default: true.

## `removeDescriptions` (type: `boolean`):

Titles, captions, descriptions, keywords, comments (EXIF, XMP, IPTC, JPEG and PNG comments) and ratings. Default: true.

## `removeEditingHistory` (type: `boolean`):

XMP document and instance IDs, the editing history (which software did what, sometimes with file paths), Lightroom and Camera Raw settings, and Photoshop layers. Default: true.

## `removeRights` (type: `boolean`):

Copyright notices, rights, usage terms, licence and credit lines. Kept unless set: they are rights-management information. Default: false.

## `removeColorProfile` (type: `boolean`):

The embedded ICC colour profile. Kept unless set: removing it can change how colours look. Default: false.

## `removeOtherMetadata` (type: `boolean`):

Everything else not listed: exposure, flash, focus and scene settings, lens corrections, unknown tags, Photoshop print settings. Default: true.

## `reportOnly` (type: `boolean`):

List what each image carries, group by group, without changing or storing it. Charged like a cleaned image.

## Actor input object example

```json
{
  "urls": [
    "https://raw.githubusercontent.com/python-pillow/Pillow/262e8e48229197ef08792de41a6bdd94e42219a0/Tests/images/exif_gps.jpg"
  ],
  "removeLocation": true,
  "removeDevice": true,
  "removePeople": true,
  "removeTimestamps": false,
  "removeThumbnails": true,
  "removeDescriptions": true,
  "removeEditingHistory": true,
  "removeRights": false,
  "removeColorProfile": false,
  "removeOtherMetadata": true,
  "reportOnly": false
}
```

# Actor output Schema

## `results` (type: `string`):

One record per input URL with ok, the format, the groups removed and kept, the field names found per group, Content Credentials and AI-label status, the file key and its URL, or an error code.

## `files` (type: `string`):

The cleaned images in the run's key-value store, in the format they came in.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "https://raw.githubusercontent.com/python-pillow/Pillow/262e8e48229197ef08792de41a6bdd94e42219a0/Tests/images/exif_gps.jpg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("hermeskd/image-metadata-remover").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "urls": ["https://raw.githubusercontent.com/python-pillow/Pillow/262e8e48229197ef08792de41a6bdd94e42219a0/Tests/images/exif_gps.jpg"] }

# Run the Actor and wait for it to finish
run = client.actor("hermeskd/image-metadata-remover").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "https://raw.githubusercontent.com/python-pillow/Pillow/262e8e48229197ef08792de41a6bdd94e42219a0/Tests/images/exif_gps.jpg"
  ]
}' |
apify call hermeskd/image-metadata-remover --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hermeskd/image-metadata-remover"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/kbeRGTmWctgWJMS2S/builds/Uiyw35NIN2IUSp4R6/openapi.json
