React
Wrap the tree with LandscapeProvider and emit page views from the router.
Install
pnpm add @hyperreal/landscape-core @hyperreal/landscape-react
Wrap the tree
import { LandscapeProvider } from "@hyperreal/landscape-react";
export function App({ children }: { children: React.ReactNode }) {
return (
<LandscapeProvider config={{ endpoint: "/api/events" }}>
{children}
</LandscapeProvider>
);
}
Pass client to share one instance across roots. The provider does not destroy an external client on unmount. A provider-created client is destroyed on unmount.
Record custom events
import { LandscapeProvider, useIdentify, usePageView, useTrack } from "@hyperreal/landscape-react";
export function Root({ children }: { children: React.ReactNode }) {
return (
<LandscapeProvider config={{ endpoint: "/api/events" }}>
{children}
</LandscapeProvider>
);
}
function Checkout() {
const track = useTrack();
const identify = useIdentify();
const page = usePageView();
return (
<button
onClick={() => {
identify("user_123", { plan: "pro" });
track("checkout_started", { cart_total: 49 });
page({ path: "/checkout" });
}}
>
Continue
</button>
);
}
| Hook | Package | Behavior |
|---|---|---|
useTrack() |
@hyperreal/landscape-react |
bound track; throws outside LandscapeProvider |
useIdentify() |
@hyperreal/landscape-react |
bound identify |
usePageView() |
@hyperreal/landscape-react |
bound page; pass { enabled: false } to no-op |
useLandscape() |
@hyperreal/landscape-react |
raw LandscapeClient; throws outside LandscapeProvider |
Use useLandscape() for flush, setConsent, and registerPlugin.
Track route changes
Render one tracker inside LandscapeProvider. Each emits $pageview and dedupes identical pathname + search keys.
React Router
Render inside both LandscapeProvider and the router tree (packages/react/src/react-router.ts).
import { BrowserRouter } from "react-router";
import { LandscapeProvider } from "@hyperreal/landscape-react";
import { ReactRouterTracker } from "@hyperreal/landscape-react/react-router";
export function App({ children }: { children: React.ReactNode }) {
return (
<LandscapeProvider config={{ endpoint: "/api/events" }}>
<BrowserRouter>
<ReactRouterTracker />
{children}
</BrowserRouter>
</LandscapeProvider>
);
}
Next.js App Router
Client component. Typical location: a root layout wrapper (packages/react/src/next-app.ts).
"use client";
import { LandscapeProvider } from "@hyperreal/landscape-react";
import { NextAppRouterTracker } from "@hyperreal/landscape-react/next-app";
export function Analytics({ children }: { children: React.ReactNode }) {
return (
<LandscapeProvider config={{ endpoint: "/api/events" }}>
<NextAppRouterTracker />
{children}
</LandscapeProvider>
);
}
Next.js Pages Router
import type { AppProps } from "next/app";
import { LandscapeProvider } from "@hyperreal/landscape-react";
import { NextPagesRouterTracker } from "@hyperreal/landscape-react/next-pages";
export default function App({ Component, pageProps }: AppProps) {
return (
<LandscapeProvider config={{ endpoint: "/api/events" }}>
<NextPagesRouterTracker />
<Component {...pageProps} />
</LandscapeProvider>
);
}