Skip to main content

<botshield-verify> Web Component

The <botshield-verify> element is BotShield’s client-side orchestration layer. It renders a verification widget on the merchant’s page and coordinates up to three layers of defense:
  1. Passkey Verification (always on) — cryptographic human proof via device biometrics
  2. Signal Pixel (opt-in via signals="true") — passive behavioral fingerprinting and edge scoring
  3. Third-party Integrations (automatic) — Cloudflare Turnstile, reCAPTCHA, and more when configured in your Integrations settings
On success, the widget fires a callback with a signed token, an opaque signal_token (tamper-proof bot score), and any third-party results.

Installation

Add a single script tag to your page. No npm install, no build step.
<script src="https://cdn.botshield.ai/sdk.js"></script>
The script registers the <botshield-verify> custom element globally. It uses a closed Shadow DOM so it never conflicts with your page styles.

Quick Start

<botshield-verify
  site-key="pk_live_YOUR_SITE_KEY"
  theme="auto"
  signals="true"
  onsuccess="handleVerified"
  onfailure="handleFailed"
></botshield-verify>

<script>
  function handleVerified({ token, signal_token, signal_score, turnstile_token }) {
    // Send ALL signals to your backend for server-side validation
    fetch('/api/verify-checkout', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        botshield_token: token,         // Signed verification JWT
        signal_token: signal_token,     // Tamper-proof bot score (validate server-side)
        // signal_score is display-only — always use signal_token for security
      }),
    });
  }

  function handleFailed({ reason }) {
    console.error('Verification failed:', reason);
  }
</script>

Attributes

AttributeTypeDefaultDescription
site-keystringrequiredYour public site key (pk_live_... or pk_test_...)
themelight | dark | autoautoVisual theme. auto follows the user’s prefers-color-scheme.
signalstrue | falsefalseEnable BotShield Signal Pixel — collects device and behavioral signals silently via an invisible 1x1 embed. Returns a tamper-proof signal_token alongside the bot score.
scan-modemodal | redirectmodalHow the QR scan UI is presented when a desktop user needs to verify on their phone. modal shows the QR code as an overlay. redirect opens a full-page verification screen.
challenge-urlstringhttps://cdn.botshield.ai/challengeOverride the challenge page URL (for self-hosted deployments).
onsuccessstringName of a global function called on success with { token, signal_token, signal_score, turnstile_token }
onfailurestringName of a global function called on failure with { reason }
onexpiredstringName of a global function called when the token expires
onreadystringName of a global function called when the widget loads

Events

In addition to callback attributes, the element dispatches standard Custom Events:
const el = document.querySelector('botshield-verify');

el.addEventListener('botshield:success', (e) => {
  const { token, signal_token, signal_score, turnstile_token } = e.detail;
  submitToServer(token, signal_token);
});

el.addEventListener('botshield:failure', (e) => {
  console.error('Failed:', e.detail.reason);
});
Evente.detailDescription
botshield:ready{}Widget has loaded and is ready for interaction
botshield:success{ token, signal_token, signal_score, turnstile_token }Verification complete. token is a signed JWT. signal_token is the tamper-proof bot score reference.
botshield:failure{ reason }Verification failed. reason explains why.
botshield:expired{}The verification token has expired. Widget resets to idle.
botshield:reset{}Widget was reset to idle state.

Signal Pixel

When signals="true", an invisible 1x1 iframe collects behavioral fingerprints alongside the verification widget: Edge signals (server-side, can’t be spoofed):
  • Datacenter ASN detection
  • TLS fingerprint analysis
  • HTTP protocol version
  • IP velocity tracking
  • Header anomaly detection
Behavioral signals (client-side):
  • WebDriver / automation flags
  • Canvas fingerprint
  • WebGL renderer
  • Mouse / touch events
  • Screen & hardware profile
The combined score (0–100) is returned in the signal_score field. However, this client-side score can be spoofed via DevTools. For tamper-proof validation, use the signal_token:
// Client-side score (display only — can be spoofed)
console.log('Bot score:', e.detail.signal_score); // 13

// Tamper-proof token (validate server-side — can't be spoofed)
console.log('Signal token:', e.detail.signal_token); // "bs_sig_a1b2c3..."
See the Signal Pixel reference for score ranges and signal details.

Third-Party Integrations

BotShield automatically loads and validates third-party bot detection tools when configured in your Integrations settings.

Cloudflare Turnstile

When Turnstile is enabled for your organization:
  1. The web component loads the Turnstile script automatically
  2. An invisible Turnstile widget runs in the background
  3. The Turnstile token is collected and returned in e.detail.turnstile_token
  4. BotShield validates the token server-side using your stored secret key
  5. The pass/fail result is included in your verification confidence score
