--- title: Next.js --- import Link from 'next/link'; import { Step, Steps } from 'fumadocs-ui/components/steps'; import { DeviceIdWarning } from '@/components/device-id-warning'; import { PersonalDataWarning } from '@/components/personal-data-warning'; import { Callout } from 'fumadocs-ui/components/callout'; import CommonSdkConfig from '@/components/common-sdk-config.mdx'; import WebSdkConfig from '@/components/web-sdk-config.mdx'; Looking for a step-by-step tutorial? Check out the [Next.js analytics guide](/guides/nextjs-analytics). ## Good to know Keep in mind that all tracking here happens on the client! Read more about server side tracking in the [Server Side Tracking](#track-server-events) section. ## Installation ### Install dependencies ```bash pnpm install @openpanel/nextjs ``` ### Initialize Add `OpenPanelComponent` to your root layout component. ```tsx import { OpenPanelComponent } from '@openpanel/nextjs'; export default function RootLayout({ children }) { return ( <> {children} ) } ``` #### Options ##### NextJS options - `profileId` - If you have a user id, you can pass it here to identify the user - `cdnUrl` (deprecated) - The url to the OpenPanel SDK (default: `https://openpanel.dev/op1.js`) - `scriptUrl` - The url to the OpenPanel SDK (default: `https://openpanel.dev/op1.js`) - `filter` - This is a function that will be called before tracking an event. If it returns false the event will not be tracked. [Read more](#filter) - `globalProperties` - This is an object of properties that will be sent with every event. ##### `filter` This options needs to be a stringified function and cannot access any variables outside of the function. ```tsx ``` To take advantage of typescript you can do the following. _Note `toString`_ ```tsx /.toString();/ import { type TrackHandlerPayload } from '@openpanel/nextjs'; const opFilter = ((event: TrackHandlerPayload) => { return event.type === 'track' && event.payload.name === 'my_event'; }).toString(); ``` ## Usage ### Client components For client components you can just use the `useOpenPanel` hook. ```tsx import { useOpenPanel } from '@openpanel/nextjs'; function YourComponent() { const op = useOpenPanel(); return } ``` ### Server components Since you can't use hooks in server components, you need to create an instance of the SDK. This is exported from `@openpanel/nextjs`. Remember, your client secret is exposed here so do not use this on client side. ```tsx title="utils/op.ts" import { OpenPanel } from '@openpanel/nextjs'; export const op = new OpenPanel({ clientId: 'your-client-id', clientSecret: 'your-client-secret', }); // Now you can use `op` to track events op.track('my_event', { foo: 'bar' }); ``` Refer to the [Javascript SDK](/docs/sdks/javascript#usage) for usage instructions. ### Tracking Events You can track events with two different methods: by calling the `op.track( directly or by adding `data-track` attributes to your HTML elements. ```ts title="index.ts" useOpenPanel().track('my_event', { foo: 'bar' }); ``` ### Identifying Users To identify a user, call the `op.identify( method with a unique identifier. ```js title="index.js" useOpenPanel().identify({ profileId: '123', // Required firstName: 'Joe', lastName: 'Doe', email: 'joe@doe.com', properties: { tier: 'premium', }, }); ``` #### For server components For server components you can use the `IdentifyComponent` component which is exported from `@openpanel/nextjs`. > This component is great if you have the user data available on the server side. ```tsx title="app/nested/layout.tsx" import { IdentifyComponent } from '@openpanel/nextjs'; export default function Layout({ children }) { const user = await getCurrentUser() return ( <> {children} ) } ``` ### Setting Global Properties To set properties that will be sent with every event: ```js title="index.js" useOpenPanel().setGlobalProperties({ app_version: '1.0.2', environment: 'production', }); ``` ### Incrementing Properties To increment a numeric property on a user profile. - `value` is the amount to increment the property by. If not provided, the property will be incremented by 1. ```js title="index.js" useOpenPanel().increment({ profileId: '1', property: 'visits', value: 1 // optional }); ``` ### Decrementing Properties To decrement a numeric property on a user profile. - `value` is the amount to decrement the property by. If not provided, the property will be decremented by 1. ```js title="index.js" useOpenPanel().decrement({ profileId: '1', property: 'visits', value: 1 // optional }); ``` ### Clearing User Data To clear the current user's data: ```js title="index.js" useOpenPanel().clear() ``` ## Server side If you want to track server-side events, you should create an instance of our Javascript SDK. It's exported from `@openpanel/nextjs` When using server events it's important that you use a secret to authenticate the request. This is to prevent unauthorized requests since we cannot use cors headers. You can use the same clientId but you should pass the associated client secret to the SDK. ```typescript import { OpenpanelSdk } from '@openpanel/nextjs'; const opServer = new OpenpanelSdk({ clientId: '{YOUR_CLIENT_ID}', clientSecret: '{YOUR_CLIENT_SECRET}', }); opServer.event('my_server_event', { ok: '✅' }); // Pass `profileId` to track events for a specific user opServer.event('my_server_event', { profileId: '123', ok: '✅' }); ``` ### Serverless & Vercel If you log events in a serverless environment like Vercel, you can use `waitUntil` to ensure the event is logged before the function is done. Otherwise your function might close before the event is logged. Read more about it [here](https://vercel.com/docs/functions/functions-api-reference#waituntil). ```typescript import { waitUntil } from '@vercel/functions'; import { opServer } from 'path/to/your-sdk-instance'; export function GET() { // Returns a response immediately while keeping the function alive waitUntil(opServer.event('my_server_event', { foo: 'bar' })); return new Response(`You're event has been logged!`); } ``` ### Proxy events With `createRouteHandler` you can proxy your events through your server, this will ensure all events are tracked since there is a lot of adblockers that block requests to third party domains. The handler automatically routes requests based on the path, supporting both API endpoints (like `/track` and `/track/device-id`) and the tracking script (`/op1.js`). ```typescript title="/app/api/[...op]/route.ts" import { createRouteHandler } from '@openpanel/nextjs/server'; export const { GET, POST } = createRouteHandler(); ``` Remember to change the `apiUrl` and `scriptUrl` in the `OpenPanelComponent` to your own server. ```tsx ```