App Router and Pages Router, which take different imports.
npm i @firstrun/analyticsimport { Analytics } from "@firstrun/analytics/next";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Analytics sourceKey="fr_xxxxxxxxxxxxxxxx" host="https://app.firstrun.app" />
</body>
</html>
);
}The component is already "use client"; the layout does not have to be. Routes come from usePathname() alone, so no Suspense boundary is needed. It is sourceKey and not key because React consumes a prop called key before the component ever sees it.
import type { AppProps } from "next/app";
import { Analytics } from "@firstrun/analytics/react";
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<Analytics sourceKey="fr_xxxxxxxxxxxxxxxx" host="https://app.firstrun.app" />
</>
);
}/next turns the tag's own history watching off and reports routes from usePathname() instead. next/navigation does not exist in the Pages Router, and the App Router does not move through history in a way the tag can watch, so /react there under-reports navigations.Nothing is stored and nothing is sent until consent is granted.
import { consent, event, error, log, identify } from "@firstrun/analytics";
consent(true);
event("download_clicked", { platform: "windows" });
error(err);
log({ name: "checkout_stalled", severity: 13, attributes: { step: 3 } });
identify("u_42");event writes at INFO and error at ERROR, both filling in the conventional attributes. log takes any event you like. Attribute values are JSON, so a number stays a number.
With consent granted the component also writes page_view, session_start, page_leave, outbound_click, file_download, form_submit and web_vital on its own. The props autoPage, autoOutbound, autoVitals, autoForms and trackLeave each turn one group off.