> ## Documentation Index
> Fetch the complete documentation index at: https://docs.botshield.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# BotShield Signal Pixel

> Passive bot scoring, tamper-proof signal tokens, Turnstile integration, and escalation to passkey verification

# BotShield Signal Pixel

The BotShield Signal Pixel is an opt-in passive signal collection layer built into the `<botshield-verify>` web component. When enabled with `signals="true"`, it combines **edge scoring**, **behavioral fingerprinting**, and **third-party integrations** (Cloudflare Turnstile) to produce a tamper-proof bot score — without requiring any user interaction.

<Info>
  The Signal Pixel is not a separate integration. It is a capability of the same `<botshield-verify>` web component used for active passkey verification. Add `signals="true"` to enable it.
</Info>

## Three Layers of Defense

The Signal Pixel is **Layer 1** of BotShield's defense-in-depth architecture:

```mermaid theme={null}
graph TD
    A[Page loads with signals enabled] --> B[Layer 1: Signal Pixel]
    B --> B1[Edge Scoring - ASN, TLS, IP]
    B --> B2[Behavioral Fingerprint - canvas, WebGL, mouse]
    B --> B3[Turnstile - auto-loaded if configured]
    B1 --> C[Combined Score 0-100]
    B2 --> C
    B3 --> D[Turnstile Pass/Fail]
    C --> E{Score Decision}
    D --> E
    E -->|0-30: Low risk| F[Silent pass]
    E -->|31-70: Gray zone| G[Layer 2: Passkey Verification]
    E -->|71-100: High risk| H[Block or require passkey]
    G --> I[Layer 3: Reputation over time]
```

## Quick Start

```html theme={null}
<script src="https://cdn.botshield.ai/sdk.js"></script>

<botshield-verify
  site-key="pk_live_YOUR_KEY"
  signals="true"
  onsuccess="handleVerified"
></botshield-verify>

<script>
  function handleVerified({ token, signal_token, signal_score }) {
    // signal_score = display only (can be spoofed via DevTools)
    // signal_token = tamper-proof (validate server-side)
    fetch('/api/checkout', {
      method: 'POST',
      body: JSON.stringify({
        botshield_token: token,
        signal_token: signal_token,
      }),
    });
  }
</script>
```

Or with `BotShield.render()`:

```javascript theme={null}
const widget = BotShield.render('#container', {
  siteKey: 'pk_live_YOUR_KEY',
  signals: true,
  onSuccess: ({ token, signal_token, signal_score, turnstile_token }) => {
    submitToServer(token, signal_token);
  },
});
```

## Tamper-Proof Signal Tokens

<Warning>
  The `signal_score` returned in the client event is for **display only**. It can be spoofed via DevTools. Always validate using the `signal_token` on your server.
</Warning>

The Signal Pixel returns an opaque `signal_token` (e.g. `bs_sig_a1b2c3...`) alongside the display score. This token maps to the real score stored in BotShield's database — it cannot be faked.

```mermaid theme={null}
sequenceDiagram
    participant Page as Your Page
    participant WC as Web Component
    participant CDN as cdn.botshield.ai
    participant API as BotShield API
    participant DB as Database

    WC->>CDN: Collect behavioral signals
    CDN->>CDN: Edge scoring
    CDN->>API: POST /sdk/store-signal
    API->>DB: Store real score
    DB-->>API: signal_token
    API-->>CDN: score + signal_token
    CDN-->>WC: postMessage
    WC-->>Page: onSuccess with signal_score + signal_token
    Note over Page: signal_score = display only
    Note over DB: Real score = tamper-proof
    Page->>API: POST /sdk/validate-signal
    API->>DB: Lookup real score
    DB-->>API: score, country, fp_hash
    API-->>Page: valid + real score
```

### Server-Side Validation

```typescript theme={null}
import BotShield from 'botshield-sdk';

const client = new BotShield({ apiKey: process.env.BOTSHIELD_API_KEY });

// Validate the signal token — get the REAL score
const signal = await client.sdk.validateSignal({
  signal_token: req.body.signal_token,
});

if (signal.valid) {
  console.log('Server-side score:', signal.score); // 13 (can't be spoofed)
  console.log('Country:', signal.country);          // "US"
  console.log('Fingerprint:', signal.fp_hash);      // "a1b2c3..."
}
```

<Note>
  Signal tokens are **one-time use** and expire after **10 minutes**. Once validated, the token is consumed and cannot be reused.
</Note>

## Cloudflare Turnstile Integration

