AnchorRun your first BI dashboard locally (Metabase)
This tutorial helps you launch a local BI stack (Metabase + Postgres) and start
exploring data right away. We’ll use the open-source demo project
immoteur/webhooks-ingest-demo,
which includes a small webhook ingestion API and a Metabase setup that reads
directly from the database.
If you’d like to explore the result before running anything locally, open the live demo.
Tip: Use
make demofor live mode (real webhook traffic viasmee.io). If you don’t have a source yet,make demo-with-seedinjects sample events so your dashboards are not empty.
AnchorWhat you'll build
- A local Metabase instance you can open in your browser.
- A Postgres database populated with webhook events and analytics-friendly tables.
- A first dashboard you can inspect, remix, and share locally.
AnchorPrerequisites
- Docker + Docker Compose (v2)
- Node.js 20+ (required by the demo scripts)
- Git + Make
- Free ports on your machine (defaults:
8080,3001,15432)
AnchorQuick links
- Demo repository: https://github.com/immoteur/webhooks-ingest-demo
- Metabase documentation: https://www.metabase.com/docs/latest/
- smee.io: https://smee.io/
AnchorArchitecture diagram
AnchorStep-by-step guide
Anchor1) Clone the demo project
git clone https://github.com/immoteur/webhooks-ingest-demo.git;
cd webhooks-ingest-demo;Anchor2) Start the stack (recommended)
Use live mode (real data) with the full Docker Compose stack + smee.io relays:
make demo;Example output:
[demo] Waiting for API at http://localhost:8080...
[+] Running 1/1
✔ Container webhooks_ingest_api Healthy 17.6s
[demo] Ready (live mode, no seed):
- API: http://localhost:8080
- Metabase: http://localhost:3001
- Metabase admin: [email protected] / DemoAdmin!2025ChangeMe
- Metabase public dashboard: http://localhost:3001/public/dashboard/16b57a07-9831-4ec9-b927-b6207d3eaa31
[demo] smee relays (send webhooks here):
- classified-notification: https://smee.io/classified-notification-3o41g78qykci2otd
- classifieds-export: https://smee.io/classifieds-export-holes6hi6y85rx31What this does for you:
- creates
.envfrom.env.exampleif needed - starts Postgres + the ingestion API + Metabase
- bootstraps Metabase (admin user + DB connection)
- generates and starts 2
smee.iorelays (one per webhook endpoint) - prints URLs and credentials (including a public Metabase dashboard URL)
Metabase admin credentials also come from .env (defaults in the demo):
[email protected]METABASE_ADMIN_PASSWORD=DemoAdmin!2025ChangeMe
Anchor3) Open Metabase and verify the dashboard
- Open
http://localhost:3001 - Log in with
METABASE_ADMIN_EMAIL/METABASE_ADMIN_PASSWORD - Open the demo dashboard (or the public dashboard URL printed by
make demo)

.env.
Anchor4) Explore the data model (your first BI dataset)
In Metabase, you should see tables like:
webhook_events: raw ingestion log of received webhook requests (with retention cleanup)classifieds: flattened records derived from Immoteur payloads (classified-notification/classifieds-export)classified_images: one row per image (joined toclassifieds)classified_price_history: one row per price change (joined toclassifieds)
Try a first question in Metabase’s SQL editor:
select count(*) as events from webhook_events;Anchor5) Send real events (or post sample payloads)
Back in Metabase:
- re-run your question or refresh the dashboard
- check
webhook_eventscount increased
Anchor6) Stop (or reset) the demo
To stop containers (keep data):
make stack-down-smee;To wipe everything (fresh start, deletes Docker volumes):
make stack-reset-smee;AnchorConclusion
You now have a local BI stack running: an ingestion API that writes to Postgres, and Metabase reading from it to power dashboards. Next, try creating your own question (e.g., “events per hour”), add it to a dashboard, and point the webhook endpoints to a real source when you’re ready.