Skip to main content
友田 陽大
Vercel in production
Vercel
セキュリティ
WAF
DDoS
Next.js
可観測性
B2B SaaS

Vercel Firewall × WAF × BotID implementation guide: protect the entrance with DDoS mitigation, custom rules, rate limiting, and an invisible CAPTCHA

A platform-layer security implementation guide faithful to Vercel's official docs. With real code, it explains automatic DDoS mitigation, Vercel WAF custom rules (allow/deny/challenge/log/rate limit), IP blocking and managed rule sets, 300ms global propagation and instant rollback, BotID (invisible CAPTCHA, Basic/Deep Analysis) client/server instrumentation, and Attack Challenge Mode.

Published
Reading time
7 min read
Author
友田 陽大
Share

Security is the area where it's most cost-efficient to make it effective at the entrance, "before writing app code." Vercel has three layers at the platform level — DDoS mitigation, WAF, BotID — letting you trim the attack surface with minimal code changes. This article summarizes how to defend the entrance with real code, faithful to the official specs of Vercel Firewall, Vercel WAF, and BotID.

For the full picture, see the Vercel production-operations guide.

An important premise: this article is about platform-layer (entrance) security. App-layer authorization, RLS, and injection defense (IDOR/SQLi/XSS/SSRF) can't be protected by a WAF. They're separate layers, designed as both wheels. For the app layer, see Next.js × Supabase application-layer security.


The role division of the three layers

LayerWhat it protectsPlan
DDoS mitigationExhaustion attacks via mass requestsAll plans (automatic, free)
WAFBlocking/challenging/rate-limiting/IP-blocking malicious requestsHobby/Pro/Enterprise (scale differs)
BotIDAdvanced bots posing as humans (scraping, credential stuffing)Basic free on all plans / Deep Analysis Pro·Ent

On the foundation of "DDoS mitigation that works broadly and automatically," layer "WAF that controls narrowly with rules" and "BotID that distinguishes human/bot" — this is the entrance's defense in depth.


DDoS mitigation: automatic on all plans

Vercel's DDoS mitigation works automatically on all plans. With no configuration, it absorbs mass L3/L4/L7 requests. When an attack is severe, use the Attack Challenge Mode described below alongside. This is a state where "the foundation is protected even without doing anything," and you add intentional control here with WAF and BotID.


Vercel WAF: entrance rules that propagate in 300ms

Vercel WAF is a mechanism that monitors and controls traffic to the site by logging, blocking, and challenging. Its biggest feature is operability — setting changes propagate globally in 300ms, and on a problem you can instantly roll back from the audit log (WAF docs).

Three control means

MeansContent
IP blockBlock specific IPs/CIDRs
Custom rulesDeclarative condition → action rules
Managed rule setsOff-the-shelf rule groups like OWASP (Enterprise)

Limits by plan

FeatureHobbyProEnterprise
Project IP blocksUp to 3Up to 100Up to 1000
Custom rulesUp to 3Up to 40Up to 1000
Managed rule setsYes

How to think about custom rules

A custom rule ties an "action" to a "condition (path, IP, region, request header, User-Agent, JA4, etc.)." The actions are —

  • Allow: let through (allowlist)
  • Deny: block
  • Challenge: challenge (verify human)
  • Log: record only (observe first, then tighten)
  • Rate Limit: limit by count per period

The iron rule in practice is "observe with Log first → confirm the impact → escalate to Deny/Challenge." Avoid the incident of jumping straight to Deny and catching legitimate users. With 300ms propagation and instant rollback, this "observe then tighten" operation runs safely.

Rate limiting: stop abuse structurally

For high-value routes prone to abuse like login and search, use WAF rate limiting to Challenge/Deny when "N times/minute from the same IP" is exceeded.

Relationship with Fluid Compute: in-app rate limiting (a memory counter) doesn't work correctly on serverless (since instances are shared/distributed). Use WAF rate limiting that works at the entrance, or distributed rate limiting with Upstash (Redis). WAF rate limiting works before the function is called, so it also prevents Active CPU billing.

Configuration and rollback (the operations flow)

ダッシュボード → プロジェクト → Firewall
  ① Custom Rule を Log で追加 → トラフィックを観測
  ② 影響を確認したら Deny / Challenge / Rate Limit へ昇格(300msで反映)
  ③ 誤遮断が出たら View Audit Log → 過去構成へ Restore(即時ロールバック)

You can also stage rules in the CLI and apply them in bulk (vercel firewall). Suited to teams that want to review and apply rules in an Infrastructure-as-Code manner.

Attack Challenge Mode: the emergency valve during an attack

When an attack is severe, turning Attack Challenge Mode ON imposes a temporary challenge on all visitors and greatly reduces automated traffic. Legitimate users get a minor confirmation, and you turn it OFF once the attack subsides. A two-stage setup: "precise rules in peacetime, one mode toggle in an emergency."


