
Bot Protection
- 71 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Block scraping, scalping, and credential-stuffing bots on a store using CAPTCHA, WAF rules, rate limiting, and behavioral detection, primarily via Cloudflare.
About
A skill for defending ecommerce stores against scraper, scalper, and credential-stuffing bots with layered CAPTCHA, WAF, and behavioral defenses. A developer uses it to protect catalog data, limited inventory, and checkout from automated abuse.
- Cloudflare-first WAF and Turnstile approach across platforms
- Layers platform defenses, rate limiting, honeypots, behavioral analysis
Bot Protection by the numbers
- 71 all-time installs (skills.sh)
- Ranked #1,170 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill bot-protectionAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 71 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Block scraping, scalping, and credential-stuffing bots on a store using CAPTCHA, WAF rules, rate limiting, and behavioral detection, primarily via Cloudflare.
Files
Bot Protection
Overview
Commerce stores face three major bot threats: scrapers that harvest pricing and inventory data for competitors, scalper bots that buy limited-inventory items instantly, and credential-stuffing bots that test stolen usernames and passwords. Effective bot protection layers platform-level defenses, a WAF (Web Application Firewall), CAPTCHA for high-risk actions, and optional behavioral analysis. For most merchants, Cloudflare provides the most effective and lowest-friction protection — it sits in front of your store regardless of platform.
When to Use This Skill
- When launching limited-edition products prone to scalping (sneakers, concert tickets, gaming consoles)
- When competitors are systematically scraping your product prices or inventory levels
- When account login pages show signs of credential stuffing (high failure rates from distributed IPs)
- When checkout funnel analytics show suspiciously fast completion times (sub-5-second checkout)
- When your infrastructure is overwhelmed by bot traffic consuming catalog API resources
Core Instructions
Step 1: Determine the merchant's platform and choose the right tool
| Platform | Built-in Bot Protection | Recommended Additional Layer |
|---|---|---|
| Shopify | Shopify includes basic bot detection and rate limiting | Enable Cloudflare (free plan) in front of your Shopify store for WAF rules and bot management |
| WooCommerce | None built in — the login and checkout forms are fully exposed | Wordfence (free) for login protection; Cloudflare for WAF and rate limiting |
| BigCommerce | Basic DDoS protection included | Cloudflare for advanced bot management; BigCommerce supports custom scripts for CAPTCHA |
| High-traffic drops (any platform) | None | Cloudflare Waiting Room (Business/Enterprise) or Queue-it for managed queue |
| Custom / Headless | Must build | Cloudflare + custom rate limiting + behavioral analysis |
Step 2: Set up foundational bot protection
---
Step 2a: Enable Cloudflare (works for all platforms)
Cloudflare's free plan provides significant bot protection at the DNS level without touching your application code.
1. Add your domain to Cloudflare at cloudflare.com (free plan works for most stores) 2. Update your domain's nameservers to the Cloudflare nameservers provided 3. In Cloudflare dashboard:
- SSL/TLS → Overview: set to "Full (Strict)"
- Security → WAF → Managed rules: enable Cloudflare Managed Ruleset (free) and OWASP Core Ruleset
- Security → Bots → Bot Fight Mode: enable (free) — blocks known bot user agents
4. For additional protection, create custom WAF Rules (Security → WAF → Custom Rules):
# Block requests with no User-Agent header
(not http.user_agent contains " " and not cf.client.bot)
# Rate limit catalog API scraping
# Under Security → WAF → Rate Limiting Rules:
# Path: /products/* or /api/products/*
# Rate: 100 requests per minute per IP
# Action: Block for 1 hourCloudflare Bot Management (Business plan, ~$200/month): For stores with serious scalping or scraping problems, Cloudflare Bot Management uses machine learning to score every request and challenge or block suspicious traffic without impacting legitimate shoppers.
---
Step 2b: Add CAPTCHA to high-risk forms
Use Cloudflare Turnstile (free, privacy-preserving, invisible-first) on login and checkout forms. Turnstile uses passive signals before showing a visible challenge — most legitimate users never see a CAPTCHA.
Adding Turnstile to a Shopify store: 1. Sign up for Cloudflare Turnstile at cloudflare.com/products/turnstile (free) 2. Create a new site, select "Managed" mode, note your site key and secret key 3. In Shopify, customize your theme to add the Turnstile widget to the login and checkout forms:
- Use a Shopify theme app extension or edit the theme directly
- Add
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>and a<div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY">to the login form
4. Verify the token server-side in your custom app or use a Shopify Function
Adding Turnstile to WooCommerce: 1. Install the Cloudflare Turnstile WordPress plugin (search "Cloudflare Turnstile" in the plugin directory) 2. Enter your site key and secret key 3. Configure which forms to protect: login, registration, checkout, comment forms
Server-side token verification:
async function verifyTurnstile(token: string, ip: string): Promise<boolean> {
const res = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
method: 'POST',
body: new URLSearchParams({
secret: process.env.TURNSTILE_SECRET_KEY!,
response: token,
remoteip: ip,
}),
});
const data = await res.json();
return data.success === true;
}---
Step 2c: Set up a Waiting Room for product drops (high-demand launches)
For limited-inventory launches where you expect traffic spikes and scalpers:
Cloudflare Waiting Room (Business/Enterprise plan): 1. In Cloudflare dashboard, go to Traffic → Waiting Room 2. Click Create 3. Configure:
- Hostname: your store domain
- Path: the product URL pattern (e.g.,
/products/limited-*or/collections/drop) - Total active users: maximum concurrent users allowed through (e.g., 500)
- New users per minute: admission rate (e.g., 100 per minute)
4. Customize the waiting room page with your branding 5. Cloudflare queues excess traffic fairly; bot traffic is filtered by Cloudflare's bot detection before entering the queue
---
Step 2d: Platform-specific protections
Shopify — Per-customer purchase limits: Shopify does not enforce per-customer purchase limits natively for limited products. Options:
- Use a Shopify app like Locksmith or Order Limits by MLveda to restrict purchase quantity per customer
- On Shopify Plus: use Shopify Functions to enforce limits at checkout
WooCommerce — Login brute-force protection: 1. Install Wordfence Security (free) 2. Enable brute-force protection under Wordfence → Login Security 3. Enable two-factor authentication for admin accounts
WooCommerce — CAPTCHA on checkout: 1. Install Google Recaptcha for WooCommerce (free) or the Cloudflare Turnstile plugin 2. Configure to protect: login, registration, checkout, and lost password forms
---
Custom / Headless — Application-layer rate limiting
For custom storefronts, add rate limiting at the middleware or edge layer:
// Next.js Edge Middleware — rate limiting per IP per route
import { NextRequest, NextResponse } from 'next/server';
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const redis = Redis.fromEnv();
const limiters = {
checkout: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(10, '1 m'), prefix: 'rl_checkout' }),
catalog: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(100, '1 m'), prefix: 'rl_catalog' }),
};
export async function middleware(request: NextRequest) {
const ip = request.ip ?? request.headers.get('x-forwarded-for') ?? '127.0.0.1';
const pathname = request.nextUrl.pathname;
const limiter = pathname.startsWith('/checkout') ? limiters.checkout
: pathname.startsWith('/products') ? limiters.catalog
: null;
if (limiter) {
const { success } = await limiter.limit(ip);
if (!success) return new NextResponse('Too Many Requests', { status: 429 });
}
return NextResponse.next();
}Per-customer purchase limits (custom):
async function enforcePurchaseLimit(customerId: string, productId: string, limit = 1) {
const count = await db.orders.countByCustomerAndProduct(customerId, productId);
if (count >= limit) throw new Error(`Purchase limit of ${limit} per customer reached`);
// Atomic lock to prevent race conditions at high concurrency
const lockKey = `purchase_lock:${customerId}:${productId}`;
const acquired = await redis.set(lockKey, '1', 'EX', 30, 'NX');
if (!acquired) throw new Error('Purchase already in progress');
}Best Practices
- Layer multiple defenses — no single technique stops all bots; combine Cloudflare WAF, Turnstile CAPTCHA, and application-level rate limiting
- Use invisible CAPTCHAs first — Cloudflare Turnstile and hCaptcha passive mode challenge only suspicious requests; visible CAPTCHAs on every checkout hurt conversion
- Fingerprint sessions, not just IPs — bots rotate IPs via residential proxies; supplement IP-based rules with behavioral signals and session characteristics
- Enforce per-product purchase limits at the database level — client-side limits are trivially bypassed; enforce with a server-side check or database constraint
- Monitor your bot-to-human ratio — set up a Cloudflare Analytics or Datadog dashboard tracking the ratio of blocked requests to total requests; spikes indicate new bot campaigns
- Pre-announce high-demand drops with a waitlist — collecting emails in advance lets you give waitlist members priority access, making the queue fairer and reducing demand at the moment of launch
Common Pitfalls
| Problem | Solution |
|---|---|
| Rate limits blocking legitimate flash sale traffic | Set higher rate limits for authenticated customers with purchase history; apply strict limits only to unauthenticated requests |
| Turnstile CAPTCHA breaking checkout | Test Turnstile in "Always passes" mode during setup; ensure your server-side verification endpoint is working before enabling in production |
| Waiting room not activating for a product drop | Configure Cloudflare Waiting Room 24 hours before the drop and test with a staging URL; ensure the path pattern matches the product URL |
| Purchase limit bypass via multiple accounts | Require phone verification for high-demand product purchases; link purchase limits to verified phone numbers or identity, not just accounts |
| Wordfence blocking legitimate WooCommerce customers | Review blocked IP logs in Wordfence; allowlist legitimate customers and adjust sensitivity settings |
Related Skills
- @fraud-detection
- @account-security
- @secure-checkout
- @flash-sale-engine
- @monitoring-alerting-commerce
{
"context": "Tests whether the agent correctly implements edge-layer rate limiting for a commerce application using the recommended packages, algorithms, and per-route limits — and whether the 429 response includes proper headers.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Correct rate limit package",
"max_score": 10,
"description": "Uses @upstash/ratelimit (not express-rate-limit, rate-limiter-flexible, or other alternatives)"
},
{
"name": "Correct Redis package",
"max_score": 8,
"description": "Uses @upstash/redis (not ioredis, redis, or other Redis clients)"
},
{
"name": "Redis.fromEnv() initialization",
"max_score": 7,
"description": "Initializes the Redis client using Redis.fromEnv() rather than constructor arguments or connection strings"
},
{
"name": "Edge middleware placement",
"max_score": 8,
"description": "Rate limiting logic is placed in middleware.ts (Next.js Edge Middleware), not inside individual API route handlers"
},
{
"name": "Sliding window algorithm",
"max_score": 8,
"description": "Uses Ratelimit.slidingWindow() rather than fixedWindow, tokenBucket, or other algorithms"
},
{
"name": "Catalog route limit",
"max_score": 7,
"description": "Applies a limit of 100 requests per minute for catalog/product routes (/api/products or /products)"
},
{
"name": "Checkout route limit",
"max_score": 7,
"description": "Applies a limit of 10 requests per minute for checkout routes (/api/checkout or /checkout)"
},
{
"name": "Search route limit",
"max_score": 7,
"description": "Applies a limit of 30 requests per minute for search routes (/api/search or /search)"
},
{
"name": "429 status code",
"max_score": 7,
"description": "Returns HTTP 429 status code when rate limit is exceeded"
},
{
"name": "X-RateLimit headers",
"max_score": 8,
"description": "429 response includes X-RateLimit-Limit and X-RateLimit-Remaining headers"
},
{
"name": "Retry-After header",
"max_score": 8,
"description": "429 response includes a Retry-After header with value computed from reset timestamp"
},
{
"name": "Authenticated user exemption",
"max_score": 8,
"description": "Code or comments indicate that stricter limits apply to unauthenticated requests, or that authenticated users with purchase history receive higher limits"
},
{
"name": "IP-based rate limiting",
"max_score": 7,
"description": "Rate limit key is derived from the client IP (req.ip or x-forwarded-for header), not from a static value"
}
]
}
Rate Limiting for Commerce API Protection
Problem/Feature Description
A fashion retailer's engineering team has noticed that competitors are hitting their product catalog API hundreds of times per minute, harvesting real-time pricing and inventory data. The scraping is causing elevated infrastructure costs and latency spikes that affect real shoppers. Additionally, during recent limited-edition drops, bots are saturating the checkout API, making it near-impossible for human customers to complete purchases.
The team is building a Next.js storefront and wants to add request rate limiting before traffic even reaches their application logic. The goal is to limit abuse at the edge, apply stricter throttling to the most sensitive endpoints, and return responses that well-behaved clients can use to back off gracefully.
Output Specification
Implement rate limiting middleware for the Next.js application. Produce the following files:
middleware.ts— the edge middleware implementing rate limitingpackage.json— listing the required dependencies (no need to run npm install)IMPLEMENTATION_NOTES.md— a brief description of the rate limiting strategy, including how different route types are treated and how the solution handles legitimate customers during flash sales
The implementation should cover at minimum the product catalog, checkout, and search route groups, and should handle the case where legitimate high-volume customers (e.g., authenticated users with purchase history) should not be unnecessarily blocked during peak events.
{
"context": "Tests whether the agent correctly integrates Cloudflare Turnstile as an invisible-first CAPTCHA and implements a properly hidden honeypot field, including correct server-side verification and response codes.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Turnstile over alternatives",
"max_score": 9,
"description": "Uses Cloudflare Turnstile (cf-turnstile widget or challenges.cloudflare.com) rather than reCAPTCHA, hCaptcha, or other CAPTCHA services"
},
{
"name": "Turnstile script source",
"max_score": 7,
"description": "Loads Turnstile via script tag from https://challenges.cloudflare.com/turnstile/v0/api.js"
},
{
"name": "cf-turnstile div",
"max_score": 7,
"description": "Embeds the widget using a div with class cf-turnstile and a data-sitekey attribute"
},
{
"name": "Server-side verification endpoint",
"max_score": 9,
"description": "POSTs the token to https://challenges.cloudflare.com/turnstile/v0/siteverify with secret, response, and remoteip fields"
},
{
"name": "403 on verification failure",
"max_score": 8,
"description": "Returns HTTP 403 (not 400 or 401) when the Turnstile token is missing or verification fails"
},
{
"name": "Passive/invisible-first mode",
"max_score": 8,
"description": "Code or comments indicate the CAPTCHA operates in invisible/passive mode and only escalates to a visible challenge when passive scoring detects suspicious activity"
},
{
"name": "Honeypot CSS hiding",
"max_score": 8,
"description": "Honeypot container is hidden using CSS with position: absolute and left/top set to -9999px (not display:none or visibility:hidden)"
},
{
"name": "Honeypot aria-hidden",
"max_score": 6,
"description": "Honeypot container element has aria-hidden=\"true\""
},
{
"name": "Honeypot input attributes",
"max_score": 8,
"description": "Honeypot input has tabIndex={-1} (or tabindex=\"-1\") AND autoComplete=\"off\" (or autocomplete=\"off\")"
},
{
"name": "Silent discard on honeypot fill",
"max_score": 9,
"description": "When the honeypot field is filled, the form submission is silently discarded (optionally showing a fake success) rather than displaying an error that tips off the bot"
},
{
"name": "Randomized honeypot name",
"max_score": 8,
"description": "Honeypot field name is not a static obvious value like 'website' or 'email2'; uses a randomized or session-specific name"
},
{
"name": "No visible CAPTCHA by default",
"max_score": 7,
"description": "Does NOT configure the CAPTCHA to show a visible challenge widget for every user by default"
},
{
"name": "x-www-form-urlencoded verification",
"max_score": 6,
"description": "Sends the siteverify request with Content-Type: application/x-www-form-urlencoded"
}
]
}
Bot-Resistant Checkout Form
Problem/Feature Description
A consumer electronics retailer has been struggling with bots sweeping through their checkout flow. Their current checkout form has no bot protection at all — bots fill it in milliseconds, create phantom orders, and exhaust stock before human customers can complete a purchase. The security team wants to add a CAPTCHA layer and a simple passive trap to catch unsophisticated bots that blindly fill every form field.
The challenge is to add this protection without degrading the experience for legitimate shoppers: a traditional CAPTCHA puzzle on every checkout attempt would increase abandonment rates significantly. The team wants friction to be invisible for real humans, only escalating to a visible challenge when there are genuine signals of automated behavior. They also want a complementary mechanism that catches the simplest bots at zero cost, but one that isn't trivially defeated by bots that skip commonly-named decoy fields.
Output Specification
Produce the following files implementing the checkout form protection:
components/CheckoutForm.tsx— React component with both the passive bot-detection trap and the CAPTCHA widget embedded in the formlib/bot-check.ts— server-side utility that validates the CAPTCHA token submitted with the form, returning the appropriate HTTP error when validation failsIMPLEMENTATION_NOTES.md— short explanation of each protection mechanism, how they complement each other, and any caveats about configuration (e.g. what environment variables are needed)
The implementation should work with a Next.js App Router project. You do not need to implement the full checkout logic — focus on the bot protection layer.
{
"context": "Tests whether the agent implements scalper-bot behavioral detection using timing and signal analysis, a Redis-backed virtual waiting room with correct FIFO ordering and drain rate, time-limited checkout tokens, and server-side purchase limits with atomic locking.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Page load timestamp",
"max_score": 6,
"description": "Sets window.__pageLoadTime = Date.now() (or equivalent) client-side at page load to record when the session began"
},
{
"name": "Elapsed time to server",
"max_score": 6,
"description": "Sends elapsed seconds (computed from window.__pageLoadTime) to the server as part of the checkout submission"
},
{
"name": "5-second timing threshold",
"max_score": 8,
"description": "Server-side validation rejects or flags checkouts completed in under 5 seconds"
},
{
"name": "Suspicious activity logging",
"max_score": 6,
"description": "Logs flagged sessions with reason 'superhuman_checkout_speed' (or equivalent) rather than silently discarding"
},
{
"name": "Behavioral signals tracked",
"max_score": 8,
"description": "Tracks at least 3 of the following client-side signals: mouseMovements, keystrokes, timeOnPage, focusEvents, scrollDepth"
},
{
"name": "Bot probability score threshold",
"max_score": 7,
"description": "Computes a numeric bot probability score and uses a threshold of 70 (or equivalent) to classify a session as likely-bot"
},
{
"name": "Redis sorted set for queue",
"max_score": 8,
"description": "Waiting room uses a Redis sorted set (ZADD) with Unix timestamp as the score for FIFO ordering"
},
{
"name": "Correct drain rate",
"max_score": 7,
"description": "Waiting room processes 50 customers per minute (drainRate = 50 or equivalent)"
},
{
"name": "10-minute checkout token",
"max_score": 8,
"description": "Granted checkout tokens are stored with a 600-second (10-minute) TTL using SETEX or equivalent"
},
{
"name": "Server-side purchase limit",
"max_score": 8,
"description": "Purchase limit is enforced server-side (database or Redis counter), NOT by client-side state alone"
},
{
"name": "Redis NX lock for race conditions",
"max_score": 9,
"description": "Uses Redis SET with NX flag and an expiry (e.g. 30s) to acquire a purchase lock and prevent concurrent duplicate purchases"
},
{
"name": "Lock key pattern",
"max_score": 7,
"description": "Purchase lock key includes both customer/session identifier and product identifier (e.g. purchase_lock:{customerId}:{productId})"
},
{
"name": "Server-side behavioral analysis",
"max_score": 6,
"description": "Behavioral analysis is validated server-side (not only in client-side JavaScript that can be bypassed)"
},
{
"name": "Session fingerprinting supplement",
"max_score": 6,
"description": "Code or comments indicate that session or device fingerprinting supplements IP-based detection (to handle bots that rotate IPs)"
}
]
}
Fair Launch Protection for Limited-Edition Product Drops
Problem/Feature Description
A streetwear brand is preparing a limited-edition sneaker drop — 500 pairs available at 9 AM. In their last two releases, bots purchased the entire stock within seconds of launch, leaving thousands of legitimate fans empty-handed and generating a PR backlash. The engineering team needs a system that detects automated checkout behavior, gives real customers a fair shot by queuing them, and prevents any single customer from buying more than their allotted quantity regardless of how fast their connection is or how many accounts they register.
The team has a Next.js application with Redis already available. They want to be able to detect bots that complete the checkout process at superhuman speeds or exhibit no human interaction patterns (no mouse movement, no keystrokes, instant form completion). They also want a queuing mechanism for the launch so that customers are admitted to checkout in the order they arrived, not by raw connection speed. Finally, they need purchase limits that can't be defeated by hammering the submit button multiple times concurrently.
Output Specification
Produce the following files:
lib/behavioral-analysis.ts— client-side signal collection and server-side scoring logic that flags sessions exhibiting bot-like behaviorlib/waiting-room.ts— waiting room queue implementation using Redis, including functions to join the queue, compute position/estimated wait, and admit batches of customers to checkoutlib/purchase-limit.ts— server-side purchase limit enforcement with concurrency protectionIMPLEMENTATION_NOTES.md— explanation of how the three components work together, the specific thresholds and limits chosen, and how the solution handles bots that rotate IP addresses
The implementation should be TypeScript and assume a Redis client (redis) is imported from a shared module. You do not need to implement the full checkout flow — focus on these protection layers.
{
"name": "finsi/bot-protection",
"version": "0.1.0",
"summary": "Anti-scraping, anti-scalping, and CAPTCHA strategies for commerce",
"skills": {
"bot-protection": {
"path": "SKILL.md"
}
}
}