useIdentify

The declarative identify hook. Calls identify() whenever the user ID changes. No manual useEffect wiring.

Import

import { useIdentify } from "@galacha/react";

Basic usage

function AppShell() {
  const { user } = useAuth();
 
  useIdentify(user?.id, {
    email: user?.email,
    name: user?.name,
    plan: user?.plan,
  });
 
  return <Routes />;
}

Re-runs whenever userId changes. Safe to call with null/undefined when the user isn't logged in — it becomes a no-op.

Signature

function useIdentify(
  userId: string | null | undefined,
  traits?: GalachaTraits,
): void;

What happens under the hood

On every render:

  1. Hook compares the current userId against the previous one
  2. If userId is falsy, nothing happens
  3. If userId changed, calls identify(userId, traits) on the Galacha context
  4. Traits object is compared by its JSON serialization, so object identity doesn't matter — only the contents

Common patterns

Simple auth context

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

Multi-tenant: include team/org

useIdentify(user?.id, {
  email: user?.email,
  team_id: user?.team_id,
  team_name: user?.team_name,
  role: user?.role,
});

The dashboard lets you filter by trait, so sending team_id means you can pull up "all sessions from team_042".

SaaS with plan tier

useIdentify(user?.id, {
  email: user?.email,
  plan: user?.plan,            // "free" | "pro" | "enterprise"
  seats: user?.seat_count,
  mrr: user?.monthly_revenue,
});

Filter the dashboard by plan:pro to watch only paying users. Sort by mrr to triage by value.

Updating traits after a plan change

const [user, setUser] = useState(initialUser);
 
// When the user upgrades
const handleUpgrade = async () => {
  const updated = await api.upgradeToPro();
  setUser(updated);  // useIdentify re-runs automatically with new traits
};

Because useIdentify re-runs on trait changes, you don't need a manual identify() call after the upgrade.

Server-authenticated SSR

If you read the user from a cookie during SSR and pass it down:

// Server: pages/dashboard.tsx
export async function getServerSideProps({ req }) {
  const user = await getUserFromSession(req);
  return { props: { user } };
}
 
// Client: same file
function Dashboard({ user }) {
  useIdentify(user.id, { email: user.email });
  return <div>...</div>;
}

The identify fires on first client render, before the user does anything.

Why not just call identify() in a useEffect?

You can. useIdentify is a thin convenience:

// Manual
const { identify } = useGalacha();
useEffect(() => {
  if (user?.id) identify(user.id, { email: user.email });
}, [user?.id]);
 
// With useIdentify
useIdentify(user?.id, { email: user?.email });

Same result, less boilerplate, correctly handles the ready + traits change cases.

Not for multi-user switching

If your app lets users switch accounts within a single session (uncommon), prefer the imperative identify() from useGalacha(). useIdentify only fires on userId change, which is usually what you want, but the imperative version gives you explicit control.

Related