What is Statvisor?
Statvisor gives you backend API analytics and frontend performance monitoring in one SDK. Instrument your Node.js backend in one line, and drop a component into your frontend to track page views, Core Web Vitals, and visitor geography.
One-line setup
One middleware call instruments every backend route automatically.
Full-stack analytics
Backend: latency, errors, volume. Frontend: page views, Web Vitals, geography.
Privacy-first
No request bodies, no PII. Country derived from IP — raw IP never stored.
Up and running in 2 minutes
The flow is the same regardless of framework: create a project, grab your API key, install the SDK, add one line. Here's the generic version:
Create a project in the dashboard
https://api.example.com). This is the origin where your API is hosted — scheme and host only, no path.Copy your API key
vl_. Store it securely (e.g. in an environment variable).Install the SDK
npm install @statvisor/sdkAdd the middleware
Verify it's working
Under the hood
The SDK wraps your framework's request lifecycle using standard middleware hooks. It records the wall-clock time before your handler runs and after it completes, capturing:
- Route path (normalised — e.g. /users/:id, not /users/123)
- HTTP method (GET, POST, PUT, PATCH, DELETE…)
- Response status code
- Duration in milliseconds
- Timestamp (UTC)
Events are queued in memory and flushed to https://statvisor.com/api/ingest asynchronously in the background. Your request handlers are never blocked.
Statvisor never captures request bodies, response bodies, query parameters, headers, or any end-user PII. Only the metadata listed above is sent.
Express.js Integration
Works with Express 4 and 5. Register the middleware before your routes so every request is captured.
Install the SDK
npm install @statvisor/sdkAdd the middleware
import express from "express";
import { express as statvisor } from "@statvisor/sdk";
const app = express();
// Add Statvisor BEFORE your routes
app.use(statvisor({ apiKey: process.env.STATVISOR_API_KEY }));
// Your routes
app.get("/users", (req, res) => {
res.json({ users: [] });
});
app.listen(3000);Set your environment variable
STATVISOR_API_KEY=vl_your_api_key_hereThe middleware must be registered before your route handlers. Place app.use(statvisor(…)) at the top of your middleware stack, before any app.use(router) calls.
Fastify Integration
Works with Fastify v4 and v5. Register as a plugin with fastify.register().
Install the SDK
npm install @statvisor/sdkRegister the plugin
import Fastify from "fastify";
import { fastify as statvisor } from "@statvisor/sdk";
const app = Fastify({ logger: true });
// Register Statvisor plugin
await app.register(statvisor, {
apiKey: process.env.STATVISOR_API_KEY,
});
// Your routes
app.get("/users", async (request, reply) => {
return { users: [] };
});
await app.listen({ port: 3000 });Set your environment variable
STATVISOR_API_KEY=vl_your_api_key_hereNestJS Integration
Coming soon. Native NestJS support is on the roadmap. In the meantime, you can instrument a NestJS app by using the Express adapter — NestJS uses Express under the hood by default, so registering the Express middleware in your main.ts works today.
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { express as statvisor } from "@statvisor/sdk";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Register Statvisor before any other middleware
app.use(statvisor({ apiKey: process.env.STATVISOR_API_KEY }));
await app.listen(3000);
}
bootstrap();Hono Integration
Works with Hono on any runtime — Node.js, Bun, Deno, Cloudflare Workers.
Install the SDK
npm install @statvisor/sdkAdd the middleware
import { Hono } from "hono";
import { createMiddleware } from "@statvisor/sdk";
const app = new Hono();
// Add Statvisor before your routes
app.use("*", createMiddleware({ apiKey: process.env.STATVISOR_API_KEY }));
app.get("/users", (c) => {
return c.json({ users: [] });
});
export default app;Set your environment variable
# Node.js / Bun
STATVISOR_API_KEY=vl_your_api_key_here
# Cloudflare Workers — use wrangler.toml
[vars]
STATVISOR_API_KEY = "vl_your_api_key_here"Next.js Integration
Because Next.js API routes are serverless functions, Statvisor uses a route wrapper pattern. You initialise the SDK once in a shared file and use the returned route helper to wrap each route file's handlers.
Statvisor monitors your API routes (app/api/), not page routes or Server Actions. If your Next.js app proxies to a separate backend, instrument that backend directly with the Express or Fastify integration.
Install the SDK
npm install @statvisor/sdkInitialise once in a shared lib file
Create a file that initialises the SDK and exports the helpers. Import from this file in every API route.
import { nextjs } from "@statvisor/sdk";
export const { route, monitor } = nextjs({
apiKey: process.env.STATVISOR_API_KEY!,
});Wrap your route handlers
Use route() in each API route file. Pass the route path and an object of handlers — the returned object has the same keys ready to export.
import { NextResponse } from "next/server";
import { route } from "@/lib/statvisor";
export const { GET, POST } = route("/api/users", {
GET: async (request) => {
const users = await db.query("SELECT * FROM users");
return NextResponse.json({ users });
},
POST: async (request) => {
const body = await request.json();
const user = await db.create(body);
return NextResponse.json({ user }, { status: 201 });
},
});Dynamic route segments
Pass the route pattern with the dynamic segment. The SDK records it as the pattern (e.g. /api/users/:id), not the actual URL, so routes are properly grouped in your dashboard.
import { NextResponse } from "next/server";
import { route } from "@/lib/statvisor";
export const { GET } = route("/api/users/:id", {
GET: async (request, { params }) => {
const { id } = await params;
const user = await db.findById(id);
if (!user) return NextResponse.json({ error: "Not found" }, { status: 404 });
return NextResponse.json({ user });
},
});Set your environment variable
# Keep this server-side only — do NOT prefix with NEXT_PUBLIC_
STATVISOR_API_KEY=vl_your_api_key_hereThe API key must stay server-side. Never prefix it with NEXT_PUBLIC_ — that would expose it in your client bundle.
Browser Analytics
The browser module is framework-agnostic. It auto-tracks page views and all five Core Web Vitals (LCP, FCP, CLS, TTFB, INP) using native browser APIs — zero dependencies, zero cookies.
Install the SDK
npm install @statvisor/sdkCopy your Frontend Key
vl_fe_. This is a public-safe key — it is safe to include in client-side code.Call initStatvisor once per page load
import { initStatvisor } from "@statvisor/sdk/browser";
// Call once — tracks the current page view + Web Vitals automatically
initStatvisor({ frontendKey: "vl_fe_your_key_here" });Call initStatvisor once per page navigation. In a traditional MPA it goes in a shared script tag. In a SPA (React, Vue, Svelte) call it inside an effect that runs on route change.
React Integration
The @statvisor/sdk/react export provides a <StatvisorAnalytics /> component that handles initialisation automatically. Works with React 18+, Next.js App Router, and Remix.
Install the SDK
npm install @statvisor/sdkAdd to your root layout
Place the component inside <body>. It renders nothing — it only initialises tracking once on mount.
import { StatvisorAnalytics } from "@statvisor/sdk/react";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
{children}
<StatvisorAnalytics frontendKey="vl_fe_your_key_here" />
</body>
</html>
);
}The frontendKey starts with vl_fe_ and is intentionally public-safe — it is fine to include it directly in your source code or as a NEXT_PUBLIC_ env var. It authenticates analytics writes only, never reads.
For Next.js App Router — mark as a client component if needed
The component already has "use client" at the top, so you can import it directly in a Server Component layout without wrapping it.
Structured log management
Statvisor automatically captures a log entry for every request tracked by the backend SDK — no extra configuration needed. You can also emit custom structured logs from your application code using statvisor.log().
Zero-config request logs
Every request captured by the SDK is automatically logged with level, route, status code, and duration.
Custom event logs
Emit structured log events from anywhere in your code — payment failures, retries, signups, anything.
Filterable & searchable
Filter by level (info / warn / error), search by route or message, and poll for new entries in near real-time.
Emitting custom log events
Once the SDK is initialised (via any backend integration), you can call statvisor.log() anywhere in your application. Events are batched and flushed every 5 seconds.
Import and call log()
import * as statvisor from "@statvisor/sdk";
// Basic log
statvisor.log("info", "User signed up", { plan: "pro", userId });
// Warning with context
statvisor.log("warn", "Payment retry triggered", { userId, attempt: 3 });
// Error with details
statvisor.log("error", "Webhook verification failed", { raw: body });Log levels
| Level | When to use |
|---|---|
| info | Normal application events — signups, purchases, background jobs completing. |
| warn | Degraded state — retries, slow operations, expected failures you want to track. |
| error | Unexpected failures that require investigation — exceptions, integration errors. |
Request logs (auto-captured by the middleware) are assigned a level automatically: 5xx → error, 4xx → warn, 2xx/3xx → info.
Viewing and filtering logs
Open any project and click the Logs tab to see all request and custom event logs for that project.
Configuration reference
All options are the same across Express, Fastify, Hono, and Next.js integrations.
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | — | Required. Your project API key (starts with vl_). |
| flushInterval | number | 5000 | How often (ms) the SDK flushes buffered events. |
| batchSize | number | 50 | Max events to include in a single flush. |
| ignoreRoutes | string[] | [] | Route paths to exclude from tracking (e.g. ["/health"]). |
| environment | string | NODE_ENV | Environment tag attached to events (e.g. "production", "staging"). |
| debug | boolean | false | Log SDK activity to console for troubleshooting. |
| ingestUrl | string | statvisor.com/… | Override the ingest endpoint. Only needed for self-hosted deployments. |
Example with all options
import { express as statvisor } from "@statvisor/sdk";
app.use(statvisor({
apiKey: process.env.STATVISOR_API_KEY,
flushInterval: 3000,
batchSize: 50,
ignoreRoutes: ["/health", "/ping", "/_internal"],
environment: process.env.NODE_ENV,
debug: false,
}));Using the dashboard
Once your SDK is sending data, the dashboard shows it in real time.
Projects list
The projects page shows all your monitored APIs. Each card displays the project name, domain, and a quick summary. Click a project to open its analytics dashboard. Use the copy button on a project card to copy the API key to your clipboard.