Build a real-time webhook events dashboard to capture and visualize live call messages
Go beyond terminal logs — build a live events dashboard that captures webhook events in real time and displays conversation messages in a chat-like UI you can monitor from your browser.
This guide builds on the ngrok setup. Make sure you have ngrok installed and authenticated before proceeding.
A Python server that accepts incoming webhook POST requests, parses status-update and conversation-update events, deduplicates messages, and exposes REST endpoints to query stored data.
2
Frontend — HTML live dashboard
A single-page HTML file served by the same FastAPI server. It polls the backend every few seconds, lets you pick a conversation, and renders messages in a chat-style layout with auto-refresh.
event_store is a plain Python dict keyed by call ID. Each entry holds three lists — statuses, messages, and raw events. No database setup required; data resets when you restart the server.
Message deduplication
Interactly sends all messages accumulated so far with every conversation-update event. The server tracks seen messageId values in a set and only appends genuinely new messages — so your dashboard never shows duplicates.
Dual-purpose server
The same FastAPI instance serves the webhook endpoint (POST /webhook), the REST API (GET /api/conversations), and the HTML dashboard (GET /). One process, one port — no CORS issues.
The dashboard polls /api/conversations every 1.5 seconds. When a new call ID appears, it’s added to the dropdown and auto-selected so you see messages immediately — no manual refresh needed.
Chat-style message rendering
User messages appear on the right (blue bubbles), assistant messages on the left (grey bubbles), exactly like a messaging app. Each bubble shows the role and timestamp.
Status pill timeline
Call status transitions (queued → ongoing → finished) are displayed as pills above the chat area, giving you a quick timeline of the call lifecycle.
Pause / Resume / Reset
Pause stops polling without losing data. Resume picks back up instantly. Reset clears all stored events on the server — handy between test runs.
You need two terminals — one for the server, one for ngrok.
Terminal 1 — Server
Terminal 2 — ngrok
Copy
cd interactly-live-eventssource venv/bin/activatepython3 server.py
Expected output:
Copy
🚀 Live Events Server starting on port 8000📡 Webhook endpoint : http://localhost:8000/webhook🖥️ Dashboard : http://localhost:8000/INFO: Uvicorn running on http://0.0.0.0:8000
Copy
ngrok http 8000
Copy the Forwarding URL (e.g. https://a1b2c3d4.ngrok.io).
The ngrok URL changes every time you restart ngrok (unless you have a paid plan with a reserved domain). Remember to update your assistant’s webhook URL each time.
Navigate to http://localhost:8000 in your browser.
2
Start a call
Go to your Interactly dashboard and initiate a test call with the configured assistant.
3
Watch live
The dashboard will auto-detect the new call. Status pills appear first (queued → ongoing), then messages stream in as the conversation progresses.
4
End the call
When the call ends, you’ll see the finished status pill. All messages remain visible for review.
You should see live output in both places:
Server Terminal
Browser Dashboard
Copy
[14:23:15.935] 📞 WC-82015760…07e4ab85 → QUEUED[14:23:17.112] 📞 WC-82015760…07e4ab85 → ONGOING[14:23:19.445] 💬 assistant: Hello! How can I help you today?[14:23:24.891] 💬 user: I'd like to schedule an appointment[14:23:26.334] 💬 assistant: Sure! What date works best for you?[14:24:01.220] 📞 WC-82015760…07e4ab85 → FINISHED
The chat area fills with blue (user) and grey (assistant) bubbles in real time, with status pills showing queued → ongoing → finished across the top.
Dashboard shows 'Waiting for calls…' but events are arriving in the terminal
Open browser DevTools → Console. If you see CORS or fetch errors, make sure you’re accessing the dashboard via http://localhost:8000 (served by FastAPI), not by opening the HTML file directly.
ngrok tunnel died / URL changed
Restart ngrok (ngrok http 8000), copy the new Forwarding URL, and update your assistant’s webhook URL. The server itself doesn’t need restarting.
Duplicate messages in the chat
This shouldn’t happen — the server deduplicates by messageId. If it does, restart the server (Ctrl+C then python server.py) to clear the in-memory store, or click Reset in the dashboard.
Port 8000 already in use
Either kill the existing process (lsof -i :8000 then kill <PID>), or start on a different port: