
Research
/Security News
Trivy Under Attack Again: Widespread GitHub Actions Tag Compromise Exposes CI/CD Secrets
Attackers compromised Trivy GitHub Actions by force-updating tags to deliver malware, exposing CI/CD secrets across affected pipelines.
@openpanel/nextjs
Advanced tools
> đź“– **Full documentation:** [https://openpanel.dev/docs/sdks/nextjs](https://openpanel.dev/docs/sdks/nextjs)
đź“– Full documentation: https://openpanel.dev/docs/sdks/nextjs
Looking for a step-by-step tutorial? Check out the Next.js analytics guide.
Keep in mind that all tracking here happens on the client!
Read more about server side tracking in the Server Side Tracking section.
pnpm install @openpanel/nextjs
Add OpenPanelComponent to your root layout component.
import { OpenPanelComponent } from '@openpanel/nextjs';
export default function RootLayout({ children }) {
return (
<>
<OpenPanelComponent
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}
</>
)
}
apiUrl - The url of the openpanel API or your self-hosted instanceclientId - The client id of your applicationclientSecret - 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 sentdisabled - If true, the library will not send any eventstrackScreenViews - 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-openpanel-replay-mask])blockSelector - CSS selector for elements to replace with a placeholder (default: [data-openpanel-replay-block])blockClass - Class name that blocks elements from being recordedignoreSelector - CSS selector for elements excluded from interaction trackingflushIntervalMs - 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)profileId - If you have a user id, you can pass it here to identify the usercdnUrl (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 moreglobalProperties - This is an object of properties that will be sent with every event.filterThis options needs to be a stringified function and cannot access any variables outside of the function.
<OpenPanelComponent
clientId="your-client-id"
filter={`
function filter(event) {
return event.name !== 'my_event';
}
`}
/>
To take advantage of typescript you can do the following. Note toString
import { type TrackHandlerPayload } from '@openpanel/nextjs';
const opFilter = ((event: TrackHandlerPayload) => {
return event.type === 'track' && event.payload.name === 'my_event';
}).toString();
<OpenPanelComponent
clientId="your-client-id"
filter={opFilter}
/>
For client components you can just use the useOpenPanel hook.
import { useOpenPanel } from '@openpanel/nextjs';
function YourComponent() {
const op = useOpenPanel();
return <button type="button" onClick={() => op.track('my_event', { foo: 'bar' })}>Trigger event</button>
}
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.
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 for usage instructions.
You can track events with two different methods: by calling the op.track( directly or by adding data-track` attributes to your HTML elements.
useOpenPanel().track('my_event', { foo: 'bar' });
To identify a user, call the `op.identify( method with a unique identifier.
useOpenPanel().identify({
profileId: '123', // Required
firstName: 'Joe',
lastName: 'Doe',
email: 'joe@doe.com',
properties: {
tier: 'premium',
},
});
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.
import { IdentifyComponent } from '@openpanel/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}
</>
)
}
To set properties that will be sent with every event:
useOpenPanel().setGlobalProperties({
app_version: '1.0.2',
environment: 'production',
});
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.useOpenPanel().increment({
profileId: '1',
property: 'visits',
value: 1 // optional
});
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.useOpenPanel().decrement({
profileId: '1',
property: 'visits',
value: 1 // optional
});
Groups let you track analytics at the account or company level. See the Groups guide for the full walkthrough.
Create or update a group:
useOpenPanel().upsertGroup({
id: 'org_acme',
type: 'company',
name: 'Acme Inc',
properties: { plan: 'enterprise' },
});
Assign the current user to a group (call after identify):
useOpenPanel().setGroup('org_acme');
Once set, all subsequent track() calls will automatically include the group IDs.
To clear the current user's data (including groups):
useOpenPanel().clear()
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.
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: 'âś…' });
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.
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!`);
}
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).
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.
<OpenPanelComponent
apiUrl="/api/op" // [!code highlight]
scriptUrl="/api/op/op1.js" // [!code highlight]
clientId="your-client-id"
trackScreenViews={true}
/>
FAQs
> đź“– **Full documentation:** [https://openpanel.dev/docs/sdks/nextjs](https://openpanel.dev/docs/sdks/nextjs)
We found that @openpanel/nextjs demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Attackers compromised Trivy GitHub Actions by force-updating tags to deliver malware, exposing CI/CD secrets across affected pipelines.

Security News
ENISA’s new package manager advisory outlines the dependency security practices companies will need to demonstrate as the EU’s Cyber Resilience Act begins enforcing software supply chain requirements.

Research
/Security News
We identified over 20 additional malicious extensions, along with over 20 related sleeper extensions, some of which have already been weaponized.