@adopture/next
Version:
Next.js SDK for Adopture feature adoption tracking with SSR support
489 lines (386 loc) • 11.3 kB
Markdown
# /next
Next.js SDK for Adopture feature adoption tracking with full SSR support, client/server components, and edge runtime compatibility.
## Features
- 🚀 **Full Next.js 15+ support** - Works with App Router and Pages Router
- 🔄 **SSR/SSG compatible** - Server-side rendering and static generation support
- 🎯 **Client/Server separation** - Clean separation with `/next` and `/next/server`
- ⚡ **Edge runtime support** - Works in middleware and edge functions
- 🪝 **React hooks** - Easy-to-use hooks for tracking and exposure
- 📦 **Components** - Pre-built components for common tracking patterns
- 🔧 **TypeScript first** - Full TypeScript support with strict typing
- 🎭 **Web Vitals** - Built-in Core Web Vitals tracking
- 🛡️ **Error boundaries** - Automatic error tracking with error boundaries
## Installation
```bash
npm install /next /sdk-core
# or
yarn add /next /sdk-core
# or
pnpm add /next /sdk-core
```
## Quick Start
### App Router Setup
1. **Set up environment variables** (`.env.local`):
```bash
NEXT_PUBLIC_ADOPTURE_API_KEY=ad_live_your_api_key_here
NEXT_PUBLIC_ADOPTURE_API_URL=https://api.adopture.com
```
2. **Add provider to root layout** (`app/layout.tsx`):
```tsx
import { AdoptureProvider } from '@adopture/next';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<AdoptureProvider
config={{
enableAutoPageTracking: true,
enableWebVitals: true,
debug: process.env.NODE_ENV === 'development',
}}
>
{children}
</AdoptureProvider>
</body>
</html>
);
}
```
3. **Use in components**:
```tsx
'use client';
import { useAdoptureTracking, AdoptureFeature } from '@adopture/next';
export function MyComponent() {
const { track, expose, identify } = useAdoptureTracking();
return (
<AdoptureFeature featureId="hero-section" trackVisibility>
<div>
<h1>Welcome!</h1>
<button onClick={() => track('cta-click')}>
Get Started
</button>
</div>
</AdoptureFeature>
);
}
```
### Pages Router Setup
1. **Add provider to _app.tsx**:
```tsx
import { AdopturePagesProvider } from '@adopture/next';
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return (
<AdopturePagesProvider
config={{
enableAutoPageTracking: true,
enableRouteTracking: true,
}}
>
<Component {...pageProps} />
</AdopturePagesProvider>
);
}
```
## Server-Side Usage
### Server Components
```tsx
import { initServerTracker } from '@adopture/next/server';
export default async function ServerComponent() {
const tracker = await initServerTracker();
// Track server-side events
await tracker.track('server-feature', 'user-123', {
serverSide: true,
timestamp: Date.now(),
});
return (
<div>
<h1>Server Component</h1>
</div>
);
}
```
### Server Actions
```tsx
import { trackFeature, exposeFeature } from '@adopture/next/server';
async function handleSubmit(formData: FormData) {
'use server';
// Track the form submission
await trackFeature('form-submit', 'user-123', {
formType: 'contact',
fields: formData.size,
});
// Process the form...
}
```
### API Routes
```tsx
import { getServerTracker } from '@adopture/next/server';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const tracker = getServerTracker();
try {
const data = await request.json();
// Track API usage
await tracker.track('api-endpoint', data.userId, {
endpoint: '/api/users',
method: 'POST',
});
// Process request...
return NextResponse.json({ success: true });
} catch (error) {
// Track errors
await tracker.track('api-error', 'unknown', {
endpoint: '/api/users',
error: error.message,
});
return NextResponse.json({ error: 'Failed' }, { status: 500 });
}
}
```
## Middleware Integration
Create `middleware.ts` in your project root:
```tsx
import { createAdoptureMiddleware } from '@adopture/next/middleware';
const adoptureMiddleware = createAdoptureMiddleware({
apiKey: process.env.ADOPTURE_API_KEY!,
enableRouteTracking: true,
enablePerformanceTracking: true,
excludeRoutes: ['/_next/*', '/api/internal/*'],
userIdExtractor: (request) => {
// Extract user ID from request
const authHeader = request.headers.get('authorization');
return authHeader?.split('Bearer ')[1] || null;
},
});
export async function middleware(request: NextRequest) {
return adoptureMiddleware(request);
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};
```
## React Hooks
### useAdoptureTracking
Main hook for accessing all tracking functionality:
```tsx
import { useAdoptureTracking } from '@adopture/next';
function MyComponent() {
const { track, expose, identify, isInitialized } = useAdoptureTracking();
useEffect(() => {
if (isInitialized) {
expose('my-component', 'mount');
}
}, [isInitialized, expose]);
const handleClick = () => {
track('button-click', {
component: 'MyComponent',
timestamp: Date.now(),
});
};
return <button onClick={handleClick}>Click me</button>;
}
```
### useComponentTracking
Automatically track component lifecycle:
```tsx
import { useComponentTracking } from '@adopture/next';
function MyComponent() {
useComponentTracking('my-component', {
trackMount: true,
trackUnmount: true,
metadata: { version: '1.0' },
});
return <div>Component content</div>;
}
```
### useVisibilityTracking
Track when elements become visible:
```tsx
import { useVisibilityTracking } from '@adopture/next';
function MyComponent() {
const visibilityRef = useVisibilityTracking('visible-element', {
threshold: 0.5,
trackOnce: true,
});
return (
<div ref={visibilityRef}>
This will be tracked when 50% visible
</div>
);
}
```
## Components
### AdoptureFeature
Wrap any content to automatically track exposure and interactions:
```tsx
import { AdoptureFeature } from '@adopture/next';
function MyPage() {
return (
<AdoptureFeature
featureId="hero-banner"
trackVisibility
trackInteractions
visibilityOptions={{ threshold: 0.8 }}
>
<div>Your feature content</div>
</AdoptureFeature>
);
}
```
### AdoptureTrackClick
Track click events easily:
```tsx
import { AdoptureTrackClick } from '@adopture/next';
function MyComponent() {
return (
<AdoptureTrackClick
featureId="cta-button"
as="button"
className="btn-primary"
metadata={{ location: 'header' }}
>
Get Started
</AdoptureTrackClick>
);
}
```
### AdoptureErrorBoundary
Automatically track React errors:
```tsx
import { AdoptureErrorBoundary } from '@adopture/next';
function MyApp() {
return (
<AdoptureErrorBoundary
featureId="app-boundary"
fallback={({ error, retry }) => (
<div>
<p>Error: {error.message}</p>
<button onClick={retry}>Retry</button>
</div>
)}
>
<MyComponent />
</AdoptureErrorBoundary>
);
}
```
## Configuration
### Client Configuration
```tsx
const config: NextAdoptureConfig = {
apiKey: 'ad_live_xxx', // or from NEXT_PUBLIC_ADOPTURE_API_KEY
apiUrl: 'https://api.adopture.com',
enableAutoPageTracking: true,
enableWebVitals: true,
enableRouteTracking: true,
disableInDevelopment: false,
debug: true,
batchSize: 50,
flushInterval: 5000,
visibility: {
enabled: true,
threshold: 0.5,
minDuration: 1000,
},
};
```
### Server Configuration
```tsx
const config: ServerAdoptureConfig = {
apiKey: 'ad_live_xxx', // from ADOPTURE_API_KEY (server-only)
apiUrl: 'https://api.adopture.com',
enableEdgeRuntime: true,
requestTimeout: 5000,
batchSize: 100,
flushInterval: 10000,
};
```
## Environment Variables
### Client-side (Browser)
- `NEXT_PUBLIC_ADOPTURE_API_KEY` - Your Adopture API key
- `NEXT_PUBLIC_ADOPTURE_API_URL` - API endpoint (defaults to https://api.adopture.com)
- `NEXT_PUBLIC_ADOPTURE_PROJECT_ID` - Project ID (auto-extracted from API key)
- `NEXT_PUBLIC_ADOPTURE_ENVIRONMENT` - Environment (live/test)
- `NEXT_PUBLIC_ADOPTURE_DEBUG` - Enable debug mode
### Server-side
- `ADOPTURE_API_KEY` - Server API key (more secure, not sent to client)
- `ADOPTURE_API_URL` - API endpoint
- `ADOPTURE_PROJECT_ID` - Project ID
- `ADOPTURE_ENVIRONMENT` - Environment
- `ADOPTURE_DEBUG` - Enable debug mode
## SSR Bootstrap Pattern
For optimal SSR performance, bootstrap client-side tracking with server data:
```tsx
// app/layout.tsx (Server Component)
import { initServerTracker } from '@adopture/next/server';
import { AdoptureBootstrap } from '@adopture/next';
export default async function RootLayout({ children }) {
const tracker = await initServerTracker();
const bootstrapData = tracker.generateBootstrapData('user-123', {
plan: 'pro',
signupDate: '2024-01-01',
});
return (
<html>
<head>
{bootstrapData && <AdoptureBootstrap data={bootstrapData} />}
</head>
<body>
<AdoptureProvider config={{ bootstrapFromServer: true }}>
{children}
</AdoptureProvider>
</body>
</html>
);
}
```
## TypeScript Support
Full TypeScript support with strict typing:
```tsx
import type {
NextAdoptureConfig,
NextAdoptureTracker,
BootstrapData,
UseAdoptureReturn
} from '@adopture/next';
const config: NextAdoptureConfig = {
apiKey: 'ad_live_xxx',
enableWebVitals: true,
// Full autocompletion and type checking
};
```
## Best Practices
1. **Use environment variables** for configuration
2. **Enable debug mode** during development
3. **Use server-side tracking** for sensitive operations
4. **Implement error boundaries** for robust error tracking
5. **Use visibility tracking** for engagement metrics
6. **Bootstrap from server** for optimal performance
7. **Exclude internal routes** in middleware
8. **Use TypeScript** for better developer experience
## Examples
Check out the [examples directory](./examples) for complete implementation examples:
- [App Router Example](./examples/app-router)
- [Pages Router Example](./examples/pages-router)
- [Middleware Example](./examples/middleware)
- [Server Actions Example](./examples/server-actions)
## API Reference
### Client API
- `NextClientTracker` - Main client-side tracker class
- `AdoptureProvider` - React provider for App Router
- `AdopturePagesProvider` - React provider for Pages Router
- `useAdoptureTracking()` - Main tracking hook
- `useTrack()`, `useExpose()`, `useIdentify()` - Specific tracking hooks
- `AdoptureFeature`, `AdoptureTrackClick` - Tracking components
### Server API
- `NextServerTracker` - Server-side tracker class
- `createServerTracker()`, `getServerTracker()` - Factory functions
- `trackFeature()`, `exposeFeature()` - Server actions
- `createAdoptureMiddleware()` - Middleware factory
## License
MIT © Adopture