Fraud Signals

Verifa collects over 150 fraud signals during the capture and verification process. These signals feed into the risk_assessment check, which produces a composite risk score (0–100) that can route sessions to approval, review, or rejection.

How signals are collected

Signals come from three sources:

  1. Client-side (capture flow) — Behavioral analysis, device fingerprinting, bot detection, and integrity checks collected by the capture JavaScript or mobile SDK.
  2. Server-side (network) — IP analysis, geolocation, velocity tracking, and timezone validation performed during the capture request flow.
  3. Verification engine — Document forensics, duplicate detection, and identity graph analysis performed during workflow execution.

Signal categories

Behavioral signals

Collected during the capture flow by analyzing how the user interacts with the verification UI.

SignalDescriptionRisk weight
completion_too_fastSession completed in under 15 seconds (bot speed)20
completion_too_slowSession took over 15 minutes (possible coaching)5
high_hesitationExcessive idle time (>75% of session was idle)10
high_distractionUser switched tabs/apps more than 5 times5
copy_paste_nameName field was pasted rather than typed15
mouse_bot_patternMouse moved at constant speed in straight lines25
keystroke_bot_patternKeystroke timing is unnaturally uniform25
screen_sharing_detectedRemote desktop or multi-monitor screen sharing15
autofill_then_editForm was autofilled then manually edited (using someone else’s data)10

Device signals

Client-side device fingerprinting and automation detection.

SignalDescriptionRisk weight
bot_detectedWebDriver, Phantom, or headless browser detected50
webdriver_evasion_detectedBot is attempting to hide WebDriver presence40
devtools_openBrowser developer tools are open30
virtual_cameraVirtual camera software detected (OBS, ManyCam, etc.)50
webgl_vm_detectedWebGL renderer indicates VM or emulator30
incognito_detectedPrivate/incognito browsing mode5
font_os_mismatchAvailable fonts don’t match the claimed OS15
constrained_memoryVery low heap memory (under 256 MB, suggests headless)15

Network signals

Server-side analysis of the request origin and network behavior.

SignalDescriptionRisk weight
ip_changedIP address changed mid-session25
high_ip_velocityMore than 20 sessions from the same IP in 24 hours30
ua_changedUser-agent string changed mid-session20
timing_too_uniformRequest intervals are unnaturally consistent15
timing_too_fastRequests arrive faster than human interaction20
timezone_mismatchBrowser timezone doesn’t match IP geolocation15
device_reuse_highSame device fingerprint used in 5+ sessions in 30 days20
vpn_detectedVPN service detected via GeoIP25
proxy_detectedProxy server detected30
tor_detectedTor exit node detected35
datacenter_ipIP belongs to a hosting/datacenter provider20
ip_country_mismatchIP country doesn’t match document country20
impossible_travel_detectedSession IP locations are physically impossible given time elapsed35

Document forensics signals

Analysis of uploaded ID document images for tampering and quality issues.

SignalDescriptionRisk weight
front_exif_editedEXIF metadata shows image editing software (Photoshop, GIMP)25
front_exif_stripped_jpegEXIF metadata was stripped from a JPEG (attempt to hide editing)10
front_exif_very_oldImage metadata indicates it was taken more than a year ago10
front_blurry_documentDocument image is too blurry for reliable OCR15
front_glare_detectedSignificant glare detected on the document10
front_screen_photoDocument appears to be photographed from a screen (moire patterns)30
front_image_low_resolutionImage resolution is below 480px minimum15
barcode_data_mismatchBarcode data doesn’t match OCR-extracted text35
barcode_missing_expectedExpected barcode not found on document type that should have one15
mrz_checksum_invalidMRZ checksum validation failed (tampered document)35
mrz_data_mismatchMRZ data doesn’t match OCR-extracted text30
extraction_front_back_mismatchFront and back of document contain inconsistent data30
pdf_editor_detectedPDF was created or modified with editing software25
pdf_abnormal_fontsPDF contains an unusual number of fonts15
pdf_has_annotationsPDF contains overlay annotations20

