LANDSCAPE

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>
  );
}

Constraints