From 60777cb26b6ce25e72927d231941d68f2d65ca48 Mon Sep 17 00:00:00 2001 From: vklimontovich Date: Fri, 5 Jun 2026 13:47:20 -0400 Subject: [PATCH] feat: per-event user override in analytics().sendEvent() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sendEvent now accepts an optional `user` (UserContext) that identifies the event explicitly, overriding callbacks.getUser for that event. This covers server events whose subject isn't the request's session user — e.g. an email recipient resolved from a tracking link — so they land as real identity (userId/traits) instead of plain props. --- packages/core/src/server.tsx | 7 +++++-- packages/core/src/types.ts | 8 +++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/core/src/server.tsx b/packages/core/src/server.tsx index e8299ed..1d21a54 100644 --- a/packages/core/src/server.tsx +++ b/packages/core/src/server.tsx @@ -25,6 +25,7 @@ import type { NextlyticsResult, RequestContext, ServerEventContext, + UserContext, } from "./types"; import { logConfigWarnings, validateConfig, withDefaults } from "./config-helpers"; import { createNextlyticsMiddleware } from "./middleware"; @@ -314,7 +315,7 @@ export function Nextlytics(userConfig: NextlyticsConfig): NextlyticsResult { return { sendEvent: async ( eventName: string, - opts?: { props?: Record } + opts?: { props?: Record; user?: UserContext } ): Promise<{ ok: boolean }> => { // In the App Router no-arg path a missing pageRenderId means middleware // never ran — keep that as a hard error. With an explicit `req` the @@ -332,7 +333,9 @@ export function Nextlytics(userConfig: NextlyticsConfig): NextlyticsResult { collectedAt: new Date().toISOString(), anonymousUserId, serverContext, - userContext, + // An explicit per-event user (e.g. an email recipient resolved from a + // link) overrides the request-derived one from callbacks.getUser. + userContext: opts?.user ?? userContext, properties: { ...propsFromCallback, ...opts?.props }, }; // Await full delivery, not just dispatch kickoff. Unlike the middleware diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 25e5d14..088e6b6 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -255,7 +255,13 @@ export type NextlyticsServerSide = { /** Send custom event from a server component, server action, or API route */ sendEvent: ( eventName: string, - opts?: { props?: Record } + opts?: { + props?: Record; + /** Identify the event's user explicitly. Overrides callbacks.getUser for + * this event — e.g. an email recipient resolved from a link, where the + * request has no session to derive identity from. */ + user?: UserContext; + } ) => Promise<{ ok: boolean }>; };