No code changes required — just enable Turnstile in your dashboard and add your keys. Recommended Turnstile settings:
  • Widget Mode: Invisible — BotShield handles all UI
  • Pre-clearance: Yes — let verified visitors bypass lower CF challenges
  • Pre-clearance Level: Interactive (high) — BotShield provides the real biometric proof

Adding More Integrations

reCAPTCHA, DataDome, HUMAN, and more are coming. Each integration follows the same pattern: configure in your dashboard, BotShield auto-loads and validates. Contact us to request an integration.

Server-Side Validation

Never trust client-side state alone. The widget appearance, signal_score, and even the token must be validated on your server. BotShield provides three levels of server-side validation.

1. Verify the Verification Token

The primary check — validate the signed JWT that proves a human completed the passkey challenge:
const response = await fetch('https://api.botshield.ai/v1/verify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer sk_live_YOUR_SECRET_KEY',
  },
  body: JSON.stringify({
    token: requestBody.botshield_token,
  }),
});

const result = await response.json();
// {
//   valid: true,
//   claims: {
//     botshield_user_id: "uuid-...",
//     auth_mode: "private",
//     scope: "checkout.complete",
//     ...
//   }
// }

2. Validate the Signal Token (tamper-proof bot score)

If you’re using the Signal Pixel (signals="true"), validate the signal_token to get the real server-side bot score:
const response = await fetch('https://api.botshield.ai/v1/validate-signal', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer sk_live_YOUR_SECRET_KEY',
  },
  body: JSON.stringify({
    signal_token: requestBody.signal_token,
  }),
});

const result = await response.json();
// {
//   valid: true,
//   score: 13,              // Server-side score (can't be spoofed)
//   edge_score: 10,         // Network-layer signals
//   client_score: 16,       // Behavioral fingerprint
//   country: "US",
//   fp_hash: "a1b2c3..."   // Fingerprint for correlation
// }
Signal tokens are one-time use and expire after 10 minutes. The signal_score in the client event is for display only — always use signal_token for security decisions.

3. Combined Confidence Score

When all signals are present, BotShield combines them into a single confidence score:
// Full server-side validation with all signals
const response = await fetch('https://api.botshield.ai/v1/verify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer sk_live_YOUR_SECRET_KEY',
  },
  body: JSON.stringify({
    token: requestBody.botshield_token,
    signal_token: requestBody.signal_token,
  }),
});

const result = await response.json();
// {
//   valid: true,
//   confidence: 0.97,
//   signals: {
//     botshield_score: 13,
//     turnstile: { success: true },
//     passkey: { verified: true }
//   }
// }

if (result.valid && result.confidence >= 0.5) {
  // Human verified — proceed with checkout
} else {
  // Suspected bot — block or require additional verification
}

Visual States

The widget transitions through four states:
StateAppearanceBehavior
idleShield icon, “Verify human presence”, “Required” badgeClick to start verification
verifyingSpinner, “Verifying…”Verification in progress
verifiedGreen checkmark, “Human presence verified”, green borderComplete. Token available via callback.
failedRed X, “Verification failed”, red borderClick to reset and retry.

Themes

