Introduction
Server-side analytics lets you decide exactly what you track, and ad blockers can't stop it. The Pieowl JavaScript SDK runs in Node.js, so you can track events from your backend, API routes and background jobs.
Pieowl gives you product analytics, such as funnels, retention and user profiles, without cookies.
Prerequisites
- A Node.js project
- A Pieowl account (start a 14-day free trial)
- Your Client ID and Client Secret from the Pieowl dashboard
Important: Server-side tracking needs a
clientSecret.
Step 1: Install the SDK
Install the Pieowl JavaScript SDK:
npm install @pieowl/sdkOr with pnpm:
pnpm add @pieowl/sdkStep 2: Initialize Pieowl
Create a Pieowl instance with your credentials:
import { Pieowl } from '@pieowl/sdk';
export const pieowl = new Pieowl({
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET', // Required on the server
});Security note: Never put your
clientSecretin browser code. Use environment variables in production.
Using environment variables
import { Pieowl } from '@pieowl/sdk';
export const pieowl = new Pieowl({
clientId: process.env.PIEOWL_CLIENT_ID,
clientSecret: process.env.PIEOWL_CLIENT_SECRET,
});PIEOWL_CLIENT_ID=your-client-id
PIEOWL_CLIENT_SECRET=your-client-secretStep 3: Track events
Track events anywhere in your Node.js app:
import { pieowl } from '@/lib/pieowl';
export async function POST(request) {
const { email, name } = await request.json();
// Your signup logic
const user = await createUser({ email, name });
// Track the signup
pieowl.track('user_signed_up', {
profileId: user.id,
source: 'website',
});
return Response.json({ success: true, user });
}Track API requests
import { pieowl } from '@/lib/pieowl';
export function analyticsMiddleware(req, res, next) {
pieowl.track('api_request', {
method: req.method,
path: req.path,
});
next();
}Track background jobs
import { pieowl } from '@/lib/pieowl';
export async function sendEmailJob(userId, emailData) {
try {
await sendEmail(emailData);
pieowl.track('email_sent', {
profileId: userId,
email_type: emailData.type,
});
} catch (error) {
pieowl.track('email_failed', {
profileId: userId,
email_type: emailData.type,
error: error.message,
});
}
}Passing profileId links the event to that user's profile.
Step 4: Identify users
Use identify to save a user's name, email and custom properties to their profile:
import { pieowl } from '@/lib/pieowl';
export async function POST(request) {
const { email, password } = await request.json();
const user = await authenticateUser(email, password);
// Save the profile
pieowl.identify({
profileId: user.id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
properties: {
plan: user.plan,
signupDate: user.createdAt,
},
});
// Track the login
pieowl.track('user_logged_in', {
profileId: user.id,
method: 'email',
});
return Response.json({ success: true, user });
}One instance on a server handles many users. identify also remembers the profile ID on that instance, so a later event without a profileId could be linked to the wrong person. Always pass profileId with each event on the server.
Track user actions
import { pieowl } from '@/lib/pieowl';
export async function POST(request) {
const { userId, productId, amount } = await request.json();
pieowl.track('purchase_completed', {
profileId: userId, // Link the event to the user
product_id: productId,
amount,
currency: 'USD',
});
await processPurchase(userId, productId, amount);
return Response.json({ success: true });
}Verify your setup
- Call the API endpoints that track events
- Run a background job that tracks events
- Open the Pieowl dashboard
- Check the realtime view to see events come in
Not seeing events?
- Check your server logs for errors
- Make sure your Client ID and Client Secret are correct
- Make sure you passed
clientSecret(it is required on the server)
Common patterns
Track webhook events
import { pieowl } from '@/lib/pieowl';
export async function POST(request) {
const payload = await request.json();
pieowl.track('webhook_received', {
source: payload.source,
event_type: payload.type,
});
await processWebhook(payload);
return Response.json({ success: true });
}Set global properties
Global properties are added to every event this instance sends.
import { Pieowl } from '@pieowl/sdk';
export const pieowl = new Pieowl({
clientId: process.env.PIEOWL_CLIENT_ID,
clientSecret: process.env.PIEOWL_CLIENT_SECRET,
});
pieowl.setGlobalProperties({
app_version: process.env.APP_VERSION,
environment: process.env.NODE_ENV,
server_region: process.env.SERVER_REGION,
});Track errors
import { pieowl } from '@/lib/pieowl';
export function errorHandler(err, req, res, next) {
pieowl.track('error_occurred', {
error_message: err.message,
path: req.path,
method: req.method,
});
res.status(500).json({ error: 'Internal server error' });
}Increment user properties
The profile must already exist, for example from an earlier identify call.
import { pieowl } from '@/lib/pieowl';
// Add 1 to the login count
pieowl.increment({
profileId: user.id,
property: 'login_count',
value: 1,
});Serverless and Vercel
On serverless platforms like Vercel, use waitUntil so the event is sent before the function stops:
import { waitUntil } from '@vercel/functions';
import { pieowl } from '@/lib/pieowl';
export default async function handler(req, res) {
// Responds right away and keeps the function alive until the event is sent
waitUntil(pieowl.track('important_event', { foo: 'bar' }));
return res.status(200).json({ success: true });
}Next steps
Why do I need a clientSecret for server-side tracking?
A browser sends an origin that Pieowl checks against your site settings. A server does not. The client secret proves the events come from you and blocks anyone else from sending events to your site.
Will tracking block my app?
No. Each call sends the event in the background and returns a promise. You only need to await it in serverless functions, so the event is sent before the function stops.
Does Pieowl help with GDPR?
Pieowl is built for GDPR: no cookies, no stored IPs. With server-side tracking, you also decide exactly which data you send. Read our cookieless analytics guide to learn more.