UNPKG

@adopture/next

Version:

Next.js SDK for Adopture feature adoption tracking with SSR support

489 lines (386 loc) 11.3 kB
# @adopture/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 `@adopture/next` and `@adopture/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 @adopture/next @adopture/sdk-core # or yarn add @adopture/next @adopture/sdk-core # or pnpm add @adopture/next @adopture/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