A lightweight webhook testing utility built with NestJS, React, SQLite/Redis, TailwindCSS, and Docker.
- Creates anonymous webhook URLs with random UUID identifiers
- Accepts any HTTP method at
/:webhookId - Stores requests in SQLite (default) or Redis
- Polls every 1500ms for new requests
- Renders a split-pane inspector UI with request details
- Backend: NestJS + TypeScript
- Frontend: React + Vite + TailwindCSS
- Storage: SQLite (default) or Redis
- Realtime: polling
- Containerization: Docker + Docker Compose
docker-compose up --build- Frontend: http://localhost:3001
- Backend: http://localhost:3000
When you open the frontend, it generates a random webhook identifier, stores it in your browser, and routes you to the inspector view for that URL. The webhook URL you can send traffic to is the backend origin plus that identifier, for example http://localhost:3000/550e8400-e29b-41d4-a716-446655440000.
You can send a test payload to that webhook URL with curl:
curl -X POST http://localhost:3000/550e8400-e29b-41d4-a716-446655440000 \
-H "Content-Type: application/json" \
-d '{
"event": "payment.succeeded",
"id": "evt_123",
"amount": 4200
}'By default the backend stores requests in a local SQLite database, so docker-compose up --build works with no other services. To use Redis instead, start the redis profile and point the backend at it:
STORAGE_DRIVER=redis docker-compose --profile redis up --buildThe backend supports two storage drivers, selected with the STORAGE_DRIVER environment variable:
sqlite(default) — stores requests in a local SQLite file. Configure the file path withSQLITE_PATH(defaults to./data/webhook-inspector.db). No extra services required.redis— stores requests in Redis sorted sets. Configure the connection withREDIS_URL(defaults toredis://127.0.0.1:6379).
Production setup:
- Frontend:
https://app.example.com - Backend:
https://api.example.com - Storage: local SQLite volume, or Redis on the private network only
Point app.example.com at the frontend server or load balancer.
Point api.example.com at the backend server or load balancer.
Backend (SQLite, default):
PORT=3000
STORAGE_DRIVER=sqlite
SQLITE_PATH=/data/webhook-inspector.db
CORS_ORIGIN=https://app.example.comBackend (Redis):
PORT=3000
STORAGE_DRIVER=redis
REDIS_URL=redis://<private-redis-host>:6379
CORS_ORIGIN=https://app.example.comFrontend build:
VITE_API_BASE_URL=https://api.example.comThe shareable webhook URL becomes:
https://api.example.com/<webhookId>
- If using SQLite, mount a persistent volume at the
SQLITE_PATHdirectory so data survives restarts. - If using Redis, keep it off the public internet.
- The frontend must be built with the backend URL baked in via
VITE_API_BASE_URL. - The backend already allows CORS from the configured frontend origin.
- If you use Docker, you can keep the same compose file and override the env vars for production.
The existing repo structure is still the primary setup for general use:
backend/is the standard NestJS backendfrontend/is the standard React app- storage remains configurable as
sqlite(default) orredis
The Cloudflare path is optional and deployment-only. It lives under deploy/cloudflare/ and does not replace or restructure the main app. It exists as a Cloudflare-specific adapter that serves the frontend on Cloudflare and stores requests in D1 for that deployment target.
Use deploy/cloudflare/README.md only when you want to deploy to Cloudflare.
Accepts any webhook request and stores it via the configured storage driver.
Returns requests newest-first.
sinceis a timestamp in millisecondslimitdefaults to50and is capped at50
The app is organized as two standalone packages:
backend/frontend/
You can install and run them separately if you want to develop without Docker.