Get started with 33% off your first certification using code: 33OFFNEW

Test Stripe webhooks without using ngrok

6 min read
Published on 21st October 2024

Testing Stripe webhooks is a crucial part of building payment integrations for web applications. Webhooks allow Stripe to communicate events to your backend, such as successful payments, refunds, and failed charges. However, one of the most common roadblocks for developers is testing these webhooks in a local development environment. Traditionally, tools like ngrok have been used to expose your localhost to the web, making it possible for Stripe to send webhooks to your local machine. While ngrok is a great tool, it's not always necessary, and there are other ways to test Stripe webhooks without using it.

In this article, we'll explore alternative methods to test Stripe webhooks locally without the need for ngrok or any other tunnel-based service. By the end, you'll be able to test Stripe webhooks in an efficient and more manageable way.

Why Consider Testing Webhooks Without Ngrok?

Before diving into the alternatives, let's briefly touch on why you might want to avoid using ngrok:

1. Limited free-tier: Ngrok's free tier is quite limited in terms of the number of connections, session lengths, and features. You may hit these limits during testing.

2. Reliability issues: Since ngrok exposes your local development environment to the internet, it can be slower and less reliable than testing locally.

3. Security concerns: While ngrok can be secure, exposing your localhost to the internet introduces risks, especially if you're not actively monitoring traffic.

Fortunately, Stripe provides a few ways to bypass these concerns while still testing webhooks locally.


1. Using the Stripe CLI

The Stripe CLI is a powerful tool that can simulate webhook events, manage Stripe resources, and even forward webhooks directly to your local environment. This eliminates the need for exposing your localhost to the internet.

Installing the Stripe CLI

Before getting started, you'll need to install the Stripe CLI. You can download it via Stripe's official documentation, but here's a quick breakdown:

For macOS:


brew install stripe/stripe-cli/stripe

For Linux:


curl -L https://github.com/stripe/stripe-cli/releases/download/vX.Y.Z/stripe_X.Y.Z_linux_x86_64.tar.gz | tar xz

sudo mv stripe /usr/local/bin/

For Windows:

You can use the Windows installer available here.

Authenticating the Stripe CLI

After installation, you will need to authenticate the Stripe CLI by logging into your Stripe account:


stripe login

This will open a browser window asking you to log in and confirm the connection between the CLI and your Stripe account.

Forwarding Webhooks Using Stripe CLI

Once authenticated, you can use the Stripe CLI to forward webhook events to your local machine, effectively simulating real webhooks from Stripe.

1. Navigate to your project's root directory where your webhook handler is located.

2. Start listening for Stripe webhook events by using the following command:


stripe listen --forward-to localhost:3000/webhooks

This will forward all webhook events from your Stripe account to the specified route (/webhooks in this case) on your local server running on port 3000.

Simulating Webhook Events with Stripe CLI

In addition to forwarding webhooks, you can simulate specific webhook events using the Stripe CLI. This is helpful for testing particular scenarios without triggering actual events on your Stripe account. To simulate a specific event, run:


stripe trigger payment_intent.succeeded

This command will send a simulated payment_intent.succeeded event to your local webhook endpoint.

If you want to test other types of webhooks (like refunds, subscription updates, etc.), check out the full list of webhook event types that you can simulate with stripe trigger.

Example Webhook Handler in Node.js

Here's a simple example of a webhook handler in Node.js to test with the Stripe CLI:


const express = require('express');

const app = express();

const bodyParser = require('body-parser');

const stripe = require('stripe')('your-stripe-secret-key');

app.use(bodyParser.raw({ type: 'application/json' }));

