plausible-node-client
v1.0.0
Published
A lightweight Node.js client for sending custom events to Plausible Analytics via the Events API.
Maintainers
Readme
plausible-node-client
A lightweight, zero-dependency Node.js client for sending events to Plausible Analytics from a back-end server using the Events API.
Works with Node.js 18+ (uses the built-in fetch API). Fully typed with TypeScript.
Installation
npm install plausible-node-clientQuick start
import { PlausibleClient } from "plausible-node-client";
const plausible = new PlausibleClient({ domain: "example.com" });Sending a custom event
await plausible.sendEvent({
name: "Signup", // custom event name
url: "https://example.com/register", // page where the event happened
userAgent: req.headers["user-agent"] ?? "",
ip: req.ip, // visitor's IP for geo + dedup
props: {
plan: "pro",
referral_code: "SUMMER24",
},
});Sending a pageview
await plausible.sendPageview({
url: "https://example.com/blog/my-post",
userAgent: req.headers["user-agent"] ?? "",
ip: req.ip,
});Revenue tracking (e-commerce)
await plausible.sendEvent({
name: "Purchase",
url: "https://example.com/checkout/success",
userAgent: req.headers["user-agent"] ?? "",
ip: req.ip,
revenue: { currency: "USD", amount: 49.99 },
props: { product_id: "sku-42" },
});Express.js middleware example
import express from "express";
import { PlausibleClient, PlausibleError } from "plausible-node-client";
const app = express();
const plausible = new PlausibleClient({ domain: "example.com" });
app.post("/api/checkout", async (req, res) => {
// ... process checkout ...
try {
await plausible.sendEvent({
name: "Purchase",
url: `https://example.com${req.originalUrl}`,
userAgent: req.headers["user-agent"] ?? "",
ip: req.ip,
revenue: { currency: "USD", amount: 99.0 },
});
} catch (err) {
if (err instanceof PlausibleError) {
console.warn("Plausible tracking failed:", err.message, "status:", err.statusCode);
}
}
res.json({ success: true });
});API
new PlausibleClient(options)
| Option | Type | Default | Description |
|---|---|---|---|
| domain | string | required | Domain name as configured in your Plausible dashboard. |
| baseUrl | string | "https://plausible.io" | Override for self-hosted Plausible instances. |
| timeoutMs | number | 5000 | Request timeout in milliseconds. |
client.sendEvent(options): Promise<void>
| Option | Type | Required | Description |
|---|---|---|---|
| name | string | ✅ | Event name. Use "pageview" for page views. |
| url | string | ✅ | Full URL where the event occurred. |
| userAgent | string | ✅ | Visitor's User-Agent (from the incoming request header). |
| ip | string | — | Visitor's IP address. Required for correct geo & deduplication when calling from a server. |
| referrer | string | — | Referrer URL. |
| props | Record<string, string \| number \| boolean> | — | Custom properties (max 30 pairs). |
| revenue | { currency: string; amount: number \| string } | — | Revenue data for e-commerce tracking. |
| interactive | boolean | — | Set false to exclude from bounce-rate calculations. Default true. |
client.sendPageview(options): Promise<void>
Shorthand for sendEvent({ name: "pageview", ...options }).
PlausibleError
Thrown on HTTP errors or network failures.
| Property | Type | Description |
|---|---|---|
| message | string | Human-readable error description. |
| statusCode | number \| undefined | HTTP status returned by Plausible (absent for network errors). |
| cause | unknown | Original caught error for network failures. |
Important notes on visitor tracking
Because events are sent server-side, you must forward the visitor's real User-Agent and IP address from the original HTTP request. Without these, every event will appear to come from a single unique visitor (your server).
// Express example – forward both headers
await plausible.sendEvent({
name: "Download",
url: `https://example.com${req.path}`,
userAgent: req.headers["user-agent"] ?? "", // forwarded UA
ip: req.ip, // forwarded IP
});License
MIT
