Back to roadmaps clerk Course

Syncing Clerk User Data with Webhooks

To store user profile records in your database (for SQL relationships), configure a webhook. When a user registers, Clerk sends a secure HTTP POST request containing profile metadata to your backend API.


1. Setting Up a Webhook endpoint in Next.js

Clerk uses Svix to sign webhooks. Install the verification library in your project:

# Install Svix package for webhook header signature checks
npm install svix

Configure a Next.js API route to receive Clerk event calls:

// app/api/webhooks/clerk/route.ts
import { Webhook } from "svix";
import { headers } from "next/headers";
import { WebhookEvent } from "@clerk/nextjs/server";
import { prisma } from "../../../lib/prisma";

export async function POST(req: Request) {
  const SIGNING_SECRET = process.env.CLERK_WEBHOOK_SECRET;

  if (!SIGNING_SECRET) {
    throw new Error("Missing CLERK_WEBHOOK_SECRET environment config");
  }

  // 1. Retrieve the Svix signing headers
  const headerPayload = await headers();
  const svix_id = headerPayload.get("svix-id");
  const svix_timestamp = headerPayload.get("svix-timestamp");
  const svix_signature = headerPayload.get("svix-signature");

  if (!svix_id || !svix_timestamp || !svix_signature) {
    return new Response("Missing svix headers", { status: 400 });
  }

  // Get raw request body bytes
  const payload = await req.json();
  const body = JSON.stringify(payload);

  const wh = new Webhook(SIGNING_SECRET);
  let evt: WebhookEvent;

  // 2. Verify webhook signature
  try {
    evt = wh.verify(body, {
      "svix-id": svix_id,
      "svix-timestamp": svix_timestamp,
      "svix-signature": svix_signature,
    }) as WebhookEvent;
  } catch (err) {
    console.error("Webhook verification failed:", err);
    return new Response("Verification error", { status: 400 });
  }

  // 3. Process events payload
  const eventType = evt.type;

  if (eventType === "user.created") {
    const { id, email_addresses, image_url } = evt.data;
    const email = email_addresses[0]?.email_address;

    // Save profile to database using Prisma
    await prisma.user.create({
      data: {
        clerkId: id,
        email: email,
        avatarUrl: image_url,
      },
    });

    console.log(`Saved new user profile to database: ${id}`);
  }

  return new Response("Success", { status: 200 });
}

2. Registering Webhooks in Clerk Control Panel

  1. Go to the Clerk Dashboard -> Webhooks -> Add Endpoint.
  2. Paste your API route URL (for example, https://your-domain.com/api/webhooks/clerk).
  3. Under Subscribe to events, select user.created and user.updated.
  4. Click Create.
  5. Copy the generated Signing Secret and add it to your local environment file:
CLERK_WEBHOOK_SECRET="whsec_..."
Published on Last updated: