DNAbyD3Docs
Middleware

Vercel

Routing Middleware for any framework on Vercel. Install, configure, verify.

The Vercel middleware is Routing Middleware: a root middleware.ts that works with any framework on Vercel. It checks each request before your pages run, and lets it through or returns a 403. No DNS change.

Requirements

Install

  1. Install the package:

    npm install @d3-inc/d3-edge-vercel-middleware
  2. Create middleware.ts at the root of your project:

    import { createD3Middleware, config } from '@d3-inc/d3-edge-vercel-middleware';
    
    export default createD3Middleware();
    export { config };
  3. Set DNA_API_KEY in your Vercel project to the key from API keys (created here). Keep it in the secret store, not in code.

  4. Deploy, then verify the install.

Local development

Leave DNA_API_KEY unset locally and set it only in the deployed environment. Unset, the middleware is a passthrough: it makes no network calls and marks every response x-d3-edge: disabled, which confirms it loads.

Configuration

Set each option as an argument to createD3Middleware() or as an environment variable. Arguments take precedence.

These need @d3-inc/d3-edge-vercel-middleware 0.8.0 or later.

OptionEnv varTypeDefaultDescription
apiKeyDNA_API_KEYstringunsetYour organization's API key. Unset: passthrough; the middleware does nothing.
enabledDNA_ENABLEDbooleantruefalse turns DNA off without removing the key. Any other value leaves it on.
failModeDNA_FAIL_MODE"open" | "closed"openopen: a request with no decision in time goes through. closed: it gets a 403.
timeoutMsDNA_TIMEOUT_MSnumber (ms)2000Cutoff for a decision.
paymentTimeoutMsDNA_PAYMENT_TIMEOUT_MSnumber (ms)10000Budget for a request that presents a payment, which settles inside the call.
endpointDNA_ENDPOINTstring (URL)https://edge-api.d3.com/v1/decisionDecision endpoint. Leave unset unless we give you another.
debugLogRawPayloadDNA_DEBUG_LOG_RAW_PAYLOADbooleanfalseDebug only: forwards every header but Authorization and Cookie for the request record.
  • With failMode: open (the default), a request with no decision within timeoutMs goes through to your site.
  • With failMode: closed, it gets a 403 instead.
  • A request that presents a payment and gets no decision within paymentTimeoutMs gets a 502, never the page. A refused payment is a 402; see Pay with x402.

Earlier names

Installs set up with the earlier names keep working unchanged, and a new name wins when both are set. With the earlier names, POLICY_WORKER_URL is still what switches DNA on. DEBUG_LOG_RAW_PAYLOAD is read only while POLICY_WORKER_URL is set.

Earlier nameNow
POLICY_ADAPTER_KEY, adapterKeyDNA_API_KEY, apiKey
POLICY_SHARED_SECRET, sharedSecretDNA_API_KEY, apiKey
POLICY_WORKER_URL, policyWorkerUrlDNA_ENDPOINT, endpoint, now optional
POLICY_TIMEOUT_MSDNA_TIMEOUT_MS
POLICY_PAYMENT_TIMEOUT_MSDNA_PAYMENT_TIMEOUT_MS
FAIL_MODEDNA_FAIL_MODE
DEBUG_LOG_RAW_PAYLOADDNA_DEBUG_LOG_RAW_PAYLOAD

To move over, update the package to 0.8.0 or later, then rename each variable and drop POLICY_WORKER_URL. If you turned DNA off by leaving POLICY_WORKER_URL unset, set DNA_ENABLED=false first: DNA_API_KEY switches DNA on by itself.

Matcher

  • The exported config matcher excludes Vercel's build assets: _next/static, _next/image, favicon.ico.
  • Files served from public/ are not excluded by default.
  • To check a signed upload, DNA reads the request body. Leave large-upload routes out of the matcher.

Response shape

Every response that passes through the middleware has an x-d3-edge header: disabled, pass, block, fail-open, fail-closed, payment-required, payment-redirect, or payment-stub. The payment-* values appear only on access and pricing.

A blocked request gets a 403 with a JSON body:

{ "blocked": true, "ruleId": "…", "tier": "…", "identity": "…" }

ruleId names the rule under Rules that stopped the request.

Existing middleware

Vercel runs one middleware.ts per project. Tell us what yours does and we'll help you combine the two.

Troubleshooting

SymptomCauseFix
Nothing in the logDNA_API_KEY unset in the deployed environment (silent passthrough), or the key is rejectedSet the variable. Check Vercel logs for lines prefixed policy call rejected:, which include the HTTP status and reason.
401 with unknown-key, expired, or revokedThe key is wrong, past its expiry, or revoked in the dashboardCreate a new key and update the secret.
503 with not-configuredYour organization's keys are still being set upIf it persists more than a few minutes, contact us.
Middleware doesn't runNot middleware.ts at the project root with a default export, or a custom matcher that misses the routeFix the file location and export. If you replaced config, confirm your matcher covers the routes you're testing.

On this page