Use Cases

E-commerce Protection

Protect checkout flows, inventory, and prevent scalping

E-commerce Protection

This guide covers bot protection strategies for e-commerce applications, including checkout flow protection, inventory defense, and scalping prevention. E-commerce sites face unique threats from automated traffic seeking to exploit limited inventory, scrape pricing, or abuse promotions.

Common Threats

Checkout Abuse

  • Card testing - Bots validating stolen credit cards with small purchases
  • Promo abuse - Automated redemption of discount codes
  • Account takeover - Credential stuffing on login/checkout

Inventory Attacks

  • Scalping - Bots purchasing limited items for resale
  • Denial of inventory - Holding items in carts without purchasing
  • Flash sale abuse - Automated purchasing during limited-time sales

Competitive Intelligence

  • Price scraping - Competitors monitoring your pricing
  • Catalog scraping - Copying product data and images

Integration Strategy

Layered Protection

Apply different thresholds at each stage of the purchase funnel:

Browse (low friction) → Add to Cart (monitor) → Checkout (verify) → Payment (strict)
BotSigged.init({
  apiKey: 'your-api-key',
  botScoreThresholds: {
    medium: 40,
    high: 60,
    critical: 80,
  },
});

Page-Specific Configuration

Configure protection based on page sensitivity:

// Product pages - monitor only
const productConfig = {
  apiKey: 'your-api-key',
  action: 'none',
  onScoreUpdate: (score) => {
    analytics.track('product_view_score', { score: score.bot_score });
  },
};

// Checkout - active protection
const checkoutConfig = {
  apiKey: 'your-api-key',
  actionThreshold: 60,
  action: 'challenge',
  formProtection: {
    mode: 'holdUntilFormScored',
    maxHoldTime: 5000,
  },
};

Checkout Flow Protection

Multi-Step Checkout

Track scores across checkout steps:

class CheckoutFlow {
  constructor() {
    this.stepScores = [];
    this.botSigged = BotSigged.init({
      apiKey: 'your-api-key',
      onScoreUpdate: (score) => {
        this.recordScore(score);
      },
    });
  }

  recordScore(score) {
    this.stepScores.push({
      step: this.currentStep,
      score: score.bot_score,
      timestamp: Date.now(),
    });
  }

  async proceedToStep(nextStep) {
    const avgScore = this.getAverageScore();

    // Block if consistently suspicious
    if (avgScore > 70 && this.stepScores.length >= 2) {
      throw new Error('Unable to proceed. Please contact support.');
    }

    // Challenge on payment step
    if (nextStep === 'payment' && avgScore > 50) {
      await this.botSigged.triggerChallenge('high');
    }

    this.currentStep = nextStep;
  }

  getAverageScore() {
    if (this.stepScores.length === 0) return 0;
    const sum = this.stepScores.reduce((acc, s) => acc + s.score, 0);
    return sum / this.stepScores.length;
  }
}

Express Checkout Protection

For one-click or express checkout:

async function expressCheckout(savedPaymentMethod) {
  const { score, timedOut } = await botSigged.waitUntilReady();

  // Stricter threshold for express checkout
  if (score && score > 50) {
    // Fall back to regular checkout
    return redirectToFullCheckout();
  }

  // Proceed with express checkout
  return processPayment(savedPaymentMethod);
}

Guest Checkout

Guest checkout is higher risk - apply stricter rules:

const guestCheckoutConfig = {
  apiKey: 'your-api-key',
  actionThreshold: 50, // Lower threshold than authenticated
  action: 'challenge',
  formProtection: {
    mode: 'holdUntilFormScored',
    maxHoldTime: 5000,
  },
};

Add to Cart Protection

Rate-Limited Cart Additions

Combine BotSigged with rate limiting:

class CartProtection {
  constructor(botSigged) {
    this.botSigged = botSigged;
    this.addAttempts = [];
  }

  async addToCart(productId, quantity) {
    // Check rate limit
    this.cleanOldAttempts();
    if (this.addAttempts.length > 10) {
      throw new Error('Too many requests. Please slow down.');
    }

    // Check bot score
    const score = this.botSigged.getLastScore();
    if (score && score.bot_score > 60) {
      // Require challenge for suspected bots
      await this.botSigged.triggerChallenge('medium');
    }

    this.addAttempts.push(Date.now());

    return fetch('/api/cart/add', {
      method: 'POST',
      headers: {
        'X-BotSigged-Session': this.botSigged.getSessionId(),
      },
      body: JSON.stringify({ productId, quantity }),
    });
  }

