Analytics shows you how people use your Remix app. The Pieowl Web SDK works with Remix's client-side navigation. You get automatic page views, custom events and user identification.
The tracker never sets a cookie, so in many cases you don't need a consent banner for your analytics. See when you still do.
Prerequisites
- A Remix project (Vite-based)
- A Pieowl account (start a 14-day free trial)
- Your Client ID from the Pieowl dashboard
Install the SDK
The Pieowl Web SDK is a small package that runs in any browser app. Install it with npm. pnpm and yarn work the same way.
npm install @pieowl/webCreate a Pieowl instance
Create one file for your Pieowl instance. It runs in the browser, so make sure it only loads on the client.
import { Pieowl } from '@pieowl/web';
export const pieowl = new Pieowl({
clientId: 'YOUR_CLIENT_ID',
});The .client.ts suffix tells Remix to keep this module out of the server build. Pieowl tracks a page view each time the URL changes, which works with Remix's client-side navigation. What Pieowl collects by itself (page views, clicks on links to other sites, data-track clicks) is set in Settings → Site → What Pieowl counts, not in code.
Using environment variables
Your Client ID is not a secret, but you may want a different one per environment. With Remix on Vite, read it from a VITE_ variable.
import { Pieowl } from '@pieowl/web';
export const pieowl = new Pieowl({
clientId: import.meta.env.VITE_PIEOWL_CLIENT_ID,
});VITE_PIEOWL_CLIENT_ID=your-client-idInitialize in root.tsx
Load the instance in your root component inside useEffect, so it only runs in the browser.
import { useEffect } from 'react';
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from '@remix-run/react';
export default function App() {
useEffect(() => {
// The dynamic import only runs in the browser
import('./lib/pieowl.client');
}, []);
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}Track page views
By default, Pieowl tracks a page view each time the URL changes. This works with Remix's <Link> navigation.
If you want to track page views yourself, for example to add route data, call screenView from a component that uses Remix's useLocation hook.
import { useEffect } from 'react';
import { useLocation } from '@remix-run/react';
export function PageTracker() {
const location = useLocation();
useEffect(() => {
import('../lib/pieowl.client').then(({ pieowl }) => {
pieowl.screenView({
search: location.search,
});
});
}, [location.pathname, location.search]);
return null;
}screenView uses the current URL and page title. Add this component to your root layout. If you use it, turn off Page views in Settings → Site so page views are not counted twice.
Track custom events
The SDK only runs in the browser. Load it with a dynamic import, or make sure your tracking code runs in event handlers or useEffect.
export function SignupButton() {
const handleClick = () => {
import('../lib/pieowl.client').then(({ pieowl }) => {
pieowl.track('button_clicked', {
button_name: 'signup',
button_location: 'hero',
});
});
};
return (
<button type="button" onClick={handleClick}>
Sign Up
</button>
);
}Create a tracking hook
For cleaner code, put the dynamic import in a custom hook.
import { useCallback } from 'react';
import type { Pieowl } from '@pieowl/web';
type TrackFn = Pieowl['track'];
type IdentifyFn = Pieowl['identify'];
export function useTrack() {
return useCallback<TrackFn>((name, properties) => {
import('../lib/pieowl.client').then(({ pieowl }) => {
pieowl.track(name, properties);
});
}, []);
}
export function useIdentify() {
return useCallback<IdentifyFn>((payload) => {
import('../lib/pieowl.client').then(({ pieowl }) => {
pieowl.identify(payload);
});
}, []);
}Now your components are simpler.
import { useTrack } from '../hooks/usePieowl';
export function SignupButton() {
const track = useTrack();
const handleClick = () => {
track('button_clicked', {
button_name: 'signup',
button_location: 'hero',
});
};
return (
<button type="button" onClick={handleClick}>
Sign Up
</button>
);
}Track form submissions
Remix uses form actions for data changes. You can track a submit in your action on the server, or in the browser.
import { Form } from '@remix-run/react';
import { useTrack } from '../hooks/usePieowl';
export default function Contact() {
const track = useTrack();
const handleSubmit = () => {
track('form_submitted', {
form_name: 'contact',
form_location: 'contact-page',
});
};
return (
<Form method="post" onSubmit={handleSubmit}>
<input type="email" name="email" placeholder="Your email" required />
<button type="submit">Submit</button>
</Form>
);
}Use data attributes for declarative tracking
You can also track clicks with data-track attributes, without writing JavaScript.
<button
data-track="button_clicked"
data-button-name="signup"
data-button-location="hero"
>
Sign Up
</button>When someone clicks this button, Pieowl sends a button_clicked event. The other data-* attributes become properties in camelCase: buttonName and buttonLocation. This needs Clicks you marked in your code to be on in Settings → Site (it is by default).
Identify users
When a user logs in, call identify to link their activity to a profile. In Remix, the user data usually comes from a loader.
import { useEffect } from 'react';
import { useLoaderData } from '@remix-run/react';
import type { LoaderFunctionArgs } from '@remix-run/node';
import { json } from '@remix-run/node';
import { getUser } from '../lib/auth.server';
export async function loader({ request }: LoaderFunctionArgs) {
const user = await getUser(request);
return json({ user });
}
export default function Dashboard() {
const { user } = useLoaderData<typeof loader>();
useEffect(() => {
if (user) {
import('../lib/pieowl.client').then(({ pieowl }) => {
pieowl.identify({
profileId: user.id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
properties: {
plan: user.plan,
},
});
});
}
}, [user]);
return <div>Welcome, {user?.firstName}!</div>;
}Pieowl keeps the profile ID in memory, not in a cookie or local storage. After a full page reload, call identify again.
Clear user data on logout
When a user logs out, clear the profile so new events are not linked to them.
import { Form } from '@remix-run/react';
export function LogoutButton() {
const handleClick = () => {
import('../lib/pieowl.client').then(({ pieowl }) => {
pieowl.clear();
});
};
return (
<Form method="post" action="/logout">
<button type="submit" onClick={handleClick}>
Logout
</button>
</Form>
);
}Server-side tracking
To track events in loaders, actions or resource routes, use the @pieowl/sdk package instead of the web SDK. Server-side tracking needs a client secret.
import { Pieowl } from '@pieowl/sdk';
export const pieowl = new Pieowl({
clientId: process.env.PIEOWL_CLIENT_ID!,
clientSecret: process.env.PIEOWL_CLIENT_SECRET!,
});import type { ActionFunctionArgs } from '@remix-run/node';
import { json } from '@remix-run/node';
import { pieowl } from '../lib/pieowl.server';
export async function action({ request }: ActionFunctionArgs) {
const payload = await request.json();
pieowl.track('webhook_received', {
source: payload.source,
event_type: payload.type,
});
return json({ success: true });
}Verify your setup
Open your Remix app and visit a few pages. Click the elements that send custom events. Then open the Pieowl dashboard and check the realtime view.
No events? Check the browser console for errors. Make sure your Client ID is correct and that no ad blocker is blocking requests to api.pieowl.com. The Network tab in your browser's developer tools shows whether requests are being sent.
Next steps
The Web SDK can do more, such as profile counters and event filters. Read the Web SDK documentation for the full API.
For more on server-side tracking, see the Node.js analytics guide, which covers the @pieowl/sdk package in detail.
Does Pieowl work with Remix's SSR?
Yes. The web SDK tracks events in the browser after hydration. For server-side events in loaders and actions, use the @pieowl/sdk package with your client secret.
Why do I need a client secret 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.
Does Pieowl use cookies?
No. The tracker never sets a cookie and stores nothing on your visitors' devices. In many cases that means no consent banner for your analytics. See Do you need a cookie banner?.
Does Pieowl help with GDPR?
Pieowl is built for GDPR: no cookies, no stored IPs. Your data is stored in the EU. Ask your legal advisor about your own setup.