Fingerprint Video
Generate perceptual hashes for duplicate detection and content matching.
/v1/fingerprint
1 credit
Description
Generate perceptual hashes from a video frame for duplicate detection and content matching. Returns three hash algorithms (average hash, perceptual hash, difference hash) as hex strings that can be compared using Hamming distance.
Request Body
Send a JSON body with the following parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| url | string | Yes | — | Source video URL |
| timestamp | string | No | 25% of duration | Frame to hash (seconds or "MM:SS") |
| hash_size | int | No | 16 | Hash size: 8, 16, or 32. Larger = more precise. |
Hash Algorithms
average_hash
Fast, simple. Resizes image, computes mean brightness, creates binary hash. Good for exact or near-exact duplicate detection.
perceptual_hash (pHash)
Gold standard for visual similarity. Uses DCT (discrete cosine transform) to capture frequency information. Robust to minor edits, resizing, and compression.
difference_hash (dHash)
Captures structural/gradient information. Compares adjacent pixel brightness. Good for detecting cropping and minor modifications.
Code Examples
curl -X POST "https://videoconduit.com/v1/fingerprint" \
-H "Authorization: Bearer vc_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"hash_size": 16
}'import requests
response = requests.post(
"https://videoconduit.com/v1/fingerprint",
headers={"Authorization": "Bearer vc_your_api_key"},
json={
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"hash_size": 16,
},
)
data = response.json()
print(data["job_id"])const response = await fetch("https://videoconduit.com/v1/fingerprint", {
method: "POST",
headers: {
"Authorization": "Bearer vc_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
hash_size: 16,
}),
});
const data = await response.json();
console.log(data.job_id);$client = new GuzzleHttp\Client();
$response = $client->post("https://videoconduit.com/v1/fingerprint", [
"headers" => ["Authorization" => "Bearer vc_your_api_key"],
"json" => [
"url" => "https://youtube.com/watch?v=dQw4w9WgXcQ",
"hash_size" => 16,
],
]);
$data = json_decode($response->getBody(), true);
echo $data["job_id"];body := strings.NewReader(`{
"url": "https://youtube.com/watch?v=dQw4w9WgXcQ",
"hash_size": 16
}`)
req, _ := http.NewRequest("POST", "https://videoconduit.com/v1/fingerprint", body)
req.Header.Set("Authorization", "Bearer vc_your_api_key")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var data map[string]interface{}
json.NewDecoder(resp.Body).Decode(&data)require "net/http"
require "json"
uri = URI("https://videoconduit.com/v1/fingerprint")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer vc_your_api_key"
req["Content-Type"] = "application/json"
req.body = {
url: "https://youtube.com/watch?v=dQw4w9WgXcQ",
hash_size: 16,
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
puts data["job_id"]Response
Completed Job (result_data)
Returned from GET /v1/jobs/{id} when the job finishes:
{
"job_id": "e5f6a7b8-c9d0-1234-efab-567890123456",
"status": "completed",
"result_data": {
"average_hash": "ff818181818181ff",
"perceptual_hash": "e4b4b4b4343434e4",
"difference_hash": "8e8e8e8e0e0e0e8e",
"hash_size": 16,
"frame_timestamp": "53",
"title": "Rick Astley - Never Gonna Give You Up"
}
}
Comparing Hashes
Compare two hashes using Hamming distance: convert hex strings to binary and count differing bits. Lower distance means more similar content.
def hamming_distance(hash1: str, hash2: str) -> int:
"""Compare two hex hash strings. Lower = more similar."""
b1 = bin(int(hash1, 16))[2:]
b2 = bin(int(hash2, 16))[2:]
return sum(c1 != c2 for c1, c2 in zip(b1.zfill(len(b2)), b2.zfill(len(b1))))
# Identical videos: distance ≈ 0
# Similar (re-encoded): distance ≈ 1-5
# Different videos: distance > 10
Try It
{# Usage: {% include "docs/_playground.html" with endpoint_method="POST" endpoint_path="/v1/download" fields=playground_fields %} playground_fields is a list of dicts passed from the view: [ {"name": "url", "type": "text", "required": True, "placeholder": "https://youtube.com/watch?v=...", "label": "Video URL"}, {"name": "quality", "type": "select", "options": ["best", "1080p", "720p", "480p", "audio"], "default": "best", "label": "Quality"}, ] #}Try It
POST /v1/fingerprint
Notes
Use pHash for Best Results
The perceptual_hash (pHash) is the most robust algorithm for detecting re-uploads, re-encodes, and minor edits. Use it as your primary comparison, with average_hash and difference_hash as secondary signals.
Hash Size Trade-off
Larger hash sizes (32) are more precise but produce longer strings. For most use cases, the default size of 16 provides a good balance between accuracy and performance.