# OpenPanel SDK — Setup Next.js 16 (self-hosted)

Guide d'intégration du SDK OpenPanel dans une app Next.js 16 (App Router) pour tracker les pages vues, visibles dans l'overview du dashboard (section [Pages](https://openpanel.dev/docs/dashboard/understand-the-overview#pages)).

---

## 1. Prérequis

- Une instance OpenPanel self-hosted accessible (ex. `https://op.votredomaine.com`)
- Un projet créé dans le dashboard → récupérer le **Client ID** et le **Client Secret** (Settings → Projects)
- Next.js 16 avec App Router

## 2. Installation

```bash
pnpm install @openpanel/nextjs
# ou
npm install @openpanel/nextjs
```

## 3. Variables d'environnement

`.env.local` :

```bash
NEXT_PUBLIC_OP_API_URL=https://op.votredomaine.com/api
NEXT_PUBLIC_OP_CLIENT_ID=your-client-id
OP_CLIENT_SECRET=your-client-secret   # serveur uniquement, jamais NEXT_PUBLIC_
```

> ⚠️ En self-hosted, `apiUrl` est **obligatoire**, sinon le SDK envoie les events vers le cloud openpanel.dev.

## 4. Initialisation — tracking des pages vues

Ajouter `OpenPanelComponent` dans le root layout. C'est `trackScreenViews={true}` qui génère les events `screen_view` comptés comme **Pageviews** dans l'overview.

`app/layout.tsx` :

```tsx
import { OpenPanelComponent } from '@openpanel/nextjs';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="fr">
      <body>
        <OpenPanelComponent
          apiUrl={process.env.NEXT_PUBLIC_OP_API_URL}
          clientId={process.env.NEXT_PUBLIC_OP_CLIENT_ID!}
          trackScreenViews={true}      // ← pages vues automatiques
          trackOutgoingLinks={true}    // optionnel : liens sortants
          trackAttributes={true}       // optionnel : data-track sur HTML
        />
        {children}
      </body>
    </html>
  );
}
```

Le tracking se fait côté client : chaque navigation (y compris client-side entre pages) émet un `screen_view`.

### Options utiles

| Option | Défaut | Description |
| --- | --- | --- |
| `apiUrl` | cloud OpenPanel | URL de l'API de votre instance self-hosted |
| `clientId` | — | Client ID du projet |
| `trackScreenViews` | `false` | Track automatique des pages vues |
| `trackOutgoingLinks` | `false` | Track des liens sortants |
| `trackAttributes` | `false` | Events via attributs `data-track` |
| `profileId` | — | Identifie l'utilisateur si connu |
| `globalProperties` | — | Propriétés envoyées avec chaque event |
| `filter` | — | Fonction (stringifiée) pour filtrer les events |
| `disabled` | `false` | Désactive l'envoi (utile en dev) |

Astuce dev : `disabled={process.env.NODE_ENV !== 'production'}` pour ne pas polluer les stats.

## 5. Proxy anti-adblock (recommandé)

Beaucoup d'adblockers bloquent les domaines tiers. En proxifiant via votre propre domaine, vous fiabilisez le comptage des pages vues.

`app/api/op/[...op]/route.ts` :

```ts
import { createRouteHandler } from '@openpanel/nextjs/server';

export const { GET, POST } = createRouteHandler({
  apiUrl: process.env.NEXT_PUBLIC_OP_API_URL,
});
```

Puis pointer le composant vers le proxy :

```tsx
<OpenPanelComponent
  apiUrl="/api/op"
  scriptUrl="/api/op/op1.js"
  clientId={process.env.NEXT_PUBLIC_OP_CLIENT_ID!}
  trackScreenViews={true}
/>
```

## 6. Events custom (client)

```tsx
'use client';
import { useOpenPanel } from '@openpanel/nextjs';

export function CtaButton() {
  const op = useOpenPanel();
  return (
    <button onClick={() => op.track('cta_click', { plan: 'pro' })}>
      Essayer
    </button>
  );
}
```

Ou via attribut HTML (nécessite `trackAttributes={true}`) :

```html
<button data-track="signup_click" data-plan="pro">S'inscrire</button>
```

## 7. Tracking côté serveur

Pour les events serveur (API routes, server actions), créer une instance avec le **client secret**.

`lib/op-server.ts` :

```ts
import { OpenPanel } from '@openpanel/nextjs';

export const opServer = new OpenPanel({
  apiUrl: process.env.NEXT_PUBLIC_OP_API_URL,
  clientId: process.env.NEXT_PUBLIC_OP_CLIENT_ID!,
  clientSecret: process.env.OP_CLIENT_SECRET!, // jamais exposé côté client
});
```

```ts
// API route / server action
import { opServer } from '@/lib/op-server';

await opServer.track('order_completed', { profileId: '123', amount: 49 });
```

Sur Vercel/serverless, utiliser `waitUntil` pour garantir l'envoi :

```ts
import { waitUntil } from '@vercel/functions';

export function GET() {
  waitUntil(opServer.track('my_server_event', { foo: 'bar' }));
  return new Response('ok');
}
```

## 8. Identifier les utilisateurs

Sans `identify`, OpenPanel génère un ID anonyme qui change toutes les 24h (un visiteur revenant 10 jours = 10 visiteurs uniques). Avec `identify`, la déduplication est correcte sur toute la période.

Côté client :

```tsx
useOpenPanel().identify({
  profileId: user.id, // requis
  firstName: user.firstName,
  email: user.email,
});
```

Côté serveur (layout avec données user) :

```tsx
import { IdentifyComponent } from '@openpanel/nextjs';

export default async function Layout({ children }) {
  const user = await getCurrentUser();
  return (
    <>
      <IdentifyComponent profileId={user.id} email={user.email} />
      {children}
    </>
  );
}
```

## 9. Vérification

1. Lancer l'app, naviguer entre quelques pages.
2. Dashboard OpenPanel → overview : le badge vert (live) doit afficher votre visite.
3. La carte **Pageviews** compte chaque `screen_view` ; le widget **Pages** liste Top / Entry / Exit pages.
4. Onglet Network du navigateur : requêtes POST vers `/api/op/track` (proxy) ou votre `apiUrl` avec `type: "track"`, `name: "screen_view"`.

### Dépannage

| Symptôme | Cause probable |
| --- | --- |
| Aucun event reçu | `apiUrl` absent ou incorrect (events partis vers le cloud) |
| Events bloqués pour certains visiteurs | Adblockers → mettre en place le proxy (section 5) |
| Pageviews à 0 mais events custom OK | `trackScreenViews` non activé |
| Visiteurs uniques gonflés | Pas d'`identify` → ID anonyme rotatif 24h |

---

Références : [SDK Next.js](https://openpanel.dev/docs/sdks/nextjs) · [Comprendre l'overview](https://openpanel.dev/docs/dashboard/understand-the-overview) · [Proxy adblockers](https://openpanel.dev/docs/adblockers) · [Identify](https://openpanel.dev/docs/get-started/identify-users)
