React / Next.js

Install via the @galacha/react npm package. Works in React 17+, Next.js 13+ (App Router and Pages Router), Vite, CRA, Remix, TanStack Start.

Install

npm install @galacha/react
# or
pnpm add @galacha/react
# or
yarn add @galacha/react

Peer dependency: react >= 17. Zero runtime dependencies. The package lazy-loads the recorder from sdk.galacha.me at runtime.

Set the project key

Use your framework's env var convention:

FrameworkVariable
Next.jsNEXT_PUBLIC_GALACHA_PROJECT_KEY
ViteVITE_GALACHA_PROJECT_KEY
CRAREACT_APP_GALACHA_PROJECT_KEY
Expo (React Native Web)EXPO_PUBLIC_GALACHA_PROJECT_KEY
# .env.local (Next.js)
NEXT_PUBLIC_GALACHA_PROJECT_KEY=4d4b83bcd00acd4cbc8ab5a7d94bab5abbc31887dbc1bf3f

Mount the Provider

Next.js App Router

// app/layout.tsx
import { GalachaProvider } from "@galacha/react";
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <GalachaProvider projectKey={process.env.NEXT_PUBLIC_GALACHA_PROJECT_KEY!}>
          {children}
        </GalachaProvider>
      </body>
    </html>
  );
}

GalachaProvider is already a client component. You can drop it into a server layout.tsx — Next.js handles the boundary automatically.

Next.js Pages Router

// pages/_app.tsx
import { GalachaProvider } from "@galacha/react";
import type { AppProps } from "next/app";
 
export default function App({ Component, pageProps }: AppProps) {
  return (
    <GalachaProvider projectKey={process.env.NEXT_PUBLIC_GALACHA_PROJECT_KEY!}>
      <Component {...pageProps} />
    </GalachaProvider>
  );
}

Vite / CRA

// src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { GalachaProvider } from "@galacha/react";
import App from "./App";
 
createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <GalachaProvider projectKey={import.meta.env.VITE_GALACHA_PROJECT_KEY}>
      <App />
    </GalachaProvider>
  </StrictMode>,
);

Remix

// app/root.tsx
import { GalachaProvider } from "@galacha/react";
 
export default function App() {
  return (
    <html>
      <body>
        <GalachaProvider projectKey={window.ENV.GALACHA_PROJECT_KEY}>
          <Outlet />
        </GalachaProvider>
        <Scripts />
      </body>
    </html>
  );
}

You'll need to inject ENV via loader + useLoaderData to expose the env var to the client.

Identify the user

Declarative — recommended:

import { useIdentify } from "@galacha/react";
 
function Shell() {
  const { user } = useAuth();
  useIdentify(user?.id, { email: user?.email, name: user?.name });
  return <Routes />;
}

Imperative:

import { useGalacha } from "@galacha/react";
 
function LoginForm() {
  const { identify } = useGalacha();
  const handleLogin = async (email, password) => {
    const user = await api.login(email, password);
    identify(user.id, { email: user.email });
  };
}

Mask sensitive views

import { PrivateBlock } from "@galacha/react";
 
<PrivateBlock>
  <CreditCardForm />
</PrivateBlock>

Block mode (stronger — DOM subtree dropped entirely):

<PrivateBlock block>
  <SSNInput />
</PrivateBlock>

See PrivateBlock for the full API.

What the package exports

ExportPurpose
<GalachaProvider>Wraps your tree, loads the SDK, calls init()
useGalacha()Hook returning { ready, identify, stop, sessionId, visitorId }
useIdentify()Declarative identify hook
<PrivateBlock>Mark a DOM subtree as private
GalachaConfig, GalachaTraits (types)For TypeScript consumers

What this package does NOT do

  • Ship the recorder bundle — it loads sdk.galacha.me/sdk/latest/galacha.umd.js at runtime. Browser caching is shared across sites that use Galacha
  • Support SSR event capture. Recording only runs in the browser
  • Expose track() or flush() — those are React Native features

Common pitfalls

ProblemFix
SSR error about windowUse <GalachaProvider>, not manual useEffect. It's a client component.
Env var undefined in the browserUse the framework prefix: NEXT_PUBLIC_*, VITE_*, REACT_APP_*
StrictMode double-bootSafe. Boot logic is a singleton on window.__galachaBoot.
useGalacha must be used inside <GalachaProvider>Wrap a common ancestor — usually your root layout
Calling stop() on logout breaks re-recordingSkip the stop call. Let the next identify() retag the session.

Related