When you enable [Cloudflare Turnstile](https://console.botshield.ai) in your BotShield dashboard, the web component **automatically loads and runs Turnstile** alongside the Signal Pixel. No code changes needed.

```mermaid theme={null}
sequenceDiagram
    participant Page as Your Page
    participant WC as Web Component
    participant Config as Partner Config
    participant CF as Cloudflare Turnstile
    participant API as BotShield API

    WC->>Config: GET /partner-config
    Config-->>WC: turnstile enabled + site_key
    WC->>CF: Load Turnstile script invisibly
    CF-->>WC: Turnstile token
    Note over WC: User sees nothing
    WC-->>Page: onSuccess with token + signal_token + turnstile_token
    Page->>API: POST /verify-token
    API->>CF: POST /siteverify with stored secret
    CF-->>API: success
    API-->>Page: valid, confidence 0.97, all signals
```

### Setup

1. Go to **Partner Dashboard** → **Integrations** → **Cloudflare Turnstile**
2. Enter your Turnstile **Site Key** and **Secret Key**
3. Click **Save**

**Recommended Turnstile settings:**

* **Widget Mode:** Invisible — BotShield handles all UI
* **Pre-clearance:** Yes
* **Pre-clearance Level:** Interactive (high)

That's it. The web component detects the configuration and loads Turnstile automatically on every page load.

## Combined Confidence Scoring

When you pass both `token` and `signal_token` to `verify-token`, BotShield returns a combined confidence score that factors in all available signals:

```typescript theme={null}
const result = await client.sdk.verifyToken({
  token: req.body.botshield_token,
  signal_token: req.body.signal_token,
});

// result = {
//   valid: true,
//   confidence: 0.97,
//   signals: {
//     botshield_score: 13,              // Signal Pixel (0-100)
//     turnstile: { success: true },     // Cloudflare Turnstile
//     passkey: { verified: true },      // Biometric proof
//   },
//   claims: {
//     request_id: "req_...",
//     verified: true,
//     // anonymous attestation — no identity in the token
//   }
// }
```

## Scoring Method

The bot score is a **combined metric** from two independent layers:

```
combined_score = (edge_score × 0.5) + (behavioral_score × 0.5)
```

### Edge Scoring (Server-Side — Can't Be Spoofed)

Evaluated at the Cloudflare Worker edge before any HTML is served.

| Signal                                         | Points | What It Catches                            |
| ---------------------------------------------- | ------ | ------------------------------------------ |
| **Datacenter ASN**                             | +35    | Traffic from AWS, GCP, Azure, DigitalOcean |
| **TLS version not 1.3**                        | +20    | Scripts or outdated tooling                |
| **Stripped TLS ClientHello** (under 200 bytes) | +15    | Automated HTTP library                     |
| **Padded TLS ClientHello** (over 1000 bytes)   | +10    | Evasion technique                          |
| **HTTP/1.1 protocol**                          | +15    | curl, scripts, old bots                    |
| **Missing or bot User-Agent**                  | +30-40 | python, curl, puppeteer, selenium          |
| **Missing Accept headers**                     | +10-15 | Non-browser clients                        |
| **High IP velocity** (>20 req/min)             | +20-30 | Automated rapid requests                   |

### Behavioral Fingerprint (Client-Side)

Runs over a 1.5-second collection window inside an isolated context.

| Signal                           | Points | What It Catches                 |
| -------------------------------- | ------ | ------------------------------- |
| **`navigator.webdriver` = true** | +40    | Puppeteer, Playwright, Selenium |
| **No browser plugins**           | +10    | Headless browsers               |
| **Zero hardware concurrency**    | +15    | Virtual environments            |
| **No mouse or touch events**     | +15    | Non-interactive client          |
| **Screen dimensions 0x0**        | +20    | Headless browser default        |
| **Canvas fingerprint blocked**   | +10    | Headless or privacy extension   |
| **No WebGL renderer**            | +15    | No GPU access                   |

## Score Ranges

| Score     | Risk Level     | Recommended Action                           |
| --------- | -------------- | -------------------------------------------- |
| **0-30**  | Low            | Silent pass — no UI shown to user            |
| **31-70** | Gray zone      | BotShield passkey verification as escalation |
| **71-99** | High           | Active passkey challenge required            |
| **100**   | Definitive bot | Hard block — no challenge offered            |

## Full Escalation Flow

The most powerful pattern — passive Signal Pixel screening with automatic escalation to passkey verification when the score is ambiguous:

```mermaid theme={null}
flowchart TD
    A[User visits checkout] --> B[Signal Pixel collects signals]
    B --> C{Score?}
    C -->|0-30| D[Silent pass - no friction]
    C -->|31-70| E[Show verify widget]
    C -->|71+| F[Require passkey]
    E --> G[User taps Verify]
    F --> G
    G --> H[Scan QR with phone]
    H --> I[Face ID / biometric]
    I --> J[Verified - checkout proceeds]
```

```html theme={null}
<botshield-verify
  id="bs"
  site-key="pk_live_KEY"
  signals="true"
  scan-mode="modal"
  onsuccess="onVerified"
></botshield-verify>

<script>
  function onVerified({ token, signal_token, signal_score }) {
    if (signal_score <= 30) {
      // Low risk — proceed without passkey
      submitOrder(token, signal_token);
    } else {
      // Gray zone or high risk — passkey already completed
      submitOrder(token, signal_token);
    }
  }
</script>
```

## Security

* Signal collection runs in an isolated context — cannot access the parent page's DOM, cookies, or storage
* `signal_token` is **tamper-proof** — always validate server-side, never trust `signal_score` alone
* Behavioral fingerprint collects device/environmental signals only — **no PII, no tracking**
* Turnstile secret keys are stored encrypted and used server-side only — never exposed to the client

## Next Steps

<CardGroup cols={2}>
  <Card icon="code" href="/embed/web-component" title="Web Component Reference">
    Full API docs for `<botshield-verify>` and `BotShield.render()`
  </Card>

  <Card icon="shield-check" href="/api-reference/overview" title="API Reference">
    Backend SDK methods for server-side validation
  </Card>

  <Card icon="plug" href="https://console.botshield.ai" title="Enable Turnstile">
    Configure integrations in your Partner Dashboard
  </Card>

  <Card icon="flask" href="https://console.botshield.ai" title="Playground">
    Test Signal Pixel + Turnstile with live scoring
  </Card>
</CardGroup>