Identity graph signals

Cross-session duplicate detection via hashed identity links.

SignalDescriptionRisk weight
duplicate_device_detectedSame device fingerprint seen in a previous session20
duplicate_email_detectedSame email used in a previous session15
duplicate_phone_detectedSame phone number used in a previous session15
duplicate_document_detectedSame document number in a previous session40
duplicate_face_detectedSame face matched via embedding similarity35
duplicate_name_detectedSame name + DOB combination in a previous session15
duplicate_ip_detectedSame IP address in a recent session10

Integrity signals

Validates that the client-side signal payload hasn’t been tampered with.

SignalDescriptionRisk weight
integrity_checksum_mismatchSignal payload HMAC doesn’t match (tampered)40
integrity_checksum_missingNo checksum provided (bypassed collection)20
integrity_too_few_keysSignal payload has fewer keys than expected15
integrity_has_range_violationsSignal values outside valid ranges15
integrity_has_contradictionsSignal values contradict each other20

Biometric signals

AI-generated face detection.

SignalDescriptionRisk weight
deepfake_detectedAI-generated or manipulated face detected45

Mobile-specific signals

Collected by the mobile SDK (not available in web capture).

SignalDescriptionRisk weight
rooted_or_jailbrokenDevice is rooted (Android) or jailbroken (iOS)30
emulator_detectedRunning on a virtual device35
debugger_attachedDebugger is connected to the process25
screen_recordingActive screen recording detected20
camera_injection_detectedVirtual camera app injecting fake video50
device_attestation_failedPlatform device integrity check failed35
zero_pressure_suspiciousTouch events have zero pressure (synthetic)15
gyro_too_stableGyroscope data is unnaturally stable (no hand movement)15
install_source_sideloadedApp was sideloaded, not from official store10

Risk scoring

All triggered signals are aggregated into a composite risk score by the risk_assessment check.

Risk levels

LevelScore rangeRecommendation
Low0–20Auto-approve eligible
Medium21–50Proceed with caution
High51–80Step-up verification or manual review recommended
Critical81–100Auto-reject or hard block recommended

Hard blocks

Certain signals trigger an automatic hard block regardless of the composite score:

  • bot_detected (when configured as block)
  • virtual_camera (when configured as block)
  • camera_injection_detected (when configured as block)
  • integrity_checksum_mismatch (when configured as block)

Per-signal actions

Each signal can be configured with one of three actions:

ActionBehavior
blockCounts in score + eligible for hard block
flag (default)Counts in score
ignoreExcluded from score entirely

Configure signal actions per organization to tune risk sensitivity.

Viewing signals for a session

$curl https://api.withverifa.com/api/v1/sessions/session_abc123/risk \
> -H "X-API-Key: vk_live_your_key_here"
1{
2 "risk_score": 35,
3 "risk_level": "medium",
4 "triggered_signals": [
5 { "signal": "vpn_detected", "weight": 25, "action": "flag" },
6 { "signal": "high_distraction", "weight": 5, "action": "flag" },
7 { "signal": "front_exif_stripped_jpeg", "weight": 10, "action": "flag" }
8 ],
9 "triggered_count": 3,
10 "hard_blocked": false
11}

Using risk scores in workflows

The risk_assessment check is auto-injected into every workflow. You can use conditional nodes to route based on the risk level:

1{
2 "risk_gate": {
3 "type": "conditional",
4 "routes": [
5 {
6 "conditions": [
7 { "field": "risk_assessment.risk_level", "op": "==", "value": "critical" }
8 ],
9 "target": "reject_terminal"
10 },
11 {
12 "conditions": [
13 { "field": "risk_assessment.risk_level", "op": "==", "value": "high" }
14 ],
15 "target": "review_terminal"
16 },
17 {
18 "conditions": [],
19 "target": "approve_terminal"
20 }
21 ]
22 }
23}