Debug your webhooks

Developing with webhooks can be a new experience for developers. It can be hard to debug when something goes awry. This guide will cover the basics for debugging and help you to direct your attention to the correct spot.

Webhooks and local development

When you or a user of your application performs certain actions, a webhook can be triggered. You can see the full list of webhook events for a list of the actions that could result in a Webhook. Depending on the events subscribed to in the Webhook section of the Clerk Dashboard, a webhook event will be triggered and sent to the specified endpoint in your application.

When you are developing on your localhost, your application is not internet facing and can't receive the webhook request. You will need to use a tool that creates a tunnel from the internet to your localhost. These tools will provide temporary or permanant URLs depending on the tool and the plan you subscribe to. Popular tools include ngrok, localtunnel and Cloudflare Tunnel.

This guide will address common issues that arise when developing with webhooks and how to debug them.

Check your Middleware configuration

Incoming webhook events will never be signed in -- they are coming from a source outside of your application. Since they will be in a signed out state, the route should be public.

The following example shows the recommended Middleware configuration for your webhook routes.

import { clerkMiddleware } from '@clerk/nextjs/server';

// Make sure that the `/api/webhooks/(.*)` route is not protected here
export default clerkMiddleware()

export const config = {
  matcher: [ '/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
import { authMiddleware } from "@clerk/nextjs";

export default authMiddleware({
  ignoredRoutes: ["/api/webhooks(.*)"],

export const config = {
  matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/", "/(api|trpc)(.*)"],

Test the Route Handler or API Route

If you are having trouble with your webhook, you can create a basic Route Handler and then test it locally. First, add the following file and code to your app.

If you're having trouble with your webhook, you can create a basic response and then test it locally.

  1. Create a test route in your application:
    export async function POST() {
        return Response.json({ message: 'The route is working' });
  2. Run your application.
  3. Send a request to the test route by running the following command in your terminal:
    curl -H 'Content-Type: application/json' \
        -X POST http://localhost:3000/api/webhooks/test

If you see the {"message":"The route is working"}, then the basic Route Handler is working and ready to build on.


Your webhook needs to return a success code like 200 or 201 when it has been successfully handled. This will mark the webhook as successful in the Dashboard and prevent retries.

Check your configuration in the Clerk Dashboard

Whether you are developing locally or deploying to production, the webhook URL provided in your webhook endpoint must be exact and correct. The URL breaks down into three parts:

  • the protocol (http vs https) - Whether in development using a tunnel or in production, the URL will almost always use https so ensure that the protocol is correct.
  • the domain ( - The domain needs to be exact. A common error in production is not including the www.. Unlike entering a domain in your browser, a webhook will not be redirected from to If your application lives on then the webhook URL must use that.
  • the path (/api/webhooks/user) - The path must match the path in your application.

Debug your tunnel and webhook delivery

If your webhook is still getting errors after testing its route locally and verifying the endpoint's configuration in the Clerk Dashboard, you can further investigate the specific errors returned by the webhook. Depending on the type of error, your approach to fixing the webhook will vary.

  1. Navigate to the Clerk Dashboard.
  2. In the navigation sidebar, select Webhooks.
  3. Select the endpoint for which you want to test.
  4. In the Message attempts table, you will likely see that one or more of those attempts have failed. Select the failed attempt to expand it.
  5. In the details for the attempt, there will be a HTTP RESPONSE CODE. The code will likely be either a 500 or a 4xx error, which will indicate there is some misconfiguration.

Common HTTP response codes

The following table has some of the common response codes you might see and what they indicate. This is not an exhaustive list and you may need to research the code or error you are receiving. See HTTP response status codes from MDN for reference.

400Usually indicates the verification failed, but could be caused by other issues.
401The request was not authorized. If your test in the Test the Route Handler or API Route section worked, you should not see this error. If you are seeing it, then you will need to configure your Middleware to accept the request.
404The URL for the webhook was not found. Check that your application is running and that the endpoint is correct in the Clerk Dashboard.
405Your route is not accepting a POST request. All webhooks are POST requests and the route must accept them. Unless you are using the route for something else, you can restrict the route to POST requests only.
500The request made it to your application, but there is a code-related issue. This is likely a webhook verification issue or something in the webhook logic. Please see the following sections.

Debug webhook verification

To verify the webhook, please see the Create the endpoint in your application guide for a detailed code example. You can also visit the guide on verifying webhooks with the Svix library.

Diagnosing a problem in this part of the webhook can be challenging. Your best bet would be the liberal use of console.log. You could log out the following to check if the values are correct:

  • the signing secret
  • the headers
  • the body before verifying
  • the result of the .verify() attempt

The results of these will appear in the command line where you are running your application.

Checking the values and the progress of the webhook code will allow you to narrow down where the code is failing. They will often return null or errors where they should be returning values.

Check your logic

Once you have verified the webhook, you will now be writing your own code to handle the values from the webhook. This could range from saving data to a databse, or integrating with another system, to updating users or sending emails or SMS.

If the webhook is verified and you're seeing a 500 status code or your webhook is not behaving as expected, remember that you can use console.log to help diagnose what the problem is. Console logs and errors will be displayed on your command line, allowing you to see what's happening and address the bugs.


What did you think of this content?