npm package: @signal-js/nextjs
Description: Signal SDK integration for Next.js applications
Latest version: 1.0.6

# @signal-js/nextjs

Signal SDK integration for Next.js applications. Uses **@signal-js/browser** (client) and **@signal-js/node** (server); both are included as dependencies.

## Installation

```bash
npm install @signal-js/nextjs
# or
pnpm add @signal-js/nextjs
# or
yarn add @signal-js/nextjs
```

## Quick Start

### App Router (Next.js 13+)

```tsx
// app/providers.tsx
'use client';

import { SignalNextProvider } from '@signal-js/nextjs/client';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <SignalNextProvider
      options={{
        endpoint: process.env.NEXT_PUBLIC_SIGNAL_ENDPOINT!,
        apiKey: process.env.NEXT_PUBLIC_SIGNAL_API_KEY!,
        projectId: process.env.NEXT_PUBLIC_SIGNAL_PROJECT_ID!,
      }}
      trackPageViews
    >
      {children}
    </SignalNextProvider>
  );
}

// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
```

### Using in Components

```tsx
'use client';

import { useSignal } from '@signal-js/nextjs';

export function MyComponent() {
  const { capture, identify, group } = useSignal();
  
  const handleLogin = (user) => {
    identify(user.id, { email: user.email });
    group('company', user.companyId);
  };
  
  return (
    <button onClick={() => capture('button_clicked')}>
      Click Me
    </button>
  );
}
```

### Server-Side Tracking

```typescript
// lib/signal-server.ts
import { createSignalServer } from '@signal-js/nextjs/server';

export const signal = createSignalServer({
  endpoint: process.env.SIGNAL_ENDPOINT!,
  apiKey: process.env.SIGNAL_API_KEY!,
});

// In API routes or Server Actions
import { signal } from '@/lib/signal-server';

signal.capture({
  distinctId: userId,
  event: 'purchase_completed',
  properties: { amount: 99.99 },
});
```

## Client Components

### `SignalNextProvider`

Enhanced provider for Next.js App Router with automatic page view tracking.

```tsx
<SignalNextProvider
  options={{
    endpoint: 'https://your-api.com',
    apiKey: 'your-api-key',
  }}
  trackPageViews      // Auto-track page views (default: true)
  trackSearchParams   // Include search params in page views
  autoStart           // Auto-start recording (default: true)
>
  {children}
</SignalNextProvider>
```

### `SignalPageViewTracker`

Component that tracks page views on route changes.

```tsx
import { SignalPageViewTracker } from '@signal-js/nextjs/client';

// Add to layout
<SignalPageViewTracker trackSearchParams />
```

### Hooks

All hooks from `@signal-js/react` are re-exported:

```tsx
import {
  useSignal,
  useSignalCapture,
  useSignalIdentify,
  useSignalGroup,
  useSignalSession,
  usePageView,
  useTrackEvent,
} from '@signal-js/nextjs';
```

## Server Components

### `createSignalServer(options)`

Create a server-side Signal client.

```typescript
import { createSignalServer } from '@signal-js/nextjs/server';

const signal = createSignalServer({
  endpoint: process.env.SIGNAL_ENDPOINT!,
  apiKey: process.env.SIGNAL_API_KEY!,
  projectId: 'my-project',
});
```

### `withSignalConfig(signalConfig)`

Wrap your Next.js config with Signal configuration.

```javascript
// next.config.js
const { withSignalConfig } = require('@signal-js/nextjs/server');

module.exports = withSignalConfig({
  endpoint: process.env.SIGNAL_ENDPOINT,
  apiKey: process.env.SIGNAL_API_KEY,
})({
  // your Next.js config
});
```

### `getSignalServerSideProps(getServerSidePropsFunc, options)`

Helper for getServerSideProps to inject Signal data.

```typescript
// pages/dashboard.tsx
import { getSignalServerSideProps } from '@signal-js/nextjs/server';

export const getServerSideProps = getSignalServerSideProps(
  async (context) => {
    return { props: { data: 'your data' } };
  },
  {
    getDistinctId: (context) => context.req.cookies.userId,
  }
);
```

### `trackServerEvent(options)`

Track an event from server-side code.

```typescript
import { trackServerEvent } from '@signal-js/nextjs/server';

await trackServerEvent({
  distinctId: userId,
  event: 'server_action_completed',
  properties: { action: 'update_profile' },
});
```

## Environment Variables

```env
# Public (client-side)
NEXT_PUBLIC_SIGNAL_ENDPOINT=https://your-api.com
NEXT_PUBLIC_SIGNAL_API_KEY=your-public-api-key
NEXT_PUBLIC_SIGNAL_PROJECT_ID=your-project-id

# Private (server-side)
SIGNAL_ENDPOINT=https://your-api.com
SIGNAL_API_KEY=your-server-api-key
SIGNAL_PROJECT_ID=your-project-id
```

## Full Example

```tsx
// app/providers.tsx
'use client';

import { SignalNextProvider } from '@signal-js/nextjs/client';

export function Providers({ children }) {
  return (
    <SignalNextProvider
      options={{
        endpoint: process.env.NEXT_PUBLIC_SIGNAL_ENDPOINT!,
        apiKey: process.env.NEXT_PUBLIC_SIGNAL_API_KEY!,
        projectId: process.env.NEXT_PUBLIC_SIGNAL_PROJECT_ID!,
        enableSessionReplay: true,
        enableNetworkCapture: true,
      }}
      trackPageViews
    >
      {children}
    </SignalNextProvider>
  );
}

// app/dashboard/page.tsx
'use client';

import { useSignal, usePageView } from '@signal-js/nextjs';

export default function Dashboard() {
  const { capture, identify, group, sessionId } = useSignal();
  
  // Track page view with custom properties
  usePageView('dashboard', { section: 'analytics' });
  
  return (
    <div>
      <h1>Dashboard</h1>
      <p>Session: {sessionId}</p>
      <button onClick={() => capture('export_clicked')}>
        Export Data
      </button>
    </div>
  );
}

// lib/signal-server.ts
import { createSignalServer } from '@signal-js/nextjs/server';

export const signal = createSignalServer({
  endpoint: process.env.SIGNAL_ENDPOINT!,
  apiKey: process.env.SIGNAL_API_KEY!,
});

// app/api/checkout/route.ts
import { NextResponse } from 'next/server';
import { signal } from '@/lib/signal-server';

export async function POST(request: Request) {
  const { userId, amount } = await request.json();
  
  signal.capture({
    distinctId: userId,
    event: 'checkout_completed',
    properties: { amount },
  });
  
  return NextResponse.json({ success: true });
}
```

## License

MIT