  cleanOldAttempts() {
    const oneMinuteAgo = Date.now() - 60000;
    this.addAttempts = this.addAttempts.filter((t) => t > oneMinuteAgo);
  }
}

Limited Quantity Items

Extra protection for high-demand products:

async function addLimitedItem(productId) {
  const { score, timedOut } = await botSigged.waitUntilReady();

  // Strict threshold for limited items
  if (score && score > 40) {
    showMessage('Please complete verification to add this item.');
    await botSigged.triggerChallenge('high');

    // Re-check after challenge
    const newScore = botSigged.getLastScore();
    if (newScore && newScore.bot_score > 40) {
      throw new Error('Unable to add item. Please try again later.');
    }
  }

  return addToCart(productId);
}

Inventory Protection

Cart Abandonment Defense

Prevent bots from holding inventory:

// Server-side: Release held inventory after timeout
async function releaseAbandonedCarts() {
  const abandonedCarts = await db.carts.findMany({
    where: {
      updatedAt: { lt: new Date(Date.now() - 15 * 60 * 1000) }, // 15 min
      status: 'active',
    },
  });

  for (const cart of abandonedCarts) {
    // Check session bot score
    const session = await botSiggedApi.getSession(cart.sessionId);

    // Release immediately if high bot score
    if (session.bot_score > 70) {
      await releaseCartInventory(cart.id);
    } else {
      // Give humans more time
      if (cart.updatedAt < Date.now() - 30 * 60 * 1000) {
        await releaseCartInventory(cart.id);
      }
    }
  }
}

Inventory Reservation Queue

For flash sales or limited drops:

class InventoryQueue {
  constructor(productId, maxQuantity) {
    this.productId = productId;
    this.maxQuantity = maxQuantity;
    this.queue = [];
  }

  async requestReservation(sessionId, quantity) {
    // Get bot score from BotSigged API
    const session = await fetch(`${BOTSIGGED_API}/sessions/${sessionId}`);
    const { bot_score } = await session.json();

    // Priority based on bot score (lower = higher priority)
    const priority = bot_score;

    this.queue.push({ sessionId, quantity, priority, timestamp: Date.now() });
    this.queue.sort((a, b) => a.priority - b.priority);

    return this.processQueue();
  }

  processQueue() {
    let remaining = this.maxQuantity;
    const reservations = [];

    for (const request of this.queue) {
      if (remaining <= 0) break;

      const reserved = Math.min(request.quantity, remaining);
      reservations.push({ sessionId: request.sessionId, quantity: reserved });
      remaining -= reserved;
    }

    return reservations;
  }
}

Payment Protection

Pre-Payment Verification

Verify before processing payment:

async function processPayment(paymentData) {
  const { score } = await botSigged.waitUntilReady();

  // Critical threshold for payments
  if (score && score > 80) {
    return {
      success: false,
      error: 'Unable to process payment. Please contact support.',
    };
  }

  // Challenge for medium-high scores
  if (score && score > 60) {
    const challengeResult = await botSigged.triggerChallenge('critical');
    if (!challengeResult.solved) {
      return {
        success: false,
        error: 'Verification failed. Please try again.',
      };
    }
  }

  // Include session ID for server-side verification
  return fetch('/api/payments', {
    method: 'POST',
    headers: {
      'X-BotSigged-Session': botSigged.getSessionId(),
    },
    body: JSON.stringify(paymentData),
  });
}

Server-Side Payment Validation

// Server-side payment handler
async function handlePayment(req, res) {
  const sessionId = req.headers['x-botsigged-session'];

  // Verify session with BotSigged API
  const session = await fetch(`${BOTSIGGED_API}/sessions/${sessionId}`);
  const { bot_score, classification, triggered_rules } = await session.json();

  // Log for fraud analysis
  await logPaymentAttempt({
    sessionId,
    botScore: bot_score,
    classification,
    triggeredRules: triggered_rules,
    amount: req.body.amount,
    timestamp: new Date(),
  });

  // Block high-risk transactions
  if (bot_score > 85) {
    return res.status(403).json({
      error: 'Transaction blocked for security reasons',
    });
  }

  // Flag for manual review
  if (bot_score > 60) {
    await flagForReview(sessionId, req.body);
  }

  // Process payment
  return processPaymentWithProvider(req.body);
}

Promo Code Protection

Client-Side Validation

async function applyPromoCode(code) {
  const { score } = await botSigged.waitUntilReady();

  // Challenge suspected bots before applying codes
  if (score && score > 50) {
    await botSigged.triggerChallenge('medium');
  }

  return fetch('/api/promo/apply', {
    method: 'POST',
    headers: {
      'X-BotSigged-Session': botSigged.getSessionId(),
    },
    body: JSON.stringify({ code }),
  });
}

