@getfluxly/next

Next.js SDK

App Router-native wiring for GetFluxly. Drop-in <GFluxScript> for client autocapture, server-side track / identify / alias for Server Actions and Route Handlers, and a middleware wrapper that forwards client IP and geo into downstream handlers.

Install

npm install @getfluxly/next @getfluxly/react @getfluxly/browser @getfluxly/node

react and next are peer dependencies already in your project. The four @getfluxly/* packages are peers too. Install them all so npm deduplicates the runtime.

Quickstart

1. Set env vars

Create or update .env.local at your project root:

# .env.local
NEXT_PUBLIC_GFLUX_API_KEY=gflux_pub_...
GFLUX_SERVER_TOKEN=gflux_secret_...

NEXT_PUBLIC_GFLUX_API_KEY is the publishable key, safe to expose to the browser. GFLUX_SERVER_TOKEN is the server key; never expose it client-side.

2. Mount GFluxScript in app/layout.tsx

import { GFluxScript } from "@getfluxly/next/client";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <GFluxScript apiKey={process.env.NEXT_PUBLIC_GFLUX_API_KEY!} />
        {children}
      </body>
    </html>
  );
}

That enables client-side autocapture (pageviews, clicks, forms, errors). Open the GetFluxly dashboard live feed and events arrive within a second.

Warning: Mount <GFluxScript> or <GFluxProvider>, not both. Each constructs its own client, so mounting both sends every event twice.

3. Track from a Server Action (optional)

// app/actions/subscribe.ts
"use server";
import { track } from "@getfluxly/next/server";

export async function signUpAction(formData: FormData) {
  const user = await createUser(formData);
  await track("user_signed_up", {
    externalId: user.id,
    properties: { plan: user.plan },
  });
  return { ok: true };
}

The server helper flushes immediately, which is the right default for short-lived serverless invocations. For long-running servers, use getServerClient() and manage the lifecycle yourself.

Client: @getfluxly/next/client

GFluxScript

<GFluxScript> wraps next/script with strategy="afterInteractive" by default. Set strategy="lazyOnload" to defer past hydration.

PropTypeDescription
apiKeystringPublishable key (gflux_pub_*). Renders nothing when missing.
apiHoststringAPI base URL. Defaults to https://api.getfluxly.com.
noncestringCSP nonce, passed through to <script>.
strategy"afterInteractive" | "lazyOnload"next/script load strategy. Defaults to "afterInteractive".

React hooks

@getfluxly/next/client re-exports all five React hooks from @getfluxly/react: useGFlux, useTrack, useIdentify, usePage, and useConsent. It also re-exports GFluxProvider if you prefer the React-state-based pattern instead of the script tag.

Server: @getfluxly/next/server

This subpath is gated to Node-only via the package exports map. Importing it from a client component fails the Next build with a server-only error, so your server token can never leak into the browser bundle.

getServerClient()

Returns the singleton @getfluxly/node client for the current process. It is cached on globalThis.__gflux_node__ so Next.js hot-reload does not leak background flush timers between module re-evaluations.

import { getServerClient } from "@getfluxly/next/server";

const client = getServerClient();
await client.track("invoice_paid", {
  externalId: "user_42",
  properties: { amount: 99 },
});
await client.flush();

track / identify / alias

Convenience helpers on top of the singleton. All three flush immediately.

import { track, identify, alias } from "@getfluxly/next/server";

await track("event_name", { externalId, properties });
await identify({ externalId, anonymousId, traits });
await alias({ userId, previousId });
HelperRequired fieldsNotes
track(event, opts)event stringopts.externalId or opts.anonymousId required
identify(opts)externalId or anonymousIdMerges traits into the user profile
alias(opts)userId, previousIdStitches an anonymous ID into a known user

Middleware: @getfluxly/next/middleware

withGFluxMiddleware

Wraps a Next.js middleware function and mutates request headers before calling your handler, so downstream Server Components and Route Handlers can read them.

// middleware.ts
import { withGFluxMiddleware } from "@getfluxly/next/middleware";
import { NextResponse } from "next/server";

export default withGFluxMiddleware(
  async (request) => {
    return NextResponse.next();
  },
  { forwardIp: true, forwardGeo: true },
);

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

Headers added when the corresponding option is enabled:

HeaderSourceDefault
x-gflux-iprequest.ip or x-real-ipOff
x-gflux-countryrequest.geo.countryOff
x-gflux-regionrequest.geo.regionOff

Nothing is forwarded by default. Both forwardIp and forwardGeo are opt-in. Enable them only if you intend to enrich server-side track() calls with the client's network identity; forwarding changes the data semantics for downstream consumers.

gfluxEnv()

Type-safe reader for the three Next.js env vars. Use it in any server file to assert vars are present at startup rather than at first use.

import { gfluxEnv } from "@getfluxly/next";

const env = gfluxEnv({ requirePublicKey: true, requireServerToken: true });
// env.publicKey   = NEXT_PUBLIC_GFLUX_API_KEY
// env.serverToken = GFLUX_SERVER_TOKEN
// env.apiHost     = NEXT_PUBLIC_GFLUX_API_HOST (optional, has default)
OptionBehavior
requirePublicKeyThrows if NEXT_PUBLIC_GFLUX_API_KEY is missing. Names the variable in the error message.
requireServerTokenThrows if GFLUX_SERVER_TOKEN is missing. Names the variable in the error message.

Error handling

Browser hooks (useTrack, usePage, etc.) are fire-and-forget. They never throw to caller code; a failed delivery is silently retried or dropped, keeping your UI unaffected.

Server helpers throw GFluxNodeError on failure. Wrap server-side calls in try/catch if you need to handle delivery failures explicitly:

import { track, GFluxNodeError } from "@getfluxly/next/server";

try {
  await track("checkout_completed", { externalId: userId, properties: { total } });
} catch (err) {
  if (err instanceof GFluxNodeError) {
    // log err.code, err.status, err.retryable
  }
}

Required env vars

VariableWhereNotes
NEXT_PUBLIC_GFLUX_API_KEYClient + serverPublishable key
GFLUX_SERVER_TOKENServer onlyNever expose to the browser
NEXT_PUBLIC_GFLUX_API_HOSTOptionalDefaults to https://api.getfluxly.com