Back to tutorials

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 demo for live mode (real webhook traffic via smee.io). If you don’t have a source yet, make demo-with-seed injects 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)

AnchorArchitecture diagram

Rendering diagram...

AnchorStep-by-step guide

Anchor1) Clone the demo project

git clone https://github.com/immoteur/webhooks-ingest-demo.git;
cd webhooks-ingest-demo;

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-holes6hi6y85rx31

What this does for you:

  • creates .env from .env.example if needed
  • starts Postgres + the ingestion API + Metabase
  • bootstraps Metabase (admin user + DB connection)
  • generates and starts 2 smee.io relays (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):

Anchor3) Open Metabase and verify the dashboard

  1. Open http://localhost:3001
  2. Log in with METABASE_ADMIN_EMAIL / METABASE_ADMIN_PASSWORD
  3. Open the demo dashboard (or the public dashboard URL printed by make demo)
Metabase login screen
Log in to Metabase with the admin credentials from .env.
Metabase demo dashboard
The demo project bootstraps a dashboard you can explore right away.

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 to classifieds)
  • classified_price_history: one row per price change (joined to classifieds)

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_events count 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.

AnchorDetails and troubleshooting

Run your first BI dashboard locally (Metabase) | Immoteur