# Image Similarity API | Compare Images, Find Duplicates (`johnvc/image-similarity-api`) Actor

Compare images by visual similarity with a CLIP vision model plus perceptual hashing. Score a source image against up to 500 targets, catch exact and near-duplicates, and get one clean row per comparison. URLs, base64, or file upload. Pay per result, MCP ready for AI agents.

- **URL**: https://apify.com/johnvc/image-similarity-api.md
- **Developed by:** [John](https://apify.com/johnvc) (community)
- **Categories:** AI, Developer tools, MCP servers
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.40 / 1,000 comparison results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 🖼️ Image Similarity API | Compare Images and Find Duplicate Photos

Compare images by visual similarity and catch duplicates in one run. The Image Similarity API scores a source image against up to 500 target images using a CLIP vision transformer for semantic similarity plus 64-bit perceptual hashes (pHash and dHash) for exact and near-duplicate detection. Every source-target pair returns one clean dataset row with a cosine similarity score, hash distances, and a plain-English verdict: duplicate, very-similar, related, or different.

Most image comparison tools give you one number and leave you guessing. A cosine score of 0.94 can be the same photo resized, or two different golden retrievers. This API answers both questions at once: the vision model measures what the images mean, and the perceptual hashes prove whether they are the same picture. Deduplicate product catalogs, monitor brand assets, detect re-uploads, and match supplier photos to your catalog, by URL, base64, or file upload.

### 📋 What this API returns

- One row per comparison: `similarityScore` (0 to 1 cosine similarity from the vision model), `phashDistance` and `dhashDistance` (0 to 64 Hamming distances), and boolean flags `isSimilar` and `isNearDuplicate`
- A fixed-band `verdict` for every pair: `duplicate`, `very-similar`, `related`, or `different`, so downstream automations can branch without tuning thresholds
- Echoes of your `sourceImageId` and per-target `customId`, so results join back to your catalog or database rows
- Free error rows for targets that fail to download or decode, with clear messages and no charge

### 🎯 Use cases

- **Duplicate photo detection**: find exact and near-duplicate images across product catalogs, photo libraries, and user uploads, including resized, recompressed, and lightly edited copies
- **E-commerce product matching**: match supplier or marketplace photos against your catalog to catch relistings and duplicate offers
- **Brand and content monitoring**: check whether scraped or reported images are copies of your assets
- **Content moderation**: detect re-uploads of previously removed images even after resizing or format changes
- **Visual QA and regression checks**: compare rendered screenshots or generated images against approved references
- **AI agent workflows**: give an agent a reliable "are these two images the same or similar" tool over MCP

### ⚙️ Input parameters

| Parameter | Type | Required | Description |
|---|---|---|---|
| `sourceImage` | string | yes\* | Reference image: public http(s) URL, `data:image/...;base64,` URI, or raw base64 |
| `sourceImageUpload` | array | yes\* | Upload the reference image from your computer instead (takes priority) |
| `targetImages` | array | yes | Up to 500 entries: URLs, base64 / data URIs, or objects `{url, customId, headers}` |
| `comparisonMode` | string | no | `both` (default), `embedding` (semantic only), or `phash` (duplicate detection only, fastest) |
| `threshold` | number | no | Cosine similarity cutoff for `isSimilar`, default 0.85 |
| `phashThreshold` | integer | no | Max Hamming distance for `isNearDuplicate`, default 8 |
| `sourceImageId` | string | no | Your identifier for the source, echoed on every row |
| `customId` | string | no | Run-level identifier echoed on every row; per-target `customId` wins |
| `headers` | object | no | Extra HTTP headers for downloads (for example a Referer for protected images) |
| `proxyConfiguration` | object | no | Route downloads through Apify Proxy when image hosts block datacenter traffic |

\*Provide the source through exactly one door: `sourceImageUpload` beats `sourceImage` when both are set.

### 📦 Example output

```json
{
  "resultType": "comparison",
  "targetIndex": 0,
  "sourceImage": "https://example.com/products/master-photo.jpg",
  "sourceImageId": "catalog-master-001",
  "targetImage": "https://example.com/supplier/photo-web.jpg",
  "customId": "sku-8841",
  "similarityScore": 0.9484,
  "isSimilar": true,
  "phashDistance": 2,
  "dhashDistance": 0,
  "isNearDuplicate": true,
  "verdict": "duplicate",
  "comparisonMode": "both",
  "embeddingModel": "clip-vit-b-32",
  "processedAt": "2026-08-09T14:03:22.117000+00:00"
}
```

A target that could not be fetched produces a free error row instead:

```json
{
  "resultType": "error",
  "targetIndex": 3,
  "targetImage": "https://example.com/missing.jpg",
  "errorMessage": "image download returned HTTP 404",
  "processedAt": "2026-08-09T14:03:24.902000+00:00"
}
```

#### How to read the scores

| Signal | Range | Meaning |
|---|---|---|
| `similarityScore` 0.95+ | semantic | Near-identical content |
| `similarityScore` 0.85 to 0.95 | semantic | Very similar scenes or subjects |
| `similarityScore` 0.75 to 0.85 | semantic | Related category, visually distinct |
| `phashDistance` 0 to 8 | structural | Same picture: resized, recompressed, or lightly edited |
| `phashDistance` 9+ | structural | Not the same picture, whatever the semantic score says |

The two signals together are the point: two photos of different cats score high semantically but far apart on hashes (similar, not duplicates), while a thumbnail of your photo scores close on hashes even after heavy compression (a true duplicate).

### 💰 Pricing (pay-per-event)

| Event | What it covers |
|---|---|
| Comparison result | One scored source-target pair: similarity score, hash distances, and verdict |

You pay per comparison actually delivered. Targets that fail to download or decode return error rows for free, and the source image is never billed. A run comparing one source against 100 targets bills exactly 100 events. Current rates are shown on this page's pricing tab; this is one of the lowest-priced image comparison tools on Apify.

### 🚀 How to get started

1. Open the Actor and press **Try for free**: [View on Apify Store](https://apify.com/johnvc/image-similarity-api?fpr=9n7kx3)
2. Paste a source image URL and a few target URLs (the prefilled example compares a cat photo against a resized copy, a different cat, and a dog)
3. Press **Start** and read the results table: one row per target with score, distances, and verdict
4. Call it from code or schedules via the [Apify API](https://docs.apify.com/api/v2), or drop it into your stack with the integrations below

### 🔌 Use this API from Claude (MCP)

Connect this Actor to [Claude Code](https://claude.ai/referral/uIlpa7nPLg) (free trial), Claude Desktop, or any MCP client through the hosted Apify MCP server:

```
https://mcp.apify.com/?tools=actors,docs,johnvc/image-similarity-api
```

Your agent can then call the `image-similarity-api` tool with a source and targets and get scored rows back, for deduplication steps, catalog matching, or visual QA inside agent workflows. Setup walkthrough:

https://www.youtube.com/watch?v=jREWahDGhJM

Full MCP documentation: https://docs.apify.com/platform/integrations/mcp

### 🔁 Use this API from n8n

Available as an n8n community node, **[n8n-nodes-image-similarity-api](https://www.npmjs.com/package/n8n-nodes-image-similarity-api)**. In n8n: Settings, Community Nodes, install `n8n-nodes-image-similarity-api`, then use it in any workflow (it also works as an AI Agent tool). The node exposes source and target images, comparison mode, both thresholds, and Simplified, Raw, or Selected Fields output, one clean item per comparison.

### 💸 Pay per run with crypto (x402)

The Image Similarity API supports agentic payments via the [x402 protocol](https://docs.apify.com/platform/integrations/x402).
AI agents and MCP clients can pay for runs in USDC (on Base) with no Apify account or API token needed:
point your agent at the [Apify MCP server](https://mcp.apify.com/?tools=actors,docs,johnvc/image-similarity-api) and it can
discover, pay for, and run this Actor autonomously. Read the
[Apify x402 announcement](https://apify.com/change-log/pay-for-apify-actors-with-x402?fpr=9n7kx3) for details.

### ❓ FAQ

#### How is this different from a reverse image search?

A reverse image search finds where an image appears on the web. This API compares images you already have: your source against your targets, returning similarity scores and duplicate verdicts. For web-wide reverse image search, pair it with the [Google Lens API](https://apify.com/johnvc/google-lens-api?fpr=9n7kx3).

#### What is the difference between similarityScore and phashDistance?

`similarityScore` comes from a vision model and measures semantic similarity: what the images depict. `phashDistance` measures structural identity: whether they are the same picture. Two photos of different beaches score high semantically but far apart on hashes; your photo recompressed to half size scores 0 to 8 on hashes even when the semantic score dips.

#### Can it find duplicates without running the AI model?

Yes. Set `comparisonMode` to `phash` and the run skips the vision model entirely, computing only perceptual hashes. That is the fastest and cheapest way to sweep a catalog for exact and near-exact copies.

#### What image formats are supported?

JPEG, PNG, WebP, GIF, BMP, and TIFF. Animated GIFs contribute their first frame. Images are validated by content, not by file extension, and anything up to 20 MB and 50 megapixels per image is accepted.

#### How many images can I compare in one run?

Up to 500 targets per run against one source. For bigger jobs, split the target list across runs; results carry your `customId` values so you can merge them downstream.

#### Can I compare images that are not publicly hosted?

Yes, three ways: upload the source straight from your computer, send base64 / data URIs from code (the platform caps run input at 9 MB, which fits about 6 MB of image data), or pass `headers` such as an Authorization or Referer header for images behind access rules.

#### Do failed downloads cost anything?

No. A target that cannot be downloaded or decoded produces an error row with a clear message and is never charged. You pay only for delivered comparisons.

#### Why do two different photos of the same product score above 0.9?

The vision model measures semantic similarity, and two studio shots of the same product are semantically near-identical. Check `isNearDuplicate` when the question is "is this literally my image": the hash flags catch copies, not lookalikes.

#### Can AI agents use this Actor?

Yes. It is MCP-ready through the hosted Apify MCP server, and agents without an Apify account can pay per run in USDC via the x402 protocol. The input schema is written so agent frameworks and [Claude Code](https://claude.ai/referral/uIlpa7nPLg) (free trial) can call it without human help.

#### How fast is it?

The vision model is baked into the Actor image, so there is no model download at run time. Typical runs compare a few dozen targets in well under a minute, dominated by image download time; duplicate-detection-only mode is faster still.

### 🌐 About Alpha OSINT

This Actor is part of [Alpha OSINT](https://www.alphaosint.com), toolset of financial and operations data sources and APIs.
For support or requests for this actor, please start a ticket [directly on our support page](https://apify.com/johnvc/image-similarity-api/issues/open?fpr=9n7kx3).

### ⭐ Featured Tasks

Ready-to-run examples that show this API solving a specific problem. Each opens its own setup so you can
run it on your account in one click.

- [Compare Images via API, Similarity Scores as JSON](https://apify.com/johnvc/image-similarity-api/examples/compare-images-api-similarity-scores?fpr=9n7kx3) - score a source image against up to 500 targets in one call; similarityScore, phashDistance, and a verdict per pair.
- [Compare Two Images for Similarity, Percentage Verdict](https://apify.com/johnvc/image-similarity-api/examples/compare-two-images-for-similarity?fpr=9n7kx3) - paste two image URLs, base64, or files and get a similarity percentage with a duplicate verdict.
- [Check Image Copyright: Match Copies of Your Photo](https://apify.com/johnvc/image-similarity-api/examples/image-copyright-copy-checker?fpr=9n7kx3) - verify whether suspect URLs reuse your original photo, with per-pair scores and verdicts.
- [Find Duplicate Images Online Across a List of URLs](https://apify.com/johnvc/image-similarity-api/examples/find-duplicate-images-online?fpr=9n7kx3) - flag exact and near duplicates across up to 500 image URLs by perceptual hash; failed downloads are free.
- [Bulk Image Hash Check with pHash and dHash](https://apify.com/johnvc/image-similarity-api/examples/bulk-image-hash-check-phash?fpr=9n7kx3) - the fastest mode: hash distances and isNearDuplicate per row, no model load, ideal for dedup pipelines.
- [Compare Screenshots to a Baseline, Flag Changes](https://apify.com/johnvc/image-similarity-api/examples/compare-screenshots-to-a-baseline?fpr=9n7kx3) - check UI screenshots against a baseline build and see which ones drifted, with a score and verdict per build.
- [在线比较两张图片的相似度，输出相似度分数和重复判定](https://apify.com/johnvc/image-similarity-api/examples/bijiao-liangzhang-tupian-xiangsidu?fpr=9n7kx3) - 提交两张图片，立即得到相似度分数、感知哈希距离和重复判定。
- [批量查找重复图片，用感知哈希检测近似重复](https://apify.com/johnvc/image-similarity-api/examples/piliang-chazhao-chongfu-tupian?fpr=9n7kx3) - 把最多 500 个图片链接与原图批量对比，标记完全重复和近似重复。
- [图片对比 API：批量比较图片相似度并返回 JSON](https://apify.com/johnvc/image-similarity-api/examples/tupian-duibi-api?fpr=9n7kx3) - 一次调用返回每对图片的相似度分数、哈希距离和你自己的 ID 字段，便于直接写入系统。

Last Updated: 2026.08.16

# Actor input Schema

## `sourceImage` (type: `string`):

Provide the reference image every target is compared against: a public http(s) URL, a data:image/...;base64 URI, or raw base64 bytes. For files on your computer, use Upload source image instead.

## `sourceImageUpload` (type: `array`):

Click Upload new files and pick the reference image from your computer, or paste a link to a file already stored on Apify. When set, this takes priority over Source image.

## `targetImages` (type: `array`):

List the images to compare against the source, up to 500 per run. Each entry is an http(s) URL, a data:image base64 URI, or an object like {"url": "https://...", "customId": "sku-1", "headers": {"Referer": "https://..."}} for per-image tracking ids and request headers.

## `comparisonMode` (type: `string`):

Choose what to compute per pair. 'Semantic + duplicate detection' runs the vision model and perceptual hashes and is right for most runs. 'Semantic only' scores conceptual similarity without duplicate checks. 'Duplicate detection only' skips the model entirely, which is the fastest and cheapest way to find exact or near-exact copies.

## `threshold` (type: `number`):

Set the cosine similarity cutoff, 0 to 1, above which a pair is flagged isSimilar. 0.85 works well for most content; raise it toward 0.95 to keep only near-identical scenes, lower it toward 0.75 to catch loosely related images.

## `phashThreshold` (type: `integer`):

Set the maximum perceptual hash Hamming distance, 0 to 64, at which a target counts as a near-duplicate of the source. 8 catches resized, recompressed, and lightly edited copies; 0 requires a pixel-structure-identical image; 12 tolerates heavier edits like small watermarks.

## `sourceImageId` (type: `string`):

Attach your own identifier for the source image; it is echoed on every result row so downstream systems can join results back to your records.

## `customId` (type: `string`):

Attach a run-level identifier echoed on every result row. Per-target customId values inside targetImages objects override this for their row.

## `headers` (type: `object`):

Send extra HTTP headers with every image download, for example a Referer or an Authorization header for protected images. Per-target headers inside targetImages objects are merged on top for their request.

## `proxyConfiguration` (type: `object`):

Route image downloads through Apify Proxy or your own proxies. Leave off for most runs; turn on when image hosts block datacenter traffic.

## Actor input object example

```json
{
  "sourceImage": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/960px-Cat03.jpg",
  "targetImages": [
    "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/250px-Cat03.jpg",
    "https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/Siam_lilacpoint.jpg/960px-Siam_lilacpoint.jpg",
    "https://upload.wikimedia.org/wikipedia/commons/thumb/9/90/Labrador_Retriever_portrait.jpg/960px-Labrador_Retriever_portrait.jpg"
  ],
  "comparisonMode": "both",
  "threshold": 0.85,
  "phashThreshold": 8
}
```

# Actor output Schema

## `allResults` (type: `string`):

Every comparison and error row from this run.

## `overview` (type: `string`):

Targets with thumbnails, similarity scores, duplicate distances, and verdicts in a scannable table.

# 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 = {
    "sourceImage": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/960px-Cat03.jpg",
    "targetImages": [
        "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/250px-Cat03.jpg",
        "https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/Siam_lilacpoint.jpg/960px-Siam_lilacpoint.jpg",
        "https://upload.wikimedia.org/wikipedia/commons/thumb/9/90/Labrador_Retriever_portrait.jpg/960px-Labrador_Retriever_portrait.jpg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("johnvc/image-similarity-api").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 = {
    "sourceImage": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/960px-Cat03.jpg",
    "targetImages": [
        "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/250px-Cat03.jpg",
        "https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/Siam_lilacpoint.jpg/960px-Siam_lilacpoint.jpg",
        "https://upload.wikimedia.org/wikipedia/commons/thumb/9/90/Labrador_Retriever_portrait.jpg/960px-Labrador_Retriever_portrait.jpg",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("johnvc/image-similarity-api").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 '{
  "sourceImage": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/960px-Cat03.jpg",
  "targetImages": [
    "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/250px-Cat03.jpg",
    "https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/Siam_lilacpoint.jpg/960px-Siam_lilacpoint.jpg",
    "https://upload.wikimedia.org/wikipedia/commons/thumb/9/90/Labrador_Retriever_portrait.jpg/960px-Labrador_Retriever_portrait.jpg"
  ]
}' |
apify call johnvc/image-similarity-api --silent --output-dataset

```

## MCP server setup

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

```

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/ajnnira9n6X6qo9Dw/builds/GBaBXxzDhKTNnLd1S/openapi.json
