Over Black Friday and Cyber Monday 2025, our network handled 115.8 billion requests, applied more than 7.5 billion firewall actions, and blocked more than 415 million bot attempts. Those defenses fired across checkout flows, inventory endpoints, and account systems. A headless storefront assembles all three from parts that fail differently, which makes storefront security a layering problem. This guide walks through the five layers a storefront exposes, the controls that cover each one, and where payment scope lands in the architecture.
Key takeaways:
A headless storefront exposes five attack layers, and no single control covers more than one or two of them.
Managed rulesets on a web application firewall (WAF) match known signatures. Credential stuffing and browser-mimicking bots fall to behavioral detection.
Rate limits count requests against an IP or JA4 Digest without checking whether a human sent them, so a distributed run never trips one.
A compliant processor's payment iframe keeps account data off your infrastructure and supports Self-Assessment Questionnaire (SAQ) A eligibility, which your acquirer confirms and your host cannot.
Third-party scripts run on your checkout page with your own code's privileges. Version 4.0 of the Payment Card Industry Data Security Standard (PCI DSS) added requirements specifically to close that gap.
Copy link to headingWhat is ecommerce security for a headless storefront?
Ecommerce security is the set of controls that keep a storefront's traffic, accounts, payment path, and data intact while it's under active attack. On a headless architecture, those controls sit somewhere other than where a hosted platform puts them, because the storefront is a set of components you assembled rather than one application a vendor secured.
A monolithic platform puts the catalog, the cart, the account system, and the payment page behind one perimeter. A headless build puts a CDN in front, serverless functions behind it, a payment iframe inside the checkout page, and third-party tags alongside your own bundle. Each has its own failure mode, and a control that works on one is inert on the next.
Copy link to headingThe five layers of a headless storefront's attack surface
Splitting the surface by layer stops teams from buying the same protection twice while a layer sits bare. The last column names the control that belongs there first:
The layer that gets under-defended is almost always the app layer, because nobody files their own application code under the attack surface.
Copy link to headingWhy the conventional peak-readiness plan is ordered wrong
The standard pre-peak plan puts volumetric distributed denial-of-service (DDoS) at the top of the risk list. Firewall data from retail peak points at application-layer automation instead. A flood is loud, lands on infrastructure that already absorbs it, and costs the attacker real money. A credential-stuffing run is quiet, arrives at ordinary request volumes, and costs the attacker a proxy subscription.
What reaches your functions reinforces that ordering. Automatic mitigation catches volumetric floods on its own, but bot and crawler traffic is rarely classified as an attack, so it arrives as ordinary load until you configure something to catch it. The quietest attacks are the ones your infrastructure absorbs by default.
Copy link to headingThe core ecommerce security controls, and what each one misses
Six controls sit across those five layers. Most have a documented blind spot, and that gap tells you which control to add next and which one you're wasting time tuning.
Your plan sets the starting shape of that stack, per the firewall limits:
Copy link to headingWhat a WAF managed ruleset catches, and what it leaves out by design
The Open Worldwide Application Security Project (OWASP) Core Ruleset matches requests against known patterns for SQL injection, cross-site scripting (XSS), and the rest of the OWASP Top Ten, on Enterprise plans only. Managed rulesets run after your own custom rules, so a bypass rule you write takes precedence over anything the ruleset would have blocked.
Credential stuffing, business logic abuse, IDOR, and browser-mimicking scraping have no stable signature, so no managed ruleset covers them. Pro storefronts without managed OWASP coverage put custom rules on the riskiest routes and rely on behavioral detection for the rest. Rule changes propagate worldwide in 300 milliseconds. A rule shipped in Log mode mid-incident and tightened afterward needs no deploy.
Copy link to headingBot detection for automation that solves CAPTCHAs
Sophisticated bots run JavaScript, solve challenges, and browse like a shopper. User-agent strings and IP reputation have nothing left to act on. BotID closes that gap with an invisible challenge powered by Kasada, generally available since 25 June 2025. It collects thousands of client-side signals and changes its detection code on every page load, so a working bypass doesn't replay. Attack data from one project sharpens the model for every team on the network.
Basic validation runs on all plans and catches unsophisticated automation. Deep Analysis adds a machine learning model over the collected signals once Basic passes, and it engages only on requests that call checkBotId().
The cost is the integration surface. checkBotId() classifies non-browser clients as bots, including curl, native form posts, and server-to-server calls, and your handler decides what happens next. Partner integrations hitting those routes need their own path. Inventory hoarding is the bot pattern that hits limited-stock storefronts hardest, and it gets its own treatment in [RESERVED — W28 inventory-bot spoke].
Copy link to headingRate limits protect endpoints without knowing who sent the request
A costly assumption to carry into peak is that a rate limit is bot protection. A rate limit counts requests against a key, such as an IP address or JA4 Digest, and no counting algorithm checks whether a human sent the request. An attacker distributing a run across residential proxies never trips the counter on any single identity. Counters are also tracked per region. One key spread across regions can exceed your configured limit in aggregate.
Rate limits still belong first on high-value routes, because they apply immediately and a mitigated request never reaches your functions. Each limit should answer the abuse it's there to stop:
Copy link to headingAccount takeover on an ecommerce login route is an identity problem
Account takeover usually arrives by credential stuffing, which replays username and password pairs from someone else's breach against your login route. It is not how most retail intrusions begin, though. Exploited vulnerabilities now open 42% of retail breaches, compared with 14% for credential abuse.
That reordering hides where credential abuse still does its work. Counted at any point in the breach chain, it appears in 39% of breaches in all sectors, and credentials are among the data stolen in 26% of retail cases. A run spending one attempt per identity produces no volume signal at all, and per-IP thresholds miss it completely.
Multi-factor authentication (MFA) carries the heaviest evidence of any control here, reducing account compromise risk by 99.22% across a measured population and 98.56% for accounts whose credentials had already leaked. Which factor you pick still matters, since SMS codes remain phishable while passkeys resist phishing by design. No lookup against breached-password databases runs at the firewall layer either, and NIST SP 800-63B requires checking new passwords against a compromised-password blocklist, so that check belongs in your identity provider.
Copy link to headingDDoS protection for an ecommerce storefront: absorbed versus configured
DDoS mitigation covers Layer 3, Layer 4, and Layer 7 on every plan, with no configuration. Protectd, our real-time security engine, brought time to mitigation to a P99 of 3.5 seconds and a P50 of 2.5 seconds, with a floor of 0.5 seconds. The out-of-band pipeline it fronts often takes more than 20 seconds on its own.
You configure the rest, mostly to keep mitigation from catching traffic you need:
Of those, System Bypass Rules are the ones to write early and Attack Mode is the one to rehearse, both for reasons the pre-peak sequence covers.
Copy link to headingThird-party scripts are the gap PCI DSS v4.0 was written to close
An attacker who compromises a vendor you already trust infects every site loading that vendor's script. The polyfill supply chain attack hit cdn.polyfill.io, a script embedded in more than 100,000 sites. The domain changed hands in February 2024 and began serving malicious code in June 2024.
PCI DSS v4.0 answered with an authorized script inventory enforced through CSP and SRI, plus tamper detection on payment page content as the browser receives it. In Next.js, you generate a per-request nonce in Proxy and set it on the Content-Security-Policy header, and the framework propagates it to its own bundles and inline scripts automatically. Anything without the nonce is blocked.
Nonces carry a real cost. They require dynamic rendering, which disables Incremental Static Regeneration (ISR) and takes your storefront off CDN caching. Hash-based SRI keeps static generation instead, and Turbopack has supported it since Next.js 16.2, still behind an experimental flag as of 16.3.
Copy link to headingWhere PCI scope lands in your ecommerce security architecture
No control over the storefront changes what your acquirer asks you to validate. Architecture decides that, specifically, where the payment page's elements originate.
When every element of that page comes from a compliant third-party service provider through an iframe or a redirect, you're in SAQ A territory. That holds only while your own systems never store, process, or transmit account data, and a single field posting card details through your API breaks it. A site that's partially outsourced but can still affect the security of the payment transaction falls under SAQ A-EP, a considerably longer assessment. Scope follows the code that can reach the payment page, not the code that renders the rest of the storefront. That decision belongs in architecture review, and it should be settled long before an assessor asks how you collect card data.
Hosted fields or an iframe from a compliant processor keep account data on a path from the browser to the processor that never crosses your application infrastructure, so a compromise of your own functions exposes no card data. Major processors each publish guidance on which of their integrations qualify for SAQ A when implemented according to their instructions, and reading it beats assuming an embed is in scope. Since 1 April 2025, SAQ A eligibility drops requirements 6.4.3 and 11.6.1 but adds a requirement to confirm the site isn't susceptible to script attacks affecting the payment system. You satisfy that by running those controls anyway or by getting written confirmation from your provider. That confirmation applies to embedded and iframe payment forms and not to a full redirect, so the two integration styles carry different evidence burdens even though both sit inside SAQ A.
We hold an SAQ D Attestation of Compliance (AOC) for Service Providers and an SAQ A AOC for Merchants under PCI DSS v4.1, and those attestations cover our infrastructure. Yours is a separate assessment. Running a storefront here certifies nothing about your posture, and your acquiring bank confirms which validation applies to how you collect payment data. A correctly built payment iframe holds that boundary in place day to day, and firewall rules can carry assessor-facing evidence for the controls in scope.
Copy link to headingEcommerce security best practices before a peak traffic event
Sequence carries as much weight here as coverage. Each step surfaces something the next one needs, and any of them can be walked back before the window opens.
Copy link to headingTurn every new control on in Log mode first
Enabling Bot Protection in Challenge mode a week out is how a storefront ends up filing a support ticket mid-peak. Run it in Log mode first, read what it flags against real traffic, and switch to Challenge once the flagged set contains nothing you recognize. Log mode carries one catch. Requests actioned as log or bypass are excluded from Drains. A control in Log mode is visible only in firewall traffic monitoring.
Copy link to headingPut behavioral detection on the routes that cost money
Managed rulesets and rate limits go everywhere. Deep Analysis belongs on the routes where a bot getting through is expensive, which, on a storefront, means checkout and login before anything else. The preview deployment rehearsal is easy to skip, and it's the one that catches an integration path breaking on checkBotId() before a shopper does.
Copy link to headingWrite your bypass rules before you need them
System Bypass Rules for monitoring services and partner webhooks go in while nothing is on fire, because a rule written during an incident is written without evidence. Major payment providers are already handled, since Stripe, Adyen, PayPal, and Razorpay webhooks sit in our verified bot directory and pass through without being challenged. Your own uptime checks, warehouse and fulfillment integrations, and internal tooling are not, and a blocked fulfillment callback looks like a successful order until the warehouse never ships it.
Copy link to headingTurn on the visibility you will want afterward
Three things go live together here: firewall events routed to your security information and event management (SIEM) system through Drains, Spend Management alerts set before the peak window opens, and the Attack Mode toggle tested in staging with your API routes and payment webhooks running. None of this covers capacity. The caching and load testing work runs before the same window and belongs on its own checklist. A timed drop against limited stock needs one more control on top. No firewall rule meters admission, which is the job a virtual waiting room exists to do.
Copy link to headingHow Vercel powers ecommerce security for headless storefronts
The layering problem is the same on any platform. The difference is how much of it you assemble yourself.
Copy link to headingFirewall rules that ship without a deploy
A new attack pattern surfaces at 2 am, and a deploy-to-respond loop costs you the incident. The Vercel WAF keeps rules out of your application entirely. You publish them from the dashboard, CLI, or API, and your deployment stays untouched. Pro teams get 40 custom rules on top of the bot rulesets available on every plan, and Enterprise adds the OWASP Core Ruleset.
Copy link to headingBot detection that doesn't degrade the storefront
A visible CAPTCHA on a checkout page adds friction for every real shopper in order to stop the automated ones. BotID runs invisibly and engages only on the routes you instrument, concentrating protection where inventory and revenue sit. A checkout route earns the same treatment as any expensive endpoint, because every automated call against it consumes compute you provisioned for buyers.
One deployment choice decides how well any of it works. Bot Protection loses accuracy behind a reverse proxy. A storefront running another CDN in front of Vercel gets degraded detection, plus repeated challenges as proxy IPs rotate.
Copy link to headingRate limits on identities the firewall can't see
A logged-in abuser rotating IP addresses is invisible to a firewall counting on IP or JA4 Digest, because the identity that matters lives inside your session. The @vercel/firewall package moves the counter into your function while keeping the rule in the dashboard.
The identity you want to bucket on becomes the rate limit key:
import { checkRateLimit } from '@vercel/firewall';import { authenticateUser } from './auth';
export async function POST(request: Request) { const auth = await authenticateUser(request); const { rateLimited } = await checkRateLimit('checkout-attempt', { request, rateLimitKey: `${auth.orgId}:${auth.userId}`, }); if (rateLimited) { return new Response(JSON.stringify({ error: 'Rate limit exceeded' }), { status: 429, headers: { 'Content-Type': 'application/json' }, }); }
// Handle the checkout attempt. return Response.json({ ok: true });}The key you pass replaces the per-IP bucket rather than adding to it, so a constant string turns the rule global. Compose the caller's IP or user ID into the key when you want per-caller separation.
Copy link to headingFirewall visibility in the tools your team already watches
A security signal nobody sees during an incident is worth nothing. Firewall events stream to your existing SIEM through Drains on Pro and Enterprise, and the Firewall dashboard groups live traffic by rule, so you can confirm a change does what you intended before tightening it. Those same rules can seed a honeypot that only automation ever requests, which turns the dashboard into a tripwire rather than a report.
Copy link to headingTake your storefront into peak with every layer already accounted for
Storefronts come through peak intact because somebody prepared for it, mapped each layer to the control that covers it, and knew before traffic arrived what each control leaves bare. A managed ruleset that catches injection says nothing about the credential-stuffing run on your login route, and a per-IP limit that holds against one attacker collapses against a distributed one.
How much of that mapping falls to your team depends on the stack underneath. Some layers arrive covered, some need a rule you write, and the payment boundary is settled in architecture before either question comes up. What you owe depends on your traffic shape, your inventory model, and what your acquirer already asks you to validate.
The platform covers part of that mapping, and the split runs like this:
Vercel WAF: Custom rules on every plan and the OWASP Core Ruleset on Enterprise, published from the dashboard, CLI, or API and live across the network in 300 milliseconds without a deploy.
BotID: Basic validation on every plan, and Deep Analysis on Pro and Enterprise, invisible to shoppers and instrumented per route rather than site-wide.
WAF rate limiting and
@vercel/firewall: Limits at the network edge on the keys your plan exposes, plus in-function limits keyed on a user or organization ID the firewall never sees.Always-on DDoS mitigation with Protectd: L3, L4, and L7 coverage on every plan, with a P99 time to mitigation of 3.5 seconds and no configuration to maintain.
Firewall observability and Drains: Live traffic grouped by rule for everyone, and event streaming to your own SIEM on Pro and Enterprise, so peak-window forensics happen in one place.
Start a new project to build a storefront with these controls available from the first deploy, or browse the templates for a commerce starting point already wired for production traffic.
Copy link to headingFrequently asked questions about ecommerce security
Copy link to headingShould I run another CDN in front of Vercel for ecommerce security?
Usually not. A second CDN duplicates work Vercel already does at the edge, and it costs you accuracy in Bot Protection, which reads client signals that a reverse proxy masks. If you run one anyway for reasons outside security, such as an existing contract or a legacy DNS setup, lean on BotID at the application layer, since it validates in the browser and survives the proxy.
Copy link to headingDoes blocking bot traffic reduce load on a storefront?
Only once you configure it. Automatic mitigation targets volumetric attacks, and ordinary scraping or credential-stuffing volume passes straight through to your functions. A managed ruleset or a rate limit turns that traffic into a load you never serve.
Copy link to headingHow far ahead of a peak event should security changes go live?
Rules deploy in milliseconds, so the constraint is observation, not deployment. Give each new control at least two full weekly cycles in Log mode, enough to cover two weekends and any scheduled partner jobs, before switching it to Challenge or Deny.
Copy link to headingDoes bot protection slow down checkout?
Not measurably. The challenge runs in the browser while the shopper is already on the page, and firewall rules execute before your function is invoked. Neither adds server time to the order. The latency worth watching on a checkout path is your payment provider's, not the bot check's.