Server-Side Rate Limiting by Score

// Server-side promo handler
const promoAttempts = new Map(); // sessionId -> attempts

async function handlePromoCode(req, res) {
  const sessionId = req.headers['x-botsigged-session'];
  const session = await botSiggedApi.getSession(sessionId);

  // Stricter rate limits for higher scores
  const maxAttempts = session.bot_score > 50 ? 3 : 10;
  const attempts = promoAttempts.get(sessionId) || 0;

  if (attempts >= maxAttempts) {
    return res.status(429).json({ error: 'Too many attempts' });
  }

  promoAttempts.set(sessionId, attempts + 1);

  // Validate and apply code
  return applyPromoCode(req.body.code);
}

Analytics & Monitoring

Track Bot Activity

BotSigged.init({
  apiKey: 'your-api-key',
  onScoreUpdate: (score) => {
    // Track all sessions
    analytics.track('botsigged_score', {
      score: score.bot_score,
      classification: score.classification,
      rules: score.triggered_rules,
      page: window.location.pathname,
    });
  },
  onHighBotScore: (event) => {
    // Alert on high scores
    analytics.track('suspected_bot', {
      score: event.score,
      level: event.level,
      sessionId: event.sessionId,
    });
  },
});

Conversion Funnel Analysis

Compare conversion rates by bot score:

// Track funnel events with score
function trackFunnelEvent(event, data = {}) {
  const score = botSigged.getLastScore();

  analytics.track(event, {
    ...data,
    botScore: score?.bot_score,
    classification: score?.classification,
    sessionId: botSigged.getSessionId(),
  });
}

// Usage
trackFunnelEvent('product_viewed', { productId: '123' });
trackFunnelEvent('added_to_cart', { productId: '123', quantity: 1 });
trackFunnelEvent('checkout_started');
trackFunnelEvent('payment_submitted');
trackFunnelEvent('order_completed', { orderId: 'abc' });

React E-commerce Example

Complete checkout component:

import { useState } from 'react';
import { useBotSigged } from '@/lib/botsigged';

export function Checkout({ cart }) {
  const { sdk, score, isReady } = useBotSigged();
  const [step, setStep] = useState('shipping');
  const [error, setError] = useState(null);

  const isBlocked = score && score.bot_score > 80;
  const needsChallenge = score && score.bot_score > 60;

  async function handleSubmitPayment(paymentData) {
    setError(null);

    if (isBlocked) {
      setError('Unable to process order. Please contact support.');
      return;
    }

    if (needsChallenge) {
      const result = await sdk.triggerChallenge('high');
      if (!result.solved) {
        setError('Verification required. Please try again.');
        return;
      }
    }

    try {
      const response = await fetch('/api/orders', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-BotSigged-Session': sdk.getSessionId(),
        },
        body: JSON.stringify({
          cart,
          payment: paymentData,
        }),
      });

      if (!response.ok) throw new Error('Order failed');

      const order = await response.json();
      window.location.href = `/orders/${order.id}/confirmation`;
    } catch (err) {
      setError('Unable to complete order. Please try again.');
    }
  }

  return (
    <div className="checkout">
      {error && <div className="error">{error}</div>}

      {!isReady && <div className="loading">Verifying session...</div>}

      {step === 'shipping' && (
        <ShippingForm onComplete={() => setStep('payment')} />
      )}

      {step === 'payment' && (
        <PaymentForm
          onSubmit={handleSubmitPayment}
          disabled={isBlocked || !isReady}
        />
      )}
    </div>
  );
}

Best Practices

Don’t Over-Block

False positives hurt sales. Start with monitoring and adjust:

  1. Week 1: Monitor only, collect baseline data
  2. Week 2: Enable challenges for critical scores (80+)
  3. Week 3: Lower threshold based on data
  4. Ongoing: Review blocked sessions weekly

Provide Clear Feedback

Don’t leave users confused:

// Bad
throw new Error('Error');

// Good
throw new Error('Unable to complete your request. If you believe this is an error, please contact [email protected]');

Have a Manual Override

For customer support to unblock legitimate users:

// Check for support override token
const overrideToken = req.headers['x-support-override'];
if (overrideToken && validateSupportToken(overrideToken)) {
  // Skip bot check
  return processOrder(req.body);
}

Test Your Thresholds

Use the zoo tools to verify your protection:

cd zoo
npm run test-headless   # Should be blocked/challenged
npm run test-stealth    # Test against stealth bots