Help · Install
Install on Next.js
In the root layout, with next/script. Page changes are counted automatically.
App Router
Add the script to your root layout, app/layout.tsx:
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script defer src="https://bearingstats.com/s.js" data-site="YOUR_SITE_ID" strategy="afterInteractive" />
</body>
</html>
);
}Pages Router
Add the same Script to pages/_app.tsx, next to your Component.
Custom events
Send your events through one small function. An event sent when a page appears (in a useEffect) often comes before s.js has loaded: this function keeps it in a queue instead of losing it, and types window.bearing for TypeScript. Create lib/analytics.ts:
// lib/analytics.ts: one door for your events
type Props = Record<string, string | number | boolean>;
type Bearing = ((name: string, options?: { props?: Props }) => void) & { q?: unknown[][] };
declare global {
interface Window {
bearing?: Bearing;
}
}
/** Sends an event to Bearing. Calls made before s.js has loaded wait in a queue. */
export function track(name: string, props?: Props) {
if (typeof window === "undefined") return;
if (!window.bearing) {
const queue: Bearing = (...args) => {
(queue.q ??= []).push(args);
};
window.bearing = queue;
}
window.bearing(name, props ? { props } : undefined);
}Then call it from any client component:
"use client";
import { useEffect } from "react";
import { track } from "@/lib/analytics";
export function Pricing() {
useEffect(() => track("pricing_view"), []);
return <button onClick={() => track("signup", { plan: "pro" })}>…</button>;
}Good to know
- Client-side navigations (
Link,router.push) are counted as pageviews, with no extra code. - Custom events: use
track()above. What you can send is in Custom events. - In development on
localhost, nothing is counted unless you adddata-allow-localhost.