> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.withverifa.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.withverifa.com/_mcp/server.

# Fraud Signals

> The 150+ fraud signals collected during verification and how risk scoring works.

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.

| Signal                    | Description                                                          | Risk weight |
| ------------------------- | -------------------------------------------------------------------- | ----------- |
| `completion_too_fast`     | Session completed in under 15 seconds (bot speed)                    | 20          |
| `completion_too_slow`     | Session took over 15 minutes (possible coaching)                     | 5           |
| `high_hesitation`         | Excessive idle time (>75% of session was idle)                       | 10          |
| `high_distraction`        | User switched tabs/apps more than 5 times                            | 5           |
| `copy_paste_name`         | Name field was pasted rather than typed                              | 15          |
| `mouse_bot_pattern`       | Mouse moved at constant speed in straight lines                      | 25          |
| `keystroke_bot_pattern`   | Keystroke timing is unnaturally uniform                              | 25          |
| `screen_sharing_detected` | Remote desktop or multi-monitor screen sharing                       | 15          |
| `autofill_then_edit`      | Form was autofilled then manually edited (using someone else's data) | 10          |

### Device signals

Client-side device fingerprinting and automation detection.

| Signal                       | Description                                            | Risk weight |
| ---------------------------- | ------------------------------------------------------ | ----------- |
| `bot_detected`               | WebDriver, Phantom, or headless browser detected       | 50          |
| `webdriver_evasion_detected` | Bot is attempting to hide WebDriver presence           | 40          |
| `devtools_open`              | Browser developer tools are open                       | 30          |
| `virtual_camera`             | Virtual camera software detected (OBS, ManyCam, etc.)  | 50          |
| `webgl_vm_detected`          | WebGL renderer indicates VM or emulator                | 30          |
| `incognito_detected`         | Private/incognito browsing mode                        | 5           |
| `font_os_mismatch`           | Available fonts don't match the claimed OS             | 15          |
| `constrained_memory`         | Very low heap memory (under 256 MB, suggests headless) | 15          |

### Network signals

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

| Signal                       | Description                                                                                             | Risk weight |
| ---------------------------- | ------------------------------------------------------------------------------------------------------- | ----------- |
| `ip_changed`                 | IP address changed mid-session                                                                          | 25          |
| `high_ip_velocity`           | More than 20 sessions from the same IP in 24 hours                                                      | 30          |
| `ua_changed`                 | User-agent string changed mid-session                                                                   | 20          |
| `timing_too_fast`            | A capture-step transition (e.g. country → upload) happened faster than a human can plausibly perform it | 20          |
| `timing_too_mechanical`      | A repeated user action (e.g. OTP retries) had suspiciously low variance, suggesting scripted pacing     | 20          |
| `timezone_mismatch`          | Browser timezone doesn't match IP geolocation                                                           | 15          |
| `device_reuse_high`          | Same device fingerprint used in 5+ sessions in 30 days                                                  | 20          |
| `vpn_detected`               | VPN service detected via GeoIP                                                                          | 25          |
| `proxy_detected`             | Proxy server detected                                                                                   | 30          |
| `tor_detected`               | Tor exit node detected                                                                                  | 35          |
| `datacenter_ip`              | IP belongs to a hosting/datacenter provider                                                             | 20          |
| `ip_country_mismatch`        | IP country doesn't match document country                                                               | 20          |
| `impossible_travel_detected` | Session IP locations are physically impossible given time elapsed                                       | 35          |

### Document forensics signals

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

| Signal                           | Description                                                        | Risk weight |
| -------------------------------- | ------------------------------------------------------------------ | ----------- |
| `front_exif_edited`              | EXIF metadata shows image editing software (Photoshop, GIMP)       | 25          |
| `front_exif_stripped_jpeg`       | EXIF metadata was stripped from a JPEG (attempt to hide editing)   | 10          |
| `front_exif_very_old`            | Image metadata indicates it was taken more than a year ago         | 10          |
| `front_blurry_document`          | Document image is too blurry for reliable OCR                      | 15          |
| `front_glare_detected`           | Significant glare detected on the document                         | 10          |
| `front_screen_photo`             | Document appears to be photographed from a screen (moire patterns) | 30          |
| `front_image_low_resolution`     | Image resolution is below 480px minimum                            | 15          |
| `barcode_missing_expected`       | Expected barcode not found on document type that should have one   | 15          |
| `mrz_checksum_invalid`           | MRZ checksum validation failed (tampered document)                 | 35          |
| `mrz_data_mismatch`              | MRZ data doesn't match OCR-extracted text                          | 30          |
| `extraction_front_back_mismatch` | Front and back of document contain inconsistent data               | 30          |
| `pdf_editor_detected`            | PDF was created or modified with editing software                  | 25          |
| `pdf_abnormal_fonts`             | PDF contains an unusual number of fonts                            | 15          |
| `pdf_has_annotations`            | PDF contains overlay annotations                                   | 20          |

### Identity graph signals

Cross-session duplicate detection via hashed identity links.

| Signal                        | Description                                        | Risk weight |
| ----------------------------- | -------------------------------------------------- | ----------- |
| `duplicate_device_detected`   | Same device fingerprint seen in a previous session | 20          |
| `duplicate_email_detected`    | Same email used in a previous session              | 15          |
| `duplicate_phone_detected`    | Same phone number used in a previous session       | 15          |
| `duplicate_document_detected` | Same document number in a previous session         | 40          |
| `duplicate_face_detected`     | Same face matched via embedding similarity         | 35          |
| `duplicate_name_detected`     | Same name + DOB combination in a previous session  | 15          |
| `duplicate_ip_detected`       | Same IP address in a recent session                | 10          |

### Integrity signals

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

| Signal                           | Description                                  | Risk weight |
| -------------------------------- | -------------------------------------------- | ----------- |
| `integrity_checksum_mismatch`    | Signal payload HMAC doesn't match (tampered) | 40          |
| `integrity_checksum_missing`     | No checksum provided (bypassed collection)   | 20          |
| `integrity_too_few_keys`         | Signal payload has fewer keys than expected  | 15          |
| `integrity_has_range_violations` | Signal values outside valid ranges           | 15          |
| `integrity_has_contradictions`   | Signal values contradict each other          | 20          |

### Biometric signals

AI-generated face detection.

| Signal              | Description                               | Risk weight |
| ------------------- | ----------------------------------------- | ----------- |
| `deepfake_detected` | AI-generated or manipulated face detected | 45          |

### Mobile-specific signals

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

| Signal                      | Description                                             | Risk weight |
| --------------------------- | ------------------------------------------------------- | ----------- |
| `rooted_or_jailbroken`      | Device is rooted (Android) or jailbroken (iOS)          | 30          |
| `emulator_detected`         | Running on a virtual device                             | 35          |
| `debugger_attached`         | Debugger is connected to the process                    | 25          |
| `screen_recording`          | Active screen recording detected                        | 20          |
| `camera_injection_detected` | Virtual camera app injecting fake video                 | 50          |
| `device_attestation_failed` | Platform device integrity check failed                  | 35          |
| `zero_pressure_suspicious`  | Touch events have zero pressure (synthetic)             | 15          |
| `gyro_too_stable`           | Gyroscope data is unnaturally stable (no hand movement) | 15          |
| `install_source_sideloaded` | App was sideloaded, not from official store             | 10          |

## Risk scoring

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

### Risk levels

| Level        | Score range | Recommendation                                    |
| ------------ | ----------- | ------------------------------------------------- |
| **Low**      | 0–20        | Auto-approve eligible                             |
| **Medium**   | 21–50       | Proceed with caution                              |
| **High**     | 51–80       | Step-up verification or manual review recommended |
| **Critical** | 81–100      | Auto-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:

| Action           | Behavior                                  |
| ---------------- | ----------------------------------------- |
| `block`          | Counts in score + eligible for hard block |
| `flag` (default) | Counts in score                           |
| `ignore`         | Excluded from score entirely              |

Configure signal actions per organization to tune risk sensitivity.

## Viewing signals for a session

```bash
curl https://api.withverifa.com/api/v1/sessions/session_abc123/risk \
  -H "X-API-Key: vk_live_your_key_here"
```

```json
{
  "risk_score": 35,
  "risk_level": "medium",
  "triggered_signals": [
    { "signal": "vpn_detected", "weight": 25, "action": "flag" },
    { "signal": "high_distraction", "weight": 5, "action": "flag" },
    { "signal": "front_exif_stripped_jpeg", "weight": 10, "action": "flag" }
  ],
  "triggered_count": 3,
  "hard_blocked": false
}
```

## 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:

```json
{
  "risk_gate": {
    "type": "conditional",
    "routes": [
      {
        "conditions": [
          { "field": "risk_assessment.risk_level", "op": "==", "value": "critical" }
        ],
        "target": "reject_terminal"
      },
      {
        "conditions": [
          { "field": "risk_assessment.risk_level", "op": "==", "value": "high" }
        ],
        "target": "review_terminal"
      },
      {
        "conditions": [],
        "target": "approve_terminal"
      }
    ]
  }
}
```

## Related

* [Verifications & Checks](/core-concepts/verifications-checks) — The
  `risk_assessment` and `duplicate_detection` checks
* [Workflows](/core-concepts/workflows) — Route sessions based on risk level
* [Web Capture Flow](/integration-guides/web-capture-flow) — How signals are collected
  automatically
* [Mobile SDK](/integration-guides/mobile-sdk) — Mobile-specific fraud signals