
How I Built an AI Agent That Writes My Blog From My GitHub
The build log of a blog that drafts itself: how merged pull requests become reviewable article drafts, and how one cell in a spreadsheet decides what goes live.
Read article
Every website needs analytics, but almost every mainstream analytics solution is frustrating in its own distinct way.
Google Analytics 4 is a bloated maze that slows down your Core Web Vitals and forces you to slap cookie consent banners on your website. Modern product analytics suites like PostHog are incredible, but self-hosting them means maintaining a heavy cluster of ClickHouse, Kafka, Redis, and Postgres for what should be simple event counts.
When we set up analytics for Zyntopia, we had four non-negotiable requirements:
<5KB), and non-blocking for lightning-fast page loads.We chose Smol Analytics — an open-source (MIT) Go binary designed from the ground up for modern developers and AI agents.
Here is why it works so well, along with a complete, human-readable guide to setting it up from scratch.
At its core, Smol Analytics strips analytics down to its simplest, most powerful primitives:
POST /v1/events handles everything — browser clicks, server-side Stripe webhooks, and background jobs.Setting up Smol Analytics across your server, your Next.js application, and your AI editor takes less than 10 minutes.
Create a docker-compose.yml file on your server (or VPS):
services:
smolanalytics:
image: ghcr.io/arjun0606/smolanalytics:latest
container_name: smolanalytics
restart: unless-stopped
ports:
- "127.0.0.1:8090:8080"
volumes:
- ./data:/data
environment:
- PORT=8080
- DATA_DIR=/data
Start the container and expose it behind your reverse proxy (Caddy, Nginx, or a Cloudflare Tunnel) with HTTPS:
docker compose up -d
Once running, inspect docker logs smolanalytics to get your three keys:
https://analytics.yourdomain.comIn your Next.js project, add your public keys to .env.local:
NEXT_PUBLIC_SMOLANALYTICS_HOST="https://analytics.yourdomain.com"
NEXT_PUBLIC_SMOLANALYTICS_WRITE_KEY="your_public_write_key"
Next, open your root layout (app/layout.tsx) and inject the script using Next.js next/script with strategy="afterInteractive":
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
{process.env.NEXT_PUBLIC_SMOLANALYTICS_HOST &&
process.env.NEXT_PUBLIC_SMOLANALYTICS_WRITE_KEY && (
<>
<Script
src={`${process.env.NEXT_PUBLIC_SMOLANALYTICS_HOST}/sdk.js`}
strategy="afterInteractive"
/>
<Script id="smolanalytics-init" strategy="afterInteractive">
{`
if (window.smolanalytics) {
window.smolanalytics.init("${process.env.NEXT_PUBLIC_SMOLANALYTICS_WRITE_KEY}", {
host: "${process.env.NEXT_PUBLIC_SMOLANALYTICS_HOST}",
env: "${process.env.NEXT_PUBLIC_VERCEL_ENV || process.env.NODE_ENV || 'production'}"
});
}
`}
</Script>
</>
)}
</body>
</html>
);
}
Why the
envtag matters: Smol Analytics automatically detects staging and preview subdomains. By passingNEXT_PUBLIC_VERCEL_ENV, local dev runs and Vercel preview pull requests are automatically hidden from your live production dashboard.
Pageviews are good, but for consulting and SaaS, high-intent conversion moments are what actually move the needle.
We created a tiny helper (lib/analytics.ts):
export function trackEvent(name: string, properties?: Record<string, unknown>) {
if (typeof window !== "undefined" && window.smolanalytics?.track) {
window.smolanalytics.track(name, properties);
}
}
export function identifyUser(distinctId: string) {
if (typeof window !== "undefined" && window.smolanalytics?.identify) {
window.smolanalytics.identify(distinctId);
}
}
When a visitor submits a contact or lead form:
// Inside your form submission handler
identifyUser(leadEmail);
trackEvent("lead_submitted", { company: leadCompany });
This immediately stitches the visitor's past anonymous browsing history into their verified identity, giving you a full timeline of what they read before reaching out.
middleware.ts)AI search bots like GPTBot, ClaudeBot, and PerplexityBot never run client-side JavaScript. If you rely only on a browser script tag, your analytics will report zero AI crawlers.
The fix is simple: report them from your server in Next.js middleware.ts:
import { NextResponse, type NextRequest } from "next/server";
const AI_CRAWLERS = [
{ pattern: /GPTBot/i, crawler: "GPTBot", operator: "OpenAI", purpose: "training" },
{ pattern: /OAI-SearchBot/i, crawler: "OAI-SearchBot", operator: "OpenAI", purpose: "search" },
{ pattern: /ClaudeBot/i, crawler: "ClaudeBot", operator: "Anthropic", purpose: "training" },
{ pattern: /PerplexityBot/i, crawler: "PerplexityBot", operator: "Perplexity", purpose: "search" },
];
export async function middleware(request: NextRequest) {
const userAgent = request.headers.get("user-agent") || "";
const matched = AI_CRAWLERS.find((bot) => bot.pattern.test(userAgent));
if (matched && process.env.NEXT_PUBLIC_SMOLANALYTICS_HOST) {
// Fire-and-forget server event
fetch(`${process.env.NEXT_PUBLIC_SMOLANALYTICS_HOST}/v1/events`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.NEXT_PUBLIC_SMOLANALYTICS_WRITE_KEY}`,
},
body: JSON.stringify({
name: "$ai_crawl",
distinct_id: "$crawler",
properties: {
crawler: matched.crawler,
operator: matched.operator,
purpose: matched.purpose,
path: request.nextUrl.pathname,
status: 200,
site: "zyntopia.com",
},
}),
}).catch(() => {});
}
return NextResponse.next();
}
Now, your dashboard's AI Crawlers report will show exactly which AI labs are scraping your documentation or citing your pages in real time.
The most transformative feature of Smol Analytics is its native Model Context Protocol (MCP) server.
Instead of opening a browser tab to check a dashboard, you can connect your analytics directly to Cursor, Claude Code, Windsurf, or Antigravity:
{
"mcpServers": {
"smolanalytics": {
"url": "https://analytics.yourdomain.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_SECRET_READ_KEY"
}
}
}
}
Now you can highlight a component or open your terminal and ask your AI assistant:
"What was our conversion rate from the blog to the booking form this week?"
"Which AI assistant (ChatGPT vs Claude vs Perplexity) generated the most referral traffic?"
"Did our latest release improve the signup drop-off rate?"
Because answers are computed directly from deterministic backend reports rather than guessed, the numbers are guaranteed to match your dashboard 1-to-1.
Analytics shouldn't require complex infrastructure or intrusive tracking cookies. By running a single self-hosted Go binary with native MCP connectivity, you get:
If you're building modern web apps or deploying AI automation systems, giving your stack an AI-native analytics engine is one of the highest-leverage upgrades you can make.
Filed under: Build LogAnalyticsAI AgentsNext.jsSelf-HostingOpen Source

The build log of a blog that drafts itself: how merged pull requests become reviewable article drafts, and how one cell in a spreadsheet decides what goes live.
Read article
Why single-prompt chatbots fail for busy teams, and how Seepient operates as a persistent, secure digital colleague across desktop and cloud environments.
Read articleWork with me
Got a process that's eating your week?
Fixed-scope, fixed-price automation work. We agree what's being built and what it costs — then I build it.
Book a call →