spoof-detection-package
v0.1.2
Published
On-device face anti-spoofing (printed photo / poster / phone screen detection) for Expo and React Native. Takes a photo uri, returns a spoof verdict.
Maintainers
Readme
spoof-detection-package
On-device face anti-spoofing for Expo and React Native. Give it a photo uri, it tells you whether the face is real or a presentation attack — printed photo, passport photo, poster, or a phone/tablet/laptop screen.
Everything runs natively on-device (ML Kit / Apple Vision for face detection, MiniFASNetV2 for texture analysis — converted from the official Silent-Face-Anti-Spoofing weights and bundled in the package, ~1.9 MB). No network calls, no photo ever leaves the device, no JS dependencies.
Install
npx expo install spoof-detection-package
# bare React Native: also needs expo-modules-core set up (npx install-expo-modules)Native module — needs a dev build / prebuild, does not work in Expo Go.
Plays nice with other TFLite packages
Safe to install alongside react-native-fast-tflite (or alone):
- Android uses Google's LiteRT artifact (
com.google.ai.edge.litert:litert), the same family fast-tflite v3 uses — Gradle dedupes to a single copy, no duplicate-class or duplicate-.so errors. - iOS declares
TensorFlowLiteSwift >= 2.14, < 3.0as a range, so CocoaPods can settle on whatever exact TensorFlowLiteC version other pods pin (e.g. fast-tflite 3.x pins 2.17.0) instead of conflicting.
Usage
import { detectSpoof, isSpoof } from 'spoof-detection-package';
const result = await detectSpoof(photo.uri);
// {
// live: true, // safe to proceed
// spoof: false, // presentation attack detected
// realScore: 0.94, // P(real face) from the model, 0-1
// reason: null, // 'no_face' | 'multiple_faces' | 'face_too_small' | 'texture' | null
// }
if (result.spoof) {
// show "Spoof detected" popup
} else if (!result.live) {
// quality problem: result.reason === 'no_face' or 'face_too_small'
} else {
// real face — continue with recognition / attendance
}
// or the one-liner:
if (await isSpoof(photo.uri)) return blockScan();Options
await detectSpoof(uri, {
threshold: 0.7, // min P(real) to accept; raise = stricter
minFaceRatio: 0.18, // face must be >= 18% of the photo's short side
cropScale: 2.7, // context crop around the face (model default)
});How it decides
- Face detection (ML Kit on Android, Apple Vision on iOS)
- no face ->
{ live: false, spoof: false, reason: 'no_face' } - 2+ faces ->
{ spoof: true, reason: 'multiple_faces' } - tiny face ->
{ live: false, reason: 'face_too_small' }(ask the user to come closer — also blocks passport photos held at a distance)
- no face ->
- MiniFASNetV2 texture analysis on a wide 2.7x crop (sees paper edges,
screen bezels, glare, moiré) ->
realScore; belowthreshold->{ spoof: true, reason: 'texture' }
Tips
- Combine with an object detector (COCO-SSD "cell phone"/"tv"/"laptop") and a motion check across preview frames for defense in depth.
- Tune
thresholdwith real data: logrealScorefor genuine users and known fakes, pick the value that separates them.
