Skip to main content

Checkout Protection

Protect your checkout from carding attacks, stolen card testing, and bot-driven fraud. ShieldLabs identifies automated tools and high-risk sessions before they reach your payment processor.

Common threats at checkout

ThreatScore rangeSignals
Card testing bots100+UA OS not detected, Stun is not checked, Is proxy
Manual carding (ADS browser)40–80Fail by * os detect, Is vpn by base ip
VPN user (legitimate)15Is vpn by base ip (override rule applied)
Datacenter IP (automated)50+Is datacenter, Stun is not checked

Flow

User reaches checkout page
  → force check runs immediately (no cache)
  → Webhook arrives with Score
  → Score < 40: show payment form
  → Score 40–69: require additional verification
  → Score 70+: decline or redirect to support

Step 1 — Force check at checkout page load

Use forceCheckAuthenticatedUser on the checkout page to always get a fresh score — don’t rely on the cached session score from page load.
<!-- checkout.html -->
<script type="module">
  const mod = await import('https://cdn.shieldlabs.ai/snippet.js?publicKey=YOUR_PUBLIC_KEY');
  mod.forceCheckAuthenticatedUser(USER_HASHED_ID, (ip, requestId) => {
    document.getElementById('shield-request-id').value = requestId;
    console.log('Shield check initiated:', requestId);
  });
</script>

<form id="checkout-form">
  <input type="hidden" id="shield-request-id" name="shieldRequestId">
  <!-- payment fields -->
  <button type="submit">Pay</button>
</form>

Step 2 — Gate the payment on the score

app.post('/api/checkout', async (req, res) => {
  const { shieldRequestId, paymentData, userId } = req.body;

  // Wait up to 3 seconds for Shield score
  const shield = await waitForScore(shieldRequestId, 3000);
  const score = shield?.score ?? 0;

  if (score >= 100) {
    // Block — bot/automation
    await logFraudAttempt(userId, shield);
    return res.status(403).json({
      error: 'Payment declined. Please contact support.',
    });
  }

  if (score >= 40) {
    // Require extra verification
    return res.status(200).json({
      requiresVerification: true,
      reason: 'Additional verification required for this session.',
    });
  }

  // Clean session — proceed with payment
  return processPayment(paymentData, userId, res);
});

Step 3 — Additional signals to watch

For high-value transactions, also check specific signals:
function analyzeCheckoutRisk(shield) {
  const signals = shield.signals.map(d => d.Description);
  const risks = [];

  if (signals.includes('Is proxy')) {
    risks.push('Proxy IP detected — high carding risk');
  }
  if (signals.some(s => s.startsWith('Fail by'))) {
    risks.push('Anti-detect browser detected');
  }
  if (signals.includes('Is abuser')) {
    risks.push('IP on abuse blacklist');
  }
  if (signals.includes('Stun is not checked')) {
    risks.push('Automated browser or UDP blocked');
  }

  return risks;
}

Score thresholds for checkout

ScoreAction
0–15Allow — low risk, proceed
16–39Allow — monitor
40–69Require 3DS / CAPTCHA / email verification
70+Decline — flag for manual review
100+Hard block