White background (#f9f9f9), gray border (#bebfc1), dark text.

JavaScript API

BotShield.render() — Programmatic Rendering

Create and mount a verification widget from JavaScript. Works with SPAs (React, Vue, Angular) and anywhere you need programmatic control.
const widget = BotShield.render('#checkout-container', {
  siteKey: 'pk_live_YOUR_SITE_KEY',
  signals: true,
  theme: 'dark',
  scanMode: 'modal',
  onSuccess: ({ token, signal_token, signal_score }) => {
    // Send to your backend
    submitToServer(token, signal_token);
  },
  onFailure: ({ reason }) => {
    console.error('Verification failed:', reason);
  },
  onReady: () => {
    console.log('Widget loaded');
  },
});
Options:
OptionTypeDescription
siteKeystringrequired — Your public site key
theme'light' | 'dark' | 'auto'Visual theme (default: 'auto')
signalsbooleanEnable Signal Pixel (default: false)
scanMode'modal' | 'redirect'QR scan presentation (default: 'modal')
challengeUrlstringOverride challenge URL
onSuccessfunctionCalled with { token, signal_token, signal_score, turnstile_token }
onFailurefunctionCalled with { reason }
onExpiredfunctionCalled when token expires
onReadyfunctionCalled when widget loads
Returns a widget handle:
// Trigger verification programmatically
widget.verify();

// Get the token after verification
const token = widget.getToken();     // string | null

// Get the Signal Pixel score
const score = widget.getScore();     // number | null

// Reset to idle state
widget.reset();

// Remove widget from DOM
widget.destroy();

// Access the underlying element
widget.element;  // <botshield-verify> HTMLElement

Direct Element Access

If you prefer HTML attributes, you can also query the element directly:
const el = document.querySelector('botshield-verify');
el.verify();
el.getToken();
el.getScore();
el.reset();

Framework Examples

React:
import { useEffect, useRef } from 'react';

function CheckoutVerification() {
  const containerRef = useRef(null);
  const widgetRef = useRef(null);

  useEffect(() => {
    widgetRef.current = BotShield.render(containerRef.current, {
      siteKey: 'pk_live_YOUR_KEY',
      signals: true,
      onSuccess: ({ token, signal_token }) => {
        fetch('/api/checkout', {
          method: 'POST',
          body: JSON.stringify({ token, signal_token }),
        });
      },
    });
    return () => widgetRef.current?.destroy();
  }, []);

  return <div ref={containerRef} />;
}
Vue 3:
<template>
  <div ref="container" />
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const container = ref(null);
let widget = null;

onMounted(() => {
  widget = BotShield.render(container.value, {
    siteKey: 'pk_live_YOUR_KEY',
    signals: true,
    onSuccess: ({ token, signal_token }) => {
      submitCheckout(token, signal_token);
    },
  });
});

onUnmounted(() => widget?.destroy());
</script>

QR Scan Mode

When a desktop user needs to verify on their phone (cross-device flow), the scan-mode attribute controls the presentation:
<botshield-verify site-key="pk_..." scan-mode="modal" />
Shows a QR code overlay on the current page with:
  • BotShield logo and step-by-step instructions
  • QR code for phone scanning
  • “Waiting for verification…” status with auto-close on completion
  • Cancel button

Redirect

<botshield-verify site-key="pk_..." scan-mode="redirect" />
Opens a full-page verification screen in a new tab.

Form Integration

When placed inside a <form>, the widget automatically injects a hidden input with the verification token:
<form action="/checkout" method="POST">
  <botshield-verify
    site-key="pk_live_YOUR_SITE_KEY"
    signals="true"
    onsuccess="enableSubmit"
  ></botshield-verify>

  <!-- These hidden inputs are auto-created on verification success -->
  <!-- <input type="hidden" name="botshield_token" value="eyJhbGc..."> -->

  <button type="submit" id="checkout-btn" disabled>
    Proceed to Checkout
  </button>
</form>

<script>
  function enableSubmit() {
    document.getElementById('checkout-btn').disabled = false;
  }
</script>

Platform Examples

Shopify (Cart Page)

<script src="https://cdn.botshield.ai/sdk.js"></script>

<botshield-verify
  site-key="pk_live_YOUR_KEY"
  theme="auto"
  signals="true"
  onsuccess="enableCheckout"
></botshield-verify>

<script>
  function enableCheckout({ token, signal_token }) {
    sessionStorage.setItem('botshield_token', token);
    sessionStorage.setItem('botshield_signal', signal_token);
    document.querySelector('[name=checkout]').disabled = false;
  }
</script>

WooCommerce

<script src="https://cdn.botshield.ai/sdk.js"></script>

<botshield-verify
  site-key="pk_live_YOUR_KEY"
  theme="light"
  signals="true"
  onsuccess="onVerified"
></botshield-verify>

<script>
  function onVerified({ token, signal_token }) {
    const form = document.querySelector('form.checkout');

    const tokenInput = document.createElement('input');
    tokenInput.type = 'hidden';
    tokenInput.name = 'botshield_token';
    tokenInput.value = token;
    form.appendChild(tokenInput);

    const signalInput = document.createElement('input');
    signalInput.type = 'hidden';
    signalInput.name = 'botshield_signal_token';
    signalInput.value = signal_token;
    form.appendChild(signalInput);

    document.getElementById('place_order').disabled = false;
  }
</script>

Escalation Pattern (with existing bot detection)

Use BotShield alongside your existing bot detection tool. Only show the verification widget when your existing tool is uncertain:
<script src="https://cdn.botshield.ai/sdk.js"></script>

<botshield-verify
  id="bs-verify"
  site-key="pk_live_YOUR_KEY"
  signals="true"
  style="display: none;"
></botshield-verify>

<script>
  // Your existing bot detection (Turnstile, DataDome, etc.)
  const riskScore = await getExternalBotScore();

  if (riskScore < 0.3) {
    // Clearly human — let through without BotShield
    proceedToCheckout();
  } else if (riskScore > 0.9) {
    // Clearly bot — block
    showBlockedMessage();
  } else {
    // Gray zone — escalate to BotShield
    document.getElementById('bs-verify').style.display = 'block';
  }
</script>

Next Steps