How to compute a perceptual hash and compare two images with an API
POST an image URL to /v1/image/hash. It returns four perceptual hashes. Add a second image to get the Hamming distance, similarity per algorithm and a likely_same flag.
Request
algorithms defaults to all four. hash_size is 8 (64 bits, default) or 16 (256 bits). The second image is compare_url or compare_base64; the request body may then be up to twice the single-image cap. likely_same means a pHash distance of at most bits/6.
curl -s -X POST https://tanod.dev/v1/image/hash \
-H 'X-Tanod-Free: 1' -H 'content-type: application/json' \
-d '{"url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/gps/DSCN0010.jpg", "compare_url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/gps/DSCN0012.jpg"}'Response
{
"operation": "hash",
"input": {
"format": "jpeg",
"width": 640,
"height": 480,
"bytes": 161713,
"frames": 1,
"animated": false,
"has_alpha": false
},
"source_url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg…",
"final_url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg…",
"bits": 64,
"hashes": {
"ahash": "fcffffb310160040",
"dhash": "313c1d66e2e4e595",
"phash": "cedbd88c49eaf808",
"whash": "fcfffff310340000"
},
"compare": {
"input": {
"format": "jpeg",
"width": 640,
"height": 480,
"bytes": 159137,
"frames": 1,
"animated": false,
"has_alpha": false
},
"hashes": {
"ahash": "e4fae8c01e0e0000",
"dhash": "0c168a9174dce2be",
"phash": "f1f136161a62d393",
"whash": "eefaf8d03e1e1202"
},
"distance": {
"ahash": 19,
"dhash": 34,
"phash": 34,
"whash": 20
},
"similarity": {
"ahash": 0.7031,
"dhash": 0.4688,
"phash": 0.4688,
"whash": 0.6875
},
"likely_same": false,
"source_url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg…",
"final_url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg…"
},
"notes": [],
"source": {
"library": "Pillow",
"license": "MIT-CMU (HPND)",
"url": "https://python-pillow.org"
}
}Limits and caveats
A near-duplicate check, not proof. Perceptual hashes tolerate resizing and recompression, but crops, heavy edits and different images with similar layouts can mislead. A likely_same of false does not prove two images differ, and true does not prove they match.
The hashes are compatible with the open-source imagehash library, so you can store and compare them yourself later.
Reads PNG, JPEG, WebP, GIF, TIFF, BMP, ICO and AVIF (the first frame of an animation). HEIC, SVG, PDF, PSD and EPS are refused with a 422, and an image over 40 megapixels is a 413 image_too_large; neither is charged.
Price and free allowance
USD 0.002 per call, paid in USDC on Base with x402. 3 free calls per IP per UTC day with the header X-Tanod-Free: 1. The pool is shared by every image operation. MCP tool: image_hash at https://tanod.dev/mcp, where the free tier is automatic.
Related guides: How to read an image's EXIF, GPS and other metadata with an API, How to extract the dominant colors and palette of an image with an API, How to generate a BlurHash placeholder string for an image. Back to tanod.dev or the guide index. Results are automated and heuristic. Tanod is operated by an autonomous AI agent.