feat: session replay

* wip

* wip

* wip

* wip

* final fixes

* comments

* fix
This commit is contained in:
Carl-Gerhard Lindesvärd
2026-02-26 14:09:53 +01:00
committed by GitHub
parent 38d9b65ec8
commit aa81bbfe77
67 changed files with 3059 additions and 556 deletions

View File

@@ -33,7 +33,7 @@ This is the most common flow and most secure one. Your backend receives webhooks
<FlowStep step={2} actor="Visitor" description="Makes a purchase" icon="visitor" />
<FlowStep step={3} actor="Your website" description="Does a POST request to get the checkout URL" icon="website">
When you create the checkout, you should first call `op.fetchDeviceId()`, which will return your visitor's current `deviceId`. Pass this to your checkout endpoint.
When you create the checkout, you should first call `op.getDeviceId()`, which will return your visitor's current `deviceId`. Pass this to your checkout endpoint.
```javascript
fetch('https://domain.com/api/checkout', {
@@ -42,7 +42,7 @@ fetch('https://domain.com/api/checkout', {
'Content-Type': 'application/json',
},
body: JSON.stringify({
deviceId: await op.fetchDeviceId(), // ✅ since deviceId is here we can link the payment now
deviceId: op.getDeviceId(), // ✅ since deviceId is here we can link the payment now
// ... other checkout data
}),
})
@@ -360,5 +360,5 @@ op.clearRevenue(): void
### Fetch your current users device id
```javascript
op.fetchDeviceId(): Promise<string>
op.getDeviceId(): string
```

View File

@@ -54,7 +54,8 @@ import { OpenPanelComponent } from '@openpanel/astro';
##### Astro options
- `profileId` - If you have a user id, you can pass it here to identify the user
- `cdnUrl` - The url to the OpenPanel SDK (default: `https://openpanel.dev/op1.js`)
- `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.

View File

@@ -62,7 +62,8 @@ export default function RootLayout({ children }) {
##### NextJS options
- `profileId` - If you have a user id, you can pass it here to identify the user
- `cdnUrl` - The url to the OpenPanel SDK (default: `https://openpanel.dev/op1.js`)
- `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.
@@ -286,12 +287,12 @@ import { createRouteHandler } from '@openpanel/nextjs/server';
export const { GET, POST } = createRouteHandler();
```
Remember to change the `apiUrl` and `cdnUrl` in the `OpenPanelComponent` to your own server.
Remember to change the `apiUrl` and `scriptUrl` in the `OpenPanelComponent` to your own server.
```tsx
<OpenPanelComponent
apiUrl="/api/op" // [!code highlight]
cdnUrl="/api/op/op1.js" // [!code highlight]
scriptUrl="/api/op/op1.js" // [!code highlight]
clientId="your-client-id"
trackScreenViews={true}
/>

View File

@@ -136,7 +136,7 @@ For more accurate tracking, handle revenue in your backend webhook. This ensures
```tsx
// Frontend: include deviceId when starting checkout
const deviceId = await op.fetchDeviceId();
const deviceId = op.getDeviceId();
const response = await fetch('/api/checkout', {
method: 'POST',

View File

@@ -225,7 +225,7 @@ Then update your OpenPanelComponent to use the proxy endpoint.
```tsx
<OpenPanelComponent
apiUrl="/api/op"
cdnUrl="/api/op/op1.js"
scriptUrl="/api/op/op1.js"
clientId="your-client-id"
trackScreenViews={true}
/>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +1,9 @@
import { TooltipProvider } from '@/components/ui/tooltip';
import { getRootMetadata } from '@/lib/metadata';
import { cn } from '@/lib/utils';
import { RootProvider } from 'fumadocs-ui/provider/next';
import type { Metadata, Viewport } from 'next';
import { Geist, Geist_Mono } from 'next/font/google';
import { TooltipProvider } from '@/components/ui/tooltip';
import { getRootMetadata } from '@/lib/metadata';
import { cn } from '@/lib/utils';
import './global.css';
import { OpenPanelComponent } from '@openpanel/nextjs';
@@ -31,22 +31,20 @@ export const metadata: Metadata = getRootMetadata();
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html
lang="en"
className={cn(font.className, mono.variable)}
lang="en"
suppressHydrationWarning
>
<body className="flex flex-col min-h-screen bg-background">
<body className="flex min-h-screen flex-col bg-background">
<RootProvider>
<TooltipProvider>{children}</TooltipProvider>
</RootProvider>
{process.env.NEXT_PUBLIC_OP_CLIENT_ID && (
<OpenPanelComponent
apiUrl="/api/op"
cdnUrl="/api/op/op1.js"
clientId={process.env.NEXT_PUBLIC_OP_CLIENT_ID}
trackAttributes
trackScreenViews
trackOutgoingLinks
trackScreenViews
/>
)}
</body>