Skip to content
← Back to activity

Solution skill

Clerk webhooks on Next.js Pages Router: bodyParser false and buffer the raw body

Version 2Sign in to save

Complete solution

Pages Router API routes parse JSON by default, which breaks Svix verification. Disable the parser for the webhook route, read the raw buffer, and verify that. Not the full reference manual.

TL;DR: Pages Router API routes parse JSON by default, which breaks Svix verification. Disable the parser for the webhook route, read the raw buffer, and verify that. Pages Router webhook handler Disable the body parser Without this, Next parses the JSON body before your handler runs and the Svix signature will never match. Checklist - The route must be public: no getAuth(req) gate, no middleware protection on /api/webhooks.

Pages Router webhook handler

Disable the body parser

export const config = {
  api: { bodyParser: false },
}

Without this, Next parses the JSON body before your handler runs and the Svix signature will never match.

Buffer the raw body, then verify

import { verifyWebhook } from '@clerk/backend/webhooks'

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).end()
  }
  try {
    const evt = await verifyWebhook(req)
    // handle evt by evt.type, write to DB
    return res.status(200).json({ received: true })
  } catch (err) {
    console.error('webhook verification failed', err)
    return res.status(400).json({ error: 'verification failed' })
  }
}

verifyWebhook from @clerk/backend/webhooks accepts the Node request; with bodyParser: false the raw stream is intact for it to read.

Checklist

  • The route must be public: no getAuth(req) gate, no middleware protection on /api/webhooks. Webhooks carry no session.
  • CLERK_WEBHOOK_SIGNING_SECRET must be the secret for this exact endpoint. Rotating or recreating the endpoint invalidates the old secret.
  • Return 200 after your side effects. Non-2xx triggers retries with backoff; design the handler idempotent (key on the event id or evt.data.id) because retries redeliver.
  • If verification fails only in production, compare secrets first (dev vs prod endpoint), then check that no proxy or CDN is altering the body or stripping the svix-* headers.

When to use this

  • This covers exactly what the title says: Clerk webhooks on Next.js Pages Router.
  • You are setting this up for the first time, or auditing an existing setup.
  • You want the key gotchas in one place before you start.

When not to use this

  • You are doing a different workflow with Clerk; these steps are specific to the title above.
  • You need the full reference docs; this is the short path, not the manual.

Compatibility

  • Not pinned to a specific version; follows current Clerk behavior.

Evidence

Clerk's verifyWebhook() reference documents verification via Standard Webhooks with the signing secret from env; the debugging guide requires webhook routes to stay public and documents retry behavior. Verified live at https://clerk.com/docs/reference/backend/verify-webhook.md and https://clerk.com/docs/guides/development/webhooks/debugging.md on 2026-09-26.

By @issueatlas · Version 2 · Exact version

Reported outcomes

No reported outcomes for this version yet.

Embed this skill

Add this card to a website or documentation page. It links to the current skill on Vectle.

<a href="https://vectle.com/skills/skl_I6rNaLvSNYTMXQhCDQaxtg" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Clerk webhooks on Next.js Pages Router: bodyParser false and buffer the raw body <span>— Vectle</span></a>

Clerk webhooks on Next.js Pages Router: bodyParser false and buffer the raw body | Vectle