MeetStream Guide: Test Webhooks Locally with ngrok or Cloudflare Tunnel

View as MarkdownOpen in Claude

When you’re building a MeetStream integration, you’ll often want to test webhooks locally (on your laptop) before deploying a server.

This guide shows how to:

  • run a local webhook server
  • expose it to the internet using ngrok or Cloudflare Tunnel (cloudflared)
  • paste the public URL into MeetStream as your callback_url

What you’re building

  1. You run a local HTTP server (example: http://localhost:3000/webhooks/meetstream)
  2. You create a tunnel that gives you a public URL (example: https://abc123.ngrok-free.app/webhooks/meetstream)
  3. You use that public URL as MeetStream’s webhook callback_url

0) Create a simple local webhook endpoint

Pick any stack. Here are two minimal examples.

A) Node.js (Express)

$mkdir meetstream-webhook-test && cd meetstream-webhook-test
$npm init -y
$npm i express

Create server.js:

1import express from "express";
2
3const app = express();
4app.use(express.json({ type: "*/*" }));
5
6app.post("/webhooks/meetstream", (req, res) => {
7 console.log("✅ Webhook received");
8 console.log("Headers:", req.headers);
9 console.log("Body:", req.body);
10 res.status(200).send("ok");
11});
12
13app.listen(3000, () => console.log("Listening on http://localhost:3000"));

Run it:

$node server.js

Your local endpoint is now:

  • http://localhost:3000/webhooks/meetstream

B) Python (FastAPI)

$pip install fastapi uvicorn

Create app.py:

1from fastapi import FastAPI, Request
2
3app = FastAPI()
4
5@app.post("/webhooks/meetstream")
6async def webhook(req: Request):
7 body = await req.json()
8 print("✅ Webhook received")
9 print("Headers:", dict(req.headers))
10 print("Body:", body)
11 return {"ok": True}

Run it:

$uvicorn app:app --port 3000 --reload

Endpoint:

  • http://localhost:3000/webhooks/meetstream

1) Option A — Use ngrok (quickest)

Step 1: Install ngrok

  • macOS (Homebrew):
$brew install ngrok/ngrok/ngrok

Or download from ngrok website and follow install steps.

Step 2: Authenticate ngrok

$ngrok config add-authtoken <YOUR_NGROK_TOKEN>

Step 3: Start a tunnel to your local port

If your local server is running on localhost:3000:

$ngrok http 3000

ngrok will print a public HTTPS URL like:

  • https://abc123.ngrok-free.app

Step 4: Use the public URL as callback_url

If your route is /webhooks/meetstream, your final webhook URL becomes:

  • https://abc123.ngrok-free.app/webhooks/meetstream

Use this in your Create Bot payload:

1{
2 "callback_url": "https://abc123.ngrok-free.app/webhooks/meetstream"
3}

2) Option B — Use Cloudflare Tunnel (cloudflared)

Cloudflare Tunnel is great if you already use Cloudflare or want a stable tunnel.

Step 1: Install cloudflared

  • macOS (Homebrew):
$brew install cloudflare/cloudflare/cloudflared

Step 2: Start a quick (temporary) tunnel

If your local server is on port 3000:

$cloudflared tunnel --url http://localhost:3000

cloudflared will output a public URL like:

  • https://something.trycloudflare.com

Step 3: Use it as callback_url

Final webhook URL:

  • https://something.trycloudflare.com/webhooks/meetstream

3) Verify your local webhook is receiving events

A) Add the URL while creating the bot

Include in Create Bot / Create Agent payload:

1{
2 "callback_url": "https://<PUBLIC_TUNNEL_URL>/webhooks/meetstream"
3}

B) Trigger a bot lifecycle

You should see incoming webhook payloads for events like:

  • bot.joining
  • bot.inmeeting
  • bot.stopped

4) Common issues & fixes

Webhook not arriving?

  • Confirm your local server is running and the endpoint path matches exactly.
  • Ensure your tunnel is pointing to the right port (e.g., 3000).
  • Make sure your webhook handler returns 2xx quickly.

“502 Bad Gateway” in ngrok / Cloudflare

  • Your local server is not reachable on that port.
  • Try opening locally:
    • curl -X POST http://localhost:3000/webhooks/meetstream -H "Content-Type: application/json" -d '{}'

Missing JSON body

  • Ensure you have JSON parsing enabled:
    • Express: app.use(express.json({ type: "*/*" }))
    • FastAPI already parses JSON with await req.json()

5) Production best practices (when you deploy)

  • Make webhook handling idempotent (avoid double-processing).
  • Verify webhook signatures (if configured).
  • Log webhook events + store minimal event history for debugging.
  • Don’t run tunnels in production — use a hosted endpoint.

If you tell me your preferred runtime (Node / Python / Bun / Go), I can add a “copy‑paste ready” webhook handler with signature verification + de-duplication.