Helion

Next.js

Looking for a step-by-step tutorial? Check out the Next.js analytics guide.

Good to know

All client-side tracking runs in the browser. For server-side event tracking, see the Server Side Tracking section below.

Installation

Install dependencies

pnpm install @helionlabs/nextjs

Initialize

Add HelionComponent to your root layout component.

import { HelionComponent } from '@helionlabs/nextjs';

export default function RootLayout({ children }) {
  return (
    <>
      <HelionComponent
        clientId="your-client-id"
        trackScreenViews={true}
        // trackAttributes={true}
        // trackOutgoingLinks={true}
        // If you have a user id, you can pass it here to identify the user
        // profileId={'123'}
      />
      {children}
    </>
  )
}

Options

Common options
  • apiUrl - The url of the helion API or your self-hosted instance
  • clientId - The client id of your application
  • clientSecret - The client secret of your application (only required for server-side events)
  • filter - A function that will be called before sending an event. If it returns false, the event will not be sent
  • disabled - If true, the library will not send any events
Web options
  • trackScreenViews - If true, the library will automatically track screen views (default: false)
  • trackOutgoingLinks - If true, the library will automatically track outgoing links (default: false)
  • trackAttributes - If true, you can trigger events by using html attributes (<button type="button" data-track="your_event" />) (default: false)
  • sessionReplay - Session replay configuration object (default: disabled). See session replay docs for full options.
    • enabled - Enable session replay recording (default: false)
    • maskAllInputs - Mask all input field values (default: true)
    • maskTextSelector - CSS selector for text elements to mask (default: [data-helion-replay-mask])
    • blockSelector - CSS selector for elements to replace with a placeholder (default: [data-helion-replay-block])
    • blockClass - Class name that blocks elements from being recorded
    • ignoreSelector - CSS selector for elements excluded from interaction tracking
    • flushIntervalMs - How often (ms) recorded events are sent to the server (default: 10000)
    • maxEventsPerChunk - Maximum events per payload chunk (default: 200)
    • maxPayloadBytes - Maximum payload size in bytes (default: 1048576)
    • scriptUrl - Custom URL for the replay script (script-tag builds only)
Next.js options
  • profileId — If you have a user ID, pass it here to identify the user automatically
  • cdnUrl (deprecated) — The URL to the Helion SDK (default: https://helionlabs.dev/hl1.js)
  • scriptUrl — The URL to the Helion SDK (default: https://helionlabs.dev/hl1.js)
  • filter — A function called before each event. Return false to suppress the event. Read more
  • globalProperties — Properties sent with every event
filter

The filter must be a stringified function and cannot reference variables outside of its own scope.

<HelionComponent
  clientId="your-client-id"
  filter={`
    function filter(event) {
      return event.name !== 'my_event';
    }
  `}
/>

To take advantage of TypeScript, use .toString():

import { type TrackHandlerPayload } from '@helionlabs/nextjs';

const helionFilter = ((event: TrackHandlerPayload) => {
  return event.type === 'track' && event.payload.name === 'my_event';
}).toString();

<HelionComponent
  clientId="your-client-id"
  filter={helionFilter}
/>

Usage

Client components

Use the useHelion hook in client components:

import { useHelion } from '@helionlabs/nextjs';

function YourComponent() {
  const hl = useHelion();

  return <button type="button" onClick={() => hl.track('my_event', { foo: 'bar' })}>Trigger event</button>
}

Server components

Hooks are not available in server components. Create a shared Helion instance and import it where needed:

The client secret is only safe server-side — never expose it in client code.
utils/helion.ts
import { Helion } from '@helionlabs/nextjs';

export const hl = new Helion({
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret',
});

Refer to the JavaScript SDK for usage instructions.

Tracking Events

Call hl.track() directly, or use data-track attributes on HTML elements for automatic click tracking.

index.ts
useHelion().track('my_event', { foo: 'bar' });

Identifying Users

Call hl.identify() with a unique identifier to associate the session with a known user profile.

index.js
useHelion().identify({
  profileId: '123', // Required
  firstName: 'Joe',
  lastName: 'Doe',
  email: 'joe@doe.com',
  properties: {
    tier: 'premium',
  },
});

For server components

Use the IdentifyComponent exported from @helionlabs/nextjs when user data is available server-side:

app/nested/layout.tsx
import { IdentifyComponent } from '@helionlabs/nextjs';

export default function Layout({ children }) {
  const user = await getCurrentUser()

  return (
    <>
      <IdentifyComponent
        profileId={user.id}
        firstName={user.firstName}
        lastName={user.lastName}
        email={user.email}
        properties={{
          tier: 'premium',
        }}
      />
      {children}
    </>
  )
}

Setting Global Properties

Properties set via setGlobalProperties are attached to every subsequent event.

index.js
useHelion().setGlobalProperties({
  app_version: '1.0.2',
  environment: 'production',
});

Incrementing Properties

Increment a numeric property on a user profile. Omit value to increment by 1.

index.js
useHelion().increment({
  profileId: '1',
  property: 'visits',
  value: 1 // optional
});

Decrementing Properties

Decrement a numeric property on a user profile. Omit value to decrement by 1.

index.js
useHelion().decrement({
  profileId: '1',
  property: 'visits',
  value: 1 // optional
});

Working with Groups

Groups let you track analytics at the account or company level. See the Groups guide for the full walkthrough.

Create or update a group:

app/login/page.tsx
useHelion().upsertGroup({
  id: 'org_acme',
  type: 'company',
  name: 'Acme Inc',
  properties: { plan: 'enterprise' },
});

Assign the current user to a group (call after identify):

app/login/page.tsx
useHelion().setGroup('org_acme');

Once set, all subsequent track() calls will automatically include the group IDs.

Clearing User Data

clear() resets the profile, device identity, session, and all group associations. Call it on logout.

index.js
useHelion().clear()

Server side

To track server-side events, use the HelionSdk class exported from @helionlabs/nextjs.

Server-side tracking requires a client secret to authenticate requests. The secret prevents unauthorized event ingestion because CORS headers cannot protect server-to-server calls.

You can reuse the same clientId but must supply the associated clientSecret.

import { HelionSdk } from '@helionlabs/nextjs';

const hlServer = new HelionSdk({
  clientId: '{YOUR_CLIENT_ID}',
  clientSecret: '{YOUR_CLIENT_SECRET}',
});

hlServer.event('my_server_event', { ok: true });

// Pass `profileId` to attribute the event to a specific user
hlServer.event('my_server_event', { profileId: '123', ok: true });

Serverless & Vercel

In serverless environments like Vercel, use waitUntil to ensure the event is logged before the function terminates:

import { waitUntil } from '@vercel/functions';
import { hlServer } from 'path/to/your-sdk-instance';

export function GET() {
  waitUntil(hlServer.event('my_server_event', { foo: 'bar' }));
  return new Response(`Your event has been logged!`);
}

Proxy events

Use createRouteHandler to proxy tracking requests through your own server, bypassing adblockers that block third-party domains. The handler routes requests based on path, supporting API endpoints (/track, /track/device-id) and the tracking script (/hl1.js).

/app/api/[...hl]/route.ts
import { createRouteHandler } from '@helionlabs/nextjs/server';

export const { GET, POST } = createRouteHandler();

Update HelionComponent to point at your proxy:

<HelionComponent
  apiUrl="/api/hl"
  scriptUrl="/api/hl/hl1.js"
  clientId="your-client-id"
  trackScreenViews={true}
/>

On this page