Guides
Detecting duplicate accounts by face (without wrongful bans)
Catch the fraud ring, not your legitimate user with a twin. A careful design for face-based dedup.
TL;DR
To catch duplicate accounts by face: enrol each new user's face into a single collection at signup (with consent), search the collection for near-matches, and route hits to a review queue rather than an automatic ban. A single similarity score is not proof of fraud — twins, family members, and poor-quality photos all produce high scores. Calibrate the threshold on your own data, keep a human in the loop for consequential decisions, and give users an appeals path. This guide builds that pipeline.
Note: Never auto-ban an account on one face-match score. Identical twins, close relatives, and re-used stock photos all create legitimate high-similarity collisions. A wrong ban on biometric evidence is both a terrible user experience and a legal risk. Face match is a signal that feeds review, not a verdict.
The pipeline
- Enrol at signup — with the user's consent, index their face into a single dedup collection and store the returned face id against their account.
- Search before you trust — search the collection with the new face; any near-match is a *candidate* duplicate, not a confirmed one.
- Score and bucket — high-confidence matches go to a fast-track review; borderline ones to a lower-priority queue; no match clears immediately.
- Human review for consequences — a reviewer looks at the flagged pair before any account action, with context (signup metadata, device, payment).
- Appeal path — a user told they're a duplicate can contest it, and a human can clear a false match.
Enrol and search
DEDUP = "fraud__dedup" # one collection, server-owned name
def on_signup(user_id, selfie_url):
record_consent(user_id, purpose="duplicate_detection")
# Search FIRST — does this face already exist?
r = requests.post(f"{BASE}/v1/collections/{DEDUP}/search",
headers=H, json={"url": selfie_url, "limit": 5})
r.raise_for_status()
matches = [m for m in r.json().get("matches", []) if m["score"] >= REVIEW_MIN]
# Then enrol this user's face so future signups are checked against it.
requests.post(f"{BASE}/v1/collections/{DEDUP}/index", headers=H,
json={"url": selfie_url, "photoId": user_id}).raise_for_status()
if matches:
queue_for_review(user_id, matches) # never auto-act here
return matches
REVIEW_MIN = 0.80 # native 0-1 score; calibrate on YOUR dataTip: SightRadar's native score is on a 0-1 scale (AWS Rekognition's is 0-100). Pick REVIEW_MIN and any auto-confirm bar from a labelled validation set of real duplicate and non-duplicate pairs — see the threshold guide. Don't copy a number.
Why review beats auto-action
| High score can mean… | Right response |
|---|---|
| A real duplicate / fraud ring | Confirm in review, then act per policy |
| Identical twin or sibling | Human clears it; not a duplicate |
| Re-used stock or celebrity photo | Flag the photo, not the person |
| Same person, legitimate second account | Depends on your ToS — review decides |
Consent, retention, and deletion
Enrolling a face for dedup is biometric processing — you need a lawful basis and should disclose it at signup. Keep the dedup collection scoped to that purpose, don't reuse it for anything else, and delete a user's face when they close their account or you no longer need it. Store the review decisions and audit trail; you don't need to keep the raw selfie once the face is indexed.
See the search and index operations you'd build this on.
Read the API referenceFrequently asked questions
Can I use face recognition to detect duplicate or fake accounts?
Yes — enrol each new user's face into a single dedup collection at signup (with consent) and search that collection before trusting a new account. Any near-match is a candidate duplicate. Route candidates to human review rather than auto-banning: identical twins, relatives, and reused photos all produce legitimate high scores, so a single similarity score is a signal, not proof.
Should I automatically ban an account that matches an existing face?
No. A wrongful ban based on one biometric score is both a bad user experience and a legal risk, because twins, family members, and duplicate stock photos create legitimate high-similarity collisions. Use the match to open a review with context, keep a human in the loop for any consequential action, and give users an appeals path to contest a false match.
What threshold should I use for duplicate detection?
There's no universal number, and SightRadar's native score is on a 0-1 scale (not Rekognition's 0-100). Build a validation set of known duplicate and non-duplicate pairs from your own data, measure false-match and false-non-match rates across thresholds, and pick an operating point that routes borderline cases to review rather than auto-acting.