BotID: invisible CAPTCHA

A "pick the images" UI like reCAPTCHA hurts UX while getting broken by advanced bots. BotID is an invisible CAPTCHA based on Kasada — without user interaction, it detects bots "posing as humans" like Playwright/Puppeteer (BotID docs).

Two levels and pricing

LevelContentPlanPricing
BasicVerifies the integrity of the challenge response. Catches many simple botsAll plansFree
Deep AnalysisAnalyzes thousands of client signals with ML. Handles the most advanced botsPro / EnterprisePro: $1 / 1000 checkBotId() calls, Ent: custom

Billing originates from the checkBotId() call. Passive page views aren't billed. So calling checkBotId() only on high-value routes is cost-optimal.

Instrumentation: two points, client + server

BotID is two-point instrumentation: "set up the challenge on the client, verify on the server."

// ① クライアント側:保護したいルートのチャレンジを初期化
// app/providers.tsx ("use client")
"use client";
import { initBotId } from "botid/client";

initBotId({
  protect: [
    { path: "/api/checkout", method: "POST" },
    { path: "/api/signup", method: "POST" },
  ],
});
// ② サーバー側:高価値エンドポイントで検証して分岐
// app/api/checkout/route.ts
import { checkBotId } from "botid/server";

export async function POST(request: Request) {
  const verification = await checkBotId(); // ← Deep Analysis課金はここで発生

  if (verification.isBot) {
    return new Response("Forbidden", { status: 403 });
  }

  // 人間と判定された場合のみ本処理へ
  return handleCheckout(request);
}

checkBotId() runs Deep Analysis (when configured) after passing Basic verification and returns the result (isBot, etc.). Put it in only on routes where "being trashed by bots causes damage," like checkout, signup, inquiries, and inventory APIs.

Verified bots, bypass, and observability

  • Legitimate bots like search engines can be let through with an allowlist (Verified Bots).
  • On a false positive, you can let them through with a WAF bypass rule that detours the BotID judgment.
  • BotID checks can be visualized in the Firewall tab's traffic filter or Observability Plus.

Environment variables and OIDC: don't put secrets at the entrance

As important as entrance defense is "not leaking secrets to code/clients."

  • Put API keys and DB connection strings into environment variables. The NEXT_PUBLIC_ prefix is exposed to the browser, so don't attach it to secrets (env-leak prevention).
  • Don't place long-lived access keys for external clouds; obtain temporary credentials keylessly via OIDC.
  • On Fluid Compute, don't put user-specific data in global state (preventing tenant crossing; Functions guide).

Production checklist (entrance security)

  • DDoS mitigation is working (automatic). Share the Attack Challenge Mode procedure for attacks
  • Introduce WAF custom rules in the order observe with Log → escalate
  • WAF rate limiting on high-value routes (stop before the function is called)
  • Confirm the audit log → instant rollback procedure for false blocks
  • BotID on checkout/signup, etc., with checkBotId() limited to the target routes
  • Allow legitimate bots, rescue false positives with WAF bypass
  • Secrets in environment variables, no secrets in NEXT_PUBLIC_, external via OIDC
  • App-layer security (authorization/RLS/injection) designed separately (a WAF can't protect it)

Summary

Vercel's platform-layer security is defense in depth of "broad automatic DDoS mitigation" + "narrow precise WAF" + "BotID that distinguishes human/bot."

  1. DDoS mitigation is the foundation (automatic on all plans)
  2. WAF tightens safely via Log→escalate, operated with 300ms propagation and instant rollback
  3. Rate limiting at the entrance (also protects Active CPU)
  4. Limit BotID to high-value routes and narrow the billing-originating checkBotId()
  5. WAF doesn't replace app-layer authorization/injection defense — both wheels

Next, head to the storage, Blob, and Edge Config guide for placing state.

This article is based on the Vercel Firewall / Vercel WAF / BotID official documentation (as of June 2026). Specs, limits, and pricing are updated, so confirm the latest values officially at production adoption.

友田

友田 陽大

Developer of a METI Minister's Award–winning product. With TypeScript + Python + AWS, I deliver SaaS, industry DX, and production-grade generative AI (RAG) end to end — from requirements to infrastructure and operations — single-handedly.

I can take on the implementation from this article as an engagement

Vercel apps, from design to production and cost optimization

Function design assuming Fluid Compute (safe global state, waitUntil, Cron), four-layer caching (ISR/CDN/Runtime Cache/Cache Components), safe deploys (preview/Promote/Instant Rollback/Rolling Releases), entry-point defense (Firewall/WAF/BotID), storage selection (Blob/Edge Config/Marketplace), and Active-CPU-billing-aware cost optimization. With experience running Next.js products on Vercel in production, I deliver fast, cheap, and secure.

Available for both project-based (contract) and advisory engagements. Start with a free 30-minute consult.

Also worth reading