DEV Community

Cover image for InsightsTrack + Pulse: I taught Claude Desktop to read my web analytics (via MCP)
Nishikanta Ray
Nishikanta Ray

Posted on

InsightsTrack + Pulse: I taught Claude Desktop to read my web analytics (via MCP)

This is a submission for Weekend Challenge: Passion Edition

What I Built

InsightsTrack is a self-hosted, privacy-first web analytics platform — the open-source alternative to Google Analytics. No cookies, no consent banner, no data selling. You run it on your own server and get real-time visitors, funnels, heatmaps, Core Web Vitals, and 17+ analytics views.

But the part I'm passionate about — and the reason I'm submitting it here — is Pulse: a built-in AI analyst that turns your analytics into a conversation.

Instead of hunting through dashboards, you just ask:

"What were my top pages last week?"
"Where is my traffic coming from?"
"Where are users dropping off in the funnel?"

Pulse answers in plain English, with real charts, tables, and CSV exports — every number backed by a live tool call, never hallucinated.

And here's the passion project twist: Pulse isn't locked inside the dashboard. The same analytics tools are exposed over MCP (Model Context Protocol), so I can open Claude Desktop, Cursor, or any MCP client and ask it about my website traffic — and it queries InsightsTrack directly.

My goal: make your own analytics as easy to query as sending a text message — and make that capability portable to every AI tool you already use.

Demo

🔗 Live app: https://insightstrack.dev
▶️ Video walkthrough: https://youtu.be/LGZw8temtPY

What to show in the demo:

  1. Open the dashboard, click Ask Pulse, type "top pages last 7 days" → watch it stream an answer + render a table with a CSV button and an Open pages → deep link.
  2. Switch the same result between table / bar / line / donut with one click.
  3. Open Claude Desktop → ask "which sites do I have in InsightsTrack, and what's my top traffic source this month?" → it calls the MCP tools and answers with live data.

insightstracks

Code

GitHub: https://github.com/NishikantaRay/InsightTrack

GitHub logo NishikantaRay / InsightTrack

Self-hosted, privacy-first web analytics — the open-source alternative to Google Analytics

📊 InsightsTrack

Self-hosted, privacy-first web analytics — the open-source alternative to Google Analytics

Open Source Self-Hosted No Cookies Stack Sponsor

Track visitors, pageviews, conversions, heatmaps, and Core Web Vitals — all on your own server. No cookies, no consent banners, no data selling. Deploy in under 15 minutes.

Live Demo · Quick Start · Features · Deploy · Docs

InsightsTrack Dashboard


What is InsightsTrack?

InsightsTrack is a complete, production-grade web analytics platform you run yourself. It gives you the depth of Google Analytics 4 — real-time visitors, traffic sources, funnels, heatmaps, Web Vitals — without sending a single byte of your visitors' data to a third party.

Why teams choose it:

  • 🔒 Privacy by design — no cookies, no fingerprinting, anonymous visitor IDs, GDPR-compliant, DNT/GPC honored.
  • Fast at any scale — a dual-database design (PostgreSQL for writes, DuckDB for reads) answers 90-day queries in under 100 ms even over millions of events.
  • 🧩 Everything in one place —…

The parts most relevant to this submission:

  • MCP tool registryanalytics-db/src/mcp/tools/registry.js (17 read-only tools)
  • MCP protocol handler (JSON-RPC 2.0, remote Streamable-HTTP transport) — analytics-db/src/mcp/protocol.js
  • The stdio bridge for local clients — mcp-server/src/index.js
  • The AI loop + BYO-key provider layer (Anthropic / OpenAI / Gemini) — analytics-db/src/routes/assistant.js and analytics-db/src/mcp/llm/provider.js

How I Built It

insightstracks

The dual-database core

InsightsTrack writes every tracking event to PostgreSQL and streams it into DuckDB, an embedded columnar engine. All analytics reads hit DuckDB — 90-day queries answer in tens of milliseconds, in-process, with no separate query cluster. Writes go to Postgres, reads come from DuckDB. That separation is what makes it fast and cheap to self-host.

Pulse: one tool registry, two front doors

The interesting decision was not building the AI assistant and the MCP integration as two separate things. There's one registry of 17 read-only tools (get_kpi, get_top_pages, get_funnel, get_realtime, list_sites, …). That single registry powers:

  1. The in-dashboard Pulse panel — a streaming chat loop that lets an LLM call the tools and renders each result as a chart/table/KPI card.
  2. MCP — the exact same tools, exposed to external clients.

Because both surfaces share the registry, an answer is consistent everywhere and I only maintain the tools once.

MCP: two transports

insightstracks

This is the connector heart of the project. I implemented both MCP transports:

  • Remote (Streamable-HTTP)POST /api/mcp/http speaks JSON-RPC 2.0 (initialize / tools/list / tools/call). Clients that support remote MCP connect with just a URL + a bearer connect token. Nothing to install.
  • Local (stdio bridge) — a tiny mcp-server process (the only place the real @modelcontextprotocol/sdk is used) runs next to the client, speaks stdio, and proxies every call over HTTP to the API. It never touches the database — which keeps per-user site scoping and DuckDB's single-writer lock intact.

Connect tokens are scoped JWTs (scope: 'mcp', with jti so they can be revoked one-by-one), so a leaked token from one laptop can be killed without affecting others. All tools are read-only — the AI can query but can never change or delete data.

Bring-your-own-key, encrypted at rest

Pulse runs on your model key — Anthropic (Claude), OpenAI (GPT), or Google (Gemini). Keys are stored AES-256-GCM encrypted (dependency-free node:crypto, key derived from the server secret) and never leave your server. Precedence is BYO-key first, server key as fallback — so a self-hoster can either let every user bring their own, or set one server key so it "just works."

Result cards that do real work

Every tool returns a structured envelope — { summary, data, render, download, deepLink }. The dashboard turns that into a card with a CSV export, a view switcher (table ↔ bar ↔ line ↔ donut, client-side, no re-query), and a deep link to the matching dashboard page. Over MCP, the same envelope ships as structuredContent so agent clients get the data too.

The honest hard part

Getting Gemini to work over its OpenAI-compatible endpoint surfaced a subtle streaming bug: OpenAI streams tool-call arguments as fragments to concatenate, but Gemini sends the complete arguments object per delta (and sometimes repeats it) — naive concatenation produced invalid JSON like {}{} that Gemini then rejected on the next round. The fix: if an incoming fragment is already valid JSON, treat it as the whole value instead of appending. One provider quirk, but it's the difference between "Gemini works" and a mysterious INVALID_ARGUMENT.

Prize Categories

Best Use of Google AI — Pulse supports Google Gemini as a first-class model provider for the AI analyst. Bring a Gemini API key in Settings and every plain-English question about your analytics is answered by Gemini calling InsightsTrack's 17 read-only tools — in the dashboard and over MCP from Claude Desktop / Cursor.


Built with ❤️ as an open-source project. Try it, self-host it, or connect it to your favorite AI client. Feedback and stars welcome → https://github.com/NishikantaRay/InsightTrack

Top comments (0)