sdk: update nextjs and web sdk

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-05-31 20:47:36 +02:00
parent 51bb0c969d
commit f75fe498ba
3 changed files with 101 additions and 55 deletions

View File

@@ -126,6 +126,21 @@ const profileId = '123';
setProfileId(profileId);
```
Or if you want to identify the user with a server component.
```typescript
import { SetProfileId } from '@openpanel/nextjs';
export function Layout({ children }) {
return (
<>
<SetProfileId value={'123'} />
{children}
</>
)
}
```
#### Additional data
This method does the same as `setProfileId` but also allows you to update the profile with additional data.
@@ -146,6 +161,21 @@ setProfile({
});
```
Or if you want to identify the user with a server component.
```typescript
import { SetProfile } from '@openpanel/nextjs';
export function Layout({ children }) {
return (
<>
<SetProfile profileId={'12'} firstName={'Joe'} lastName={'Doe'} email={'joe.doe@openpanel.dev'} avatar={'https://image.com'} properties={{...}} />
{children}
</>
)
}
```
#### Increment property
Increment a property on the profile.
@@ -184,7 +214,7 @@ import { clear } from '@openpanel/nextjs';
clear();
```
### Track server events
## Track server events
If you want to track server-side events, you should create an instance of our Javascript SDK. It's exported from `@openpanel/nextjs`
@@ -209,7 +239,24 @@ opServer.event('my_server_event', { ok: '✅' });
opServer.event('my_server_event', { profileId: '123', ok: '✅' });
```
### Proxy events
### 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 `createNextRouteHandler` 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.

View File

@@ -50,11 +50,11 @@ export function OpenpanelProvider({
cdnUrl,
...options
}: OpenpanelProviderProps) {
const events: { name: OpenpanelMethods; value: unknown }[] = [
const methods: { name: OpenpanelMethods; value: unknown }[] = [
{ name: 'ctor', value: options },
];
if (profileId) {
events.push({ name: 'setProfileId', value: profileId });
methods.push({ name: 'setProfileId', value: profileId });
}
return (
<>
@@ -62,9 +62,9 @@ export function OpenpanelProvider({
<Script
dangerouslySetInnerHTML={{
__html: `window.op = window.op || function(...args) {(window.op.q = window.op.q || []).push(args)};
${events
.map((event) => {
return `window.op('${event.name}', ${JSON.stringify(event.value)});`;
${methods
.map((method) => {
return `window.op('${method.name}', ${JSON.stringify(method.value)});`;
})
.join('\n')}`,
}}
@@ -89,6 +89,20 @@ export function SetProfileId({ value }: SetProfileIdProps) {
);
}
type SetProfileProps = UpdateProfilePayload;
export function SetProfile(props: SetProfileProps) {
return (
<>
<Script
dangerouslySetInnerHTML={{
__html: `window.op('setProfile', ${JSON.stringify(props)});`,
}}
/>
</>
);
}
export function trackEvent(
name: string,
data?: PostEventPayload['properties']

View File

@@ -5,7 +5,6 @@ export interface OpenpanelEventOptions {
export interface PostEventPayload {
name: string;
timestamp: string;
deviceId?: string;
profileId?: string;
properties?: Record<string, unknown> & OpenpanelEventOptions;
}
@@ -36,13 +35,9 @@ export interface OpenpanelSdkOptions {
clientId: string;
clientSecret?: string;
verbose?: boolean;
setDeviceId?: (deviceId: string) => void;
getDeviceId?: () => string | null | undefined;
removeDeviceId?: () => void;
}
export interface OpenpanelState {
deviceId?: string;
profileId?: string;
properties: Record<string, unknown>;
}
@@ -149,9 +144,9 @@ export class OpenpanelSdk<
this.state.profileId = profileId;
}
public setProfile(payload: UpdateProfilePayload) {
public async setProfile(payload: UpdateProfilePayload) {
this.setProfileId(payload.profileId);
this.api.fetch<UpdateProfilePayload, string>('/profile', {
return this.api.fetch<UpdateProfilePayload, string>('/profile', {
...payload,
properties: {
...this.state.properties,
@@ -160,7 +155,7 @@ export class OpenpanelSdk<
});
}
public increment(
public async increment(
property: string,
value: number,
options?: OpenpanelEventOptions
@@ -169,14 +164,17 @@ export class OpenpanelSdk<
if (!profileId) {
return console.log('No profile id');
}
this.api.fetch<IncrementProfilePayload, string>('/profile/increment', {
profileId,
property,
value,
});
return this.api.fetch<IncrementProfilePayload, string>(
'/profile/increment',
{
profileId,
property,
value,
}
);
}
public decrement(
public async decrement(
property: string,
value: number,
options?: OpenpanelEventOptions
@@ -185,32 +183,31 @@ export class OpenpanelSdk<
if (!profileId) {
return console.log('No profile id');
}
this.api.fetch<DecrementProfilePayload, string>('/profile/decrement', {
profileId,
property,
value,
});
return this.api.fetch<DecrementProfilePayload, string>(
'/profile/decrement',
{
profileId,
property,
value,
}
);
}
public event(name: string, properties?: PostEventPayload['properties']) {
public async event(
name: string,
properties?: PostEventPayload['properties']
) {
const profileId = properties?.profileId ?? this.state.profileId;
delete properties?.profileId;
this.api
.fetch<PostEventPayload, string>('/event', {
name,
properties: {
...this.state.properties,
...(properties ?? {}),
},
timestamp: this.timestamp(),
deviceId: this.getDeviceId(),
profileId,
})
.then((deviceId) => {
if (this.options.setDeviceId && deviceId) {
this.options.setDeviceId(deviceId);
}
});
return this.api.fetch<PostEventPayload, string>('/event', {
name,
properties: {
...this.state.properties,
...(properties ?? {}),
},
timestamp: this.timestamp(),
profileId,
});
}
public setGlobalProperties(properties: Record<string, unknown>) {
@@ -221,11 +218,7 @@ export class OpenpanelSdk<
}
public clear() {
this.state.deviceId = undefined;
this.state.profileId = undefined;
if (this.options.removeDeviceId) {
this.options.removeDeviceId();
}
}
// Private
@@ -233,12 +226,4 @@ export class OpenpanelSdk<
private timestamp() {
return new Date().toISOString();
}
private getDeviceId() {
if (this.state.deviceId) {
return this.state.deviceId;
} else if (this.options.getDeviceId) {
this.state.deviceId = this.options.getDeviceId() || undefined;
}
}
}