Skip to content

Adding AI-Powered Insights to Plausible Analytics

Updated Sep 2026

verified on Ubuntu 26.04 · Aug 2026
We earn commissions when you shop through the links below. Full disclosure →

Enhance your self-hosted Plausible analytics with AI insights — use LLMs to analyze traffic patterns, generate reports, and answer questions about your data.

Before you start
  • Plausible running on a VPS (see Deploy Plausible on a VPS)
  • Ollama or another LLM backend available
  • Basic understanding of SQL and data analysis
Need a box for this guide? Kamatera's free tier lets you spin one up now.Start free on Kamatera → (opens in new tab)

Why AI + Plausible?

Plausible is a privacy-friendly, self-hosted analytics tool. It gives you clean, simple metrics without cookies, trackers, or GDPR headaches. But Plausible's strength — simplicity — also means it doesn't do deep analysis. Adding AI lets you ask questions about your data in natural language and get insights that would require writing custom SQL queries.

The appeal is conversational analytics. Instead of clicking through dashboards or writing SQL, you can ask: "What pages got the most traffic last month?" or "Why did my signups drop in March?" and get a clear answer with context.

This guide assumes you already have Plausible running. If not, set up a self-hosted instance first, then return here to add AI capabilities.

Architecture overview

The approach:

  1. Plausible stores your analytics data in ClickHouse
  2. A middleware service connects to both ClickHouse and your LLM
  3. The AI translates natural language questions into SQL, runs them, and interprets the results

This keeps your analytics data in Plausible where it belongs, while adding an AI layer on top.

Set up the middleware

Create a simple API that connects ClickHouse to your LLM:

// plausible-ai/index.ts
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from "https://deno.land/x/clickhouse@v0.0.14/mod.ts";

const clickhouse = createClient({
  url: Deno.env.get("CLICKHOUSE_URL") || "http://clickhouse:8123",
  username: "clickhouse",
  password: Deno.env.get("CLICKHOUSE_PASSWORD"),
});

serve(async (req) => {
  const { question } = await req.json();
  
  // 1. Generate SQL from natural language
  const sql = await generateSQL(question);
  
  // 2. Execute the query
  const result = await clickhouse.query({
    query: sql,
    format: "JSONEachRow",
  });
  
  // 3. Interpret the results
  const insight = await interpretResults(question, sql, result);
  
  return new Response(JSON.stringify({ sql, results: result, insight }), {
    headers: { "Content-Type": "application/json" },
  });
});
Where to host itaffiliate disclosure
Hetzner Cloudrun it on
2 vCPU · 4 GB RAM · 80 GB SSD · $23.59/mo
Get Hetzner Cloud (opens in new tab)
Kamaterafree trial
1 vCPU · 1 GB RAM · 20 GB SSD · $4.00/mo
Start free on Kamatera → (opens in new tab)
DigitalOceanalso works on
1 vCPU · 1 GB RAM · 25 GB SSD · $6.00/mo
Deploy on DigitalOcean → (opens in new tab)

Paid link — we earn a commission if you shop through it.

Generate SQL from natural language

Use your LLM to translate questions into SQL:

async function generateSQL(question: string): Promise<string> {
  const schema = `
Tables:
- events: name, pathname, hostname, timestamp, user_id, session_id
- sessions: session_id, user_id, timestamp, duration, source, referrer, utm_*
- pageviews: event_id, pathname
- custom_events: event_id, name, props
`;
  
  const response = await fetch("http://host.docker.internal:11434/api/generate", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      model: "llama3.2",
      prompt: `You are a ClickHouse SQL expert. Given this schema:
${schema}

Convert this question to SQL:
${question}

Return ONLY the SQL query, no explanation.`,
      stream: false,
    }),
  });
  
  const { response: sql } = await response.json();
  return sql.trim();
}

Interpret results with AI

Raw data isn't always insightful. Use the LLM to interpret:

async function interpretResults(
  question: string,
  sql: string,
  results: any[]
): Promise<string> {
  const response = await fetch("http://host.docker.internal:11434/api/generate", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      model: "llama3.2",
      prompt: `Question: ${question}

SQL executed: ${sql}

Results (first 20 rows):
${JSON.stringify(results.slice(0, 20), null, 2)}

Provide a clear, concise insight based on these results. What's interesting? What should the user pay attention to?`,
      stream: false,
    }),
  });
  
  const { response: insight } = await response.json();
  return insight;
}