app.post('/webhooks', (req, res) => {

  const sig = req.headers['stripe-signature'];

  let event;

  try {

    event = stripe.webhooks.constructEvent(req.body, sig, 'your-webhook-signing-secret');

  } catch (err) {

    return res.status(400).send(`Webhook Error: ${err.message}`);

  }

  // Handle the event

  switch (event.type) {

    case 'payment_intent.succeeded':

      const paymentIntent = event.data.object;

      console.log('PaymentIntent was successful!');

      break;

    default:

      console.log(`Unhandled event type ${event.type}`);

  }

  res.status(200).send();

});

app.listen(3000, () => console.log('Server listening on port 3000'));

With the Stripe CLI running in one terminal and your server running in another, the Stripe CLI will simulate the payment_intent.succeeded event and forward it to your /webhooks endpoint, where your server will process it.


2. Using Stripe's Webhooks Test Feature

Another option to test Stripe webhooks without ngrok is to use Stripe's built-in testing tools available in their dashboard. While this doesn't directly involve local development, it can be a quick way to test and debug webhooks.

How to Test Webhooks in the Stripe Dashboard

1. Go to the Developer section: Log into your Stripe dashboard and navigate to the "Developers" section.

2. Find the Webhooks tab: Under "Developers," you'll find a section called "Webhooks." This is where you can see all your webhook endpoints and the events that have been sent to them.

3. Send test events: In the Webhooks section, you'll see an option to "Send test webhook." You can choose the type of event you want to test, and Stripe will send a test event to your configured webhook endpoint.

Make sure your webhook endpoint is hosted online for this to work since this tool sends real webhook events, not local ones.


3. Local Stripe Webhook Testing with Docker

If you don't want to use ngrok and prefer to work entirely locally, you can spin up a Docker container that mimics Stripe's behavior and sends webhooks directly to your localhost. This solution allows for a fully isolated local environment without any need for external dependencies like ngrok.

Here's how to set this up:

Setting Up Docker for Stripe Webhook Testing

1. Create a Dockerfile: Create a Dockerfile that sets up your application along with Stripe's mock webhook server. A simple example:


# Use an official Node.js image as a parent image

FROM node:14

# Set the working directory to /app

WORKDIR /app

# Copy the current directory contents into the container at /app

COPY . /app

# Install any needed packages specified in package.json

RUN npm install

# Make port 3000 available to the world outside this container

EXPOSE 3000

# Run the app when the container launches

CMD ["node", "index.js"]

2. Build and Run the Container:


docker build -t stripe-webhook-test .

docker run -p 3000:3000 stripe-webhook-test

This sets up a local environment running in Docker, exposing the necessary ports for Stripe to communicate with your webhook handler. The setup here will be similar to the example Node.js webhook handler mentioned earlier, but fully containerized.


4. Mocking Webhooks in Integration Tests

For a truly isolated local testing experience, you can mock Stripe's webhooks in your automated tests. This approach doesn't require any external service, including ngrok or the Stripe CLI.

Example: Mocking Stripe Webhooks in Jest

If you are using Jest for your testing, here's how you can mock Stripe webhooks in your tests:


const request = require('supertest');

const app = require('../app'); // Assuming your Express app is exported here

test('Webhook payment succeeded', async () => {

  const response = await request(app)

    .post('/webhooks')

    .send({

      id: 'evt_test_webhook',

      type: 'payment_intent.succeeded',

      data: {

        object: {

          id: 'pi_test',

          amount: 2000

        }

      }

    });

  expect(response.status).toBe(200);

  // Add more assertions based on what you expect the webhook to trigger

});

Here, you simulate the payload that Stripe sends when a payment_intent.succeeded event occurs. This way, you can test your webhook handler without needing a live Stripe environment.


Wrapping It Up

While ngrok is a useful tool, it's not the only way to test Stripe webhooks in a local environment. By using tools like the Stripe CLI, Docker, and even Stripe's built-in testing tools, you can efficiently test webhooks without exposing your local development environment to the public internet.

Whether you opt for using the Stripe CLI to forward webhooks or prefer mocking webhooks entirely in your test suite, these strategies help you work more securely, avoid limitations, and maintain full control over your development environment.