@getfluxly/react

React SDK

Provider and hooks that wrap @getfluxly/browser for React 18+ and any React-based framework (Next.js, Remix, TanStack Start). SSR-safe: all hooks return no-ops during SSR, and the provider's effects never touch window on the server.

Install

npm install @getfluxly/react @getfluxly/browser react

@getfluxly/browser is a peer dependency. Install it alongside @getfluxly/react.

Provider setup

Wrap your app tree in GFluxProvider once. In Next.js App Router, you must place this inside a "use client" boundary. The recommended pattern is a dedicated providers.tsx wrapper:

// app/providers.tsx
"use client";
import { GFluxProvider } from "@getfluxly/react";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <GFluxProvider apiKey={process.env.NEXT_PUBLIC_GFLUX_API_KEY!}>
      {children}
    </GFluxProvider>
  );
}

Then use it in your root layout (which can remain a Server Component):

// app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Note: apiKey is captured at first mount. Swapping it later warns in dev and is ignored. Remount the provider to switch keys.

Quick start

// app/sign-up-button.tsx
"use client";
import { useTrack, useIdentify } from "@getfluxly/react";

export function SignUpButton() {
  const track = useTrack();
  const identify = useIdentify();

  return (
    <button onClick={async () => {
      const user = await signUp();
      identify(user.id, { email: user.email, plan: user.plan });
      track("user_signed_up", { plan: user.plan });
    }}>
      Sign up
    </button>
  );
}

Hooks

HookReturnsNotes
useTrack<TEvents>()(name, props?) => voidGeneric type parameter enables typed events and IDE autocomplete
useIdentify()(externalId, traits?) => voidSecond call with a different externalId is dropped with a warn log
usePage()(properties?) => voidManual page view. Most apps do not need this
useConsent(){ status, optIn, optOut }status is "unknown" / "opted_in" / "opted_out"
useGFlux()GFluxBrowser | nullRaw SDK instance, or null during SSR / before mount

All hooks return stable references and are safe to place in useEffect dependency arrays.

Hook reference

useTrack

type AppEvents = {
  user_signed_up: { plan: "free" | "pro" };
  feature_used:   { feature_name: string; ms_to_first_use: number };
};

const track = useTrack<AppEvents>();
track("user_signed_up", { plan: "pro" });   // valid
track("user_signed_up", { plan: "gold" });  // type error
track("typo_event", {});                    // unknown event: type error

Without the generic, track accepts any string name and any properties object.

useIdentify

Returns a stable identify callback. Calling identify twice with different externalId values in the same session is a bug in identity stitching. The second call is dropped client-side and a warn log is emitted. To re-identify, call reset() via useGFlux() first.

usePage

Returns a stable page callback for manual page view events. Most apps do not need to call this explicitly because the browser SDK autocaptures SPA route changes. Call it only when you want a custom page view with extra properties:

const page = usePage();
page({ section: "billing", plan: "pro" });

useConsent

const { status, optIn, optOut } = useConsent();

status values:

ValueMeaning
"unknown"SSR path, or EU implicit-pending state (events buffered until optIn() is called)
"opted_in"User has consented; events flow normally
"opted_out"User has declined; events are suppressed

useGFlux

Returns the raw GFluxBrowser instance, or null during SSR and before the provider has mounted. Use this for methods that do not have a dedicated hook:

const gflux = useGFlux();

// Reset anonymous ID and drop external identity (e.g. on sign-out)
gflux?.reset();

// Tear down the client entirely
gflux?.destroy();

// Inspect internal counters and queued events
gflux?.__debug();

Provider props

PropTypeNotes
apiKeystringPublishable key (gflux_pub_*). Required unless client is supplied.
apiHoststringDefaults to https://api.getfluxly.com
configPartial<GFluxConfig>Forwarded to initGFlux (autocapture toggles, consentMode, region, flushIntervalMs, etc.)
clientGFluxBrowser | nullInject a pre-constructed instance. When set, apiKey/apiHost/config are ignored. Useful for tests.

If both apiKey and client are omitted, the provider renders children and every hook returns a no-op. This is useful for environments where analytics is intentionally disabled.

SSR and Server Components

All hooks are SSR-safe:

Errors

track, identify, and page are fire-and-forget and never throw to caller code. Errors land in the configured logger (defaults to console.warn) and are reflected in __debug() counters.

The provider throws at construction if apiKey is malformed. This surfaces as a render error in development immediately.

Privacy and consent

Consent behavior (GPC, EU buffering, explicit opt-in/out) is inherited entirely from @getfluxly/browser. The React wrapper does not add or change any privacy logic. See the @getfluxly/browser docs for the full posture.

Use with Next.js

The providers.tsx pattern above is the recommended approach for App Router. If you prefer a more integrated setup, @getfluxly/next ships a Next-aware provider with automatic route-change tracking. See the Next SDK.