Example questions you can ask

With this setup, you can ask questions like:

Traffic analysis:

  • "What were my top 10 pages last month?"
  • "How much traffic did I get from Google vs Twitter?"
  • "What's my average session duration?"

Trend analysis:

  • "How has my traffic changed over the last 6 months?"
  • "Which pages are growing the fastest?"
  • "What day of the week gets the most traffic?"

User behavior:

  • "What's my most common exit page?"
  • "How do users navigate through my site?"
  • "What referrers bring the most engaged users?"

Content performance:

  • "Which blog posts get the most views?"
  • "What's my bounce rate by page?"
  • "How do new vs returning visitors behave differently?"

Adding a chat interface

Create a simple web interface for asking questions:

<!DOCTYPE html>
<html>
<head>
  <title>AI Analytics</title>
  <style>
    body { font-family: sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
    .chat { margin-top: 20px; }
    .message { margin: 10px 0; padding: 10px; border-radius: 8px; }
    .user { background: #f0f0f0; }
    .ai { background: #e3f2fd; }
    pre { background: #f5f5f5; padding: 10px; overflow-x: auto; }
  </style>
</head>
<body>
  <h1>AI Analytics</h1>
  <input type="text" id="question" placeholder="Ask about your analytics..." 
         style="width: 70%; padding: 10px;">
  <button onclick="ask()" style="padding: 10px 20px;">Ask</button>
  
  <div class="chat" id="chat"></div>

  <script>
    async function ask() {
      const question = document.getElementById('question').value;
      const chat = document.getElementById('chat');
      
      // Show user question
      chat.innerHTML += `<div class="message user">${question}</div>`;
      
      // Get AI response
      const response = await fetch('/api/ask', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ question })
      });
      
      const data = await response.json();
      
      // Show AI insight
      chat.innerHTML += `<div class="message ai">${data.insight}</div>`;
      chat.innerHTML += `<div class="message"><pre>${data.sql}</pre></div>`;
      
      document.getElementById('question').value = '';
    }
  </script>
</body>
</html>

Security considerations

Read-only access: The AI should only read data, never modify it. Create a ClickHouse user with SELECT-only permissions:

CREATE USER analytics_reader IDENTIFIED BY 'secure_password';
GRANT SELECT ON plausible.* TO analytics_reader;

SQL injection protection: The LLM generates SQL, which is risky. Add validation:

  • Only allow SELECT queries
  • Block DROP, DELETE, UPDATE, INSERT
  • Limit query execution time
  • Set maximum result set size

API authentication: Protect the /api/ask endpoint with authentication. Use API keys or session-based auth.

Performance tips

Cache common questions: If you ask the same question repeatedly, cache the results. Store them in Redis or a simple file cache.

Query timeouts: ClickHouse queries should be fast, but set timeouts to prevent runaway queries:

const result = await clickhouse.query({
  query: sql,
  format: "JSONEachRow",
  settings: { max_execution_time: 30 },  // 30 seconds
});

Limit result size: Always add LIMIT to generated SQL to prevent massive result sets:

SELECT ... FROM ... LIMIT 100

Troubleshooting

ClickHouse connection fails. Verify ClickHouse is running and the credentials are correct. Check the ClickHouse logs for connection errors.

LLM generates invalid SQL. The model may not understand your schema. Improve the schema description in the prompt, or use a larger model for SQL generation.

Slow responses. AI inference takes time, especially for complex queries. Consider using a faster model or caching frequent queries.

Results don't match the question. The LLM may misinterpret the question. Refine your prompt or add examples of good question-to-SQL translations.

Out of memory. Large result sets can use significant memory. Always add LIMIT clauses and paginate results.

Verification + next steps

You're done when you can: ask natural language questions about your analytics, get SQL queries and results, and receive AI-interpreted insights. Test with simple questions first, then try more complex analysis.

From here, explore advanced features like automated daily reports, anomaly detection, and natural language alerts. For the base Plausible setup, see Deploy Plausible on a VPS. For database-backed AI, see Supabase with AI. A 2 vCPU / 4 GB VPS handles Plausible with AI; for heavy analytics workloads, consider 4 vCPU / 8 GB. See Best VPS for AI & ML Workloads for the ranked picks.

Next steps

How to self-host Plausible →More self-hosted web analytics tools →Automatic HTTPS with Caddy →Run Claude Code with Ollama on Your Own VPS →Deploy Coolify on a VPS →How to Deploy Actual Budget on a VPS →How to Deploy AnythingLLM on a VPS →How to Deploy Appwrite on a VPS →How to Deploy Audiobookshelf on a VPS →How to Deploy Authelia on a VPS →How to Deploy authentik on a VPS →How to Deploy Baserow on a VPS →How to Deploy Beszel on a VPS →How to Deploy Bitwarden on a VPS →How to Deploy BookStack on a VPS →How to Deploy CapRover on a VPS →How to Deploy Checkmate on a VPS →How to Deploy Directus on a VPS →How to Deploy docker-mailserver on a VPS →How to Deploy Docmost on a VPS →How to Deploy Dokku on a VPS →How to Deploy Dokploy on a VPS →How to Deploy Firefly III on a VPS →How to Deploy Forgejo on a VPS →How to Deploy Gatus on a VPS →How to Deploy Ghostfolio on a VPS →How to Deploy Gitea on a VPS →How to Deploy GitLab on a VPS →How to Deploy GlitchTip on a VPS →How to Deploy Grafana on a VPS →How to Deploy Graylog on a VPS →How to Deploy Headscale on a VPS →How to Deploy Healthchecks on a VPS →How to Deploy Home Assistant on a VPS →How to Deploy Immich on a VPS →How to Deploy Jan on a VPS →How to Deploy Jellyfin on a VPS →How to Deploy Karakeep on a VPS →How to Deploy Keycloak on a VPS →How to Deploy Leantime on a VPS →How to Deploy LibreChat on a VPS →How to Deploy Linkwarden on a VPS →How to Deploy LocalAI on a VPS →How to Deploy Mailcow on a VPS →How to Deploy Mailu on a VPS →How to Deploy Matomo on a VPS →How to Deploy Mattermost on a VPS →How to Deploy Meilisearch on a VPS →How to Deploy Memos on a VPS →How to Deploy n8n on a VPS →How to Deploy Navidrome on a VPS →How to Deploy NetBird on a VPS →How to Deploy Netdata on a VPS →How to Deploy Nextcloud on a VPS →How to Deploy Next.js to a VPS →How to Deploy Nginx Proxy Manager on a VPS →How to Deploy NocoDB on a VPS →How to Deploy ntfy on a VPS →How to Deploy Ollama on a VPS →How to Deploy Open WebUI on a VPS →How to Deploy OpenHands on a VPS →How to Deploy OpenObserve on a VPS →How to Deploy OpenProject on a VPS →How to Deploy Outline on a VPS →How to Deploy Pangolin on a VPS →How to Deploy Paperless-ngx on a VPS →How to Deploy Passbolt on a VPS →How to Deploy Plane on a VPS →How to Deploy Plausible Analytics on a VPS →How to Deploy Pocket ID on a VPS →How to Deploy PocketBase on a VPS →How to Deploy Prometheus on a VPS →How to Deploy Psono on a VPS →How to Deploy Radarr on a VPS →How to Deploy Rocket.Chat on a VPS →How to Deploy SigNoz on a VPS →How to Deploy Sonarr on a VPS →How to Deploy Stalwart on a VPS →How to Deploy Stirling-PDF on a VPS →How to Deploy Supabase on a VPS →How to Deploy Synapse on a VPS →How to Deploy Taiga on a VPS →How to Deploy TeamPass on a VPS →How to Deploy Tinyauth on a VPS →How to Deploy Traefik on a VPS →How to Deploy Trilium on a VPS →How to Deploy Twenty CRM on a VPS →How to Deploy Umami on a VPS →How to Deploy Uptime Kuma on a VPS →How to Deploy Vaultwarden on a VPS →How to Deploy Vikunja on a VPS →How to Deploy wg-easy on a VPS →How to Deploy Wiki.js on a VPS →How to Deploy Zabbix on a VPS →How to Deploy Zitadel on a VPS →How to Deploy Zulip on a VPS →Docker & Compose on Ubuntu 26.04 →Building AI Workflows with n8n →Install Open WebUI with Ollama →Building AI-Powered Apps with Supabase and pgvector →

We use analytics cookies (Google Analytics, PostHog) to see which guides are useful. No ad networks, no cross-site tracking. See our privacy policy.