Skip to main content

Next.js Integration

The Solute SDK provides first-class support for Next.js App Router with React hooks, server-side utilities, and middleware.

Setup

1. Install the SDK

npm install @solute-ai/sdk

2. Create Provider Wrapper

Create a client component wrapper for the provider:
// components/providers/SoluteProviderWrapper.tsx
'use client';

import { SoluteProvider } from '@solute-ai/sdk/nextjs';

export function SoluteProviderWrapper({ children }) {
  return (
    <SoluteProvider
      config={{
        apiKey: process.env.NEXT_PUBLIC_SOLUTE_API_KEY!,
        host: process.env.NEXT_PUBLIC_SOLUTE_HOST || 'https://api.solute.dev',
        debug: process.env.NODE_ENV === 'development',
      }}
    >
      {children}
    </SoluteProvider>
  );
}

3. Add to Root Layout

// app/layout.tsx
import { SoluteProviderWrapper } from '@/components/providers/SoluteProviderWrapper';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <SoluteProviderWrapper>
          {children}
        </SoluteProviderWrapper>
      </body>
    </html>
  );
}

React Hooks

Use hooks in client components to access SDK functionality.

useTrack

Track events in client components:
'use client';

import { useTrack } from '@solute-ai/sdk/nextjs';

export function SignupButton() {
  const track = useTrack();

  const handleClick = () => {
    track('Signup Button Clicked', {
      button_id: 'header-cta',
      page: '/homepage',
    });
  };

  return <button onClick={handleClick}>Sign Up</button>;
}

useIdentify

Identify users:
'use client';

import { useIdentify } from '@solute-ai/sdk/nextjs';

export function LoginForm() {
  const identify = useIdentify();

  const handleLogin = async (userData: { id: string; email: string }) => {
    identify(userData.id, {
      email: userData.email,
    });
  };

  return <form onSubmit={handleLogin}>...</form>;
}

useFeatureEnabled

Check if a feature is enabled:
'use client';

import { useFeatureEnabled } from '@solute-ai/sdk/nextjs';

export function CheckoutButton() {
  const showNewCheckout = useFeatureEnabled('new-checkout-flow');

  return (
    <div>
      {showNewCheckout ? (
        <NewCheckoutButton />
      ) : (
        <OldCheckoutButton />
      )}
    </div>
  );
}

useExperiment

Get A/B test variant:
'use client';

import { useExperiment } from '@solute-ai/sdk/nextjs';

export function PricingPage() {
  const variant = useExperiment('pricing-test');

  return (
    <div>
      {variant === 'variant-a' ? (
        <NewPricingLayout />
      ) : (
        <OriginalPricingLayout />
      )}
    </div>
  );
}

useUser

Get user information:
'use client';

import { useUser } from '@solute-ai/sdk/nextjs';

export function UserInfo() {
  const { userId, anonymousId, sessionId } = useUser();

  return (
    <div>
      <p>User ID: {userId || 'Anonymous'}</p>
      <p>Anonymous ID: {anonymousId}</p>
      <p>Session: {sessionId}</p>
    </div>
  );
}

useSolute

Access the full SDK instance:
'use client';

import { useSolute } from '@solute-ai/sdk/nextjs';

export function MyComponent() {
  const { track, identify, client } = useSolute();

  // Use any SDK method
  const handleAction = () => {
    track('Action', { type: 'custom' });
    identify('user_123', { email: '[email protected]' });
  };

  return <button onClick={handleAction}>Action</button>;
}

Server-Side Utilities

Use server-side utilities in Server Components and API routes.

trackServerEvent

Track events on the server:
// app/actions.ts
'use server';

import { trackServerEvent } from '@solute-ai/sdk/nextjs';

export async function createOrder(orderData: any) {
  // Create order...
  
  // Track event
  await trackServerEvent(
    {
      apiKey: process.env.SOLUTE_API_KEY!,
      host: 'https://api.solute.dev',
    },
    'Order Created',
    {
      order_id: orderData.id,
      amount: orderData.amount,
    }
  );
}

getServerFeatureFlag

Get feature flags on the server:
// app/page.tsx
import { getServerFeatureFlag, isServerFeatureEnabled } from '@solute-ai/sdk/nextjs';

export default async function HomePage() {
  // Check if feature is enabled
  const showHero = await isServerFeatureEnabled(
    {
      apiKey: process.env.SOLUTE_API_KEY!,
      host: 'https://api.solute.dev',
    },
    'new-hero-section',
    false
  );

  // Get feature flag value
  const heroConfig = await getServerFeatureFlag(
    {
      apiKey: process.env.SOLUTE_API_KEY!,
      host: 'https://api.solute.dev',
    },
    'hero-config',
    { theme: 'default' }
  );

  return (
    <div>
      {showHero ? (
        <NewHeroSection config={heroConfig} />
      ) : (
        <OldHeroSection />
      )}
    </div>
  );
}

getServerExperimentVariant

Get experiment variant on the server:
// app/pricing/page.tsx
import { getServerExperimentVariant } from '@solute-ai/sdk/nextjs';

export default async function PricingPage() {
  const variant = await getServerExperimentVariant(
    {
      apiKey: process.env.SOLUTE_API_KEY!,
      host: 'https://api.solute.dev',
    },
    'pricing-test',
    'control'
  );

  return (
    <div>
      {variant === 'variant-a' ? (
        <NewPricingLayout />
      ) : (
        <OriginalPricingLayout />
      )}
    </div>
  );
}

Middleware

Set up automatic page view tracking with middleware:
// middleware.ts
import { createSoluteMiddleware } from '@solute-ai/sdk/nextjs';
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export const middleware = createSoluteMiddleware({
  apiKey: process.env.SOLUTE_API_KEY!,
  host: 'https://api.solute.dev',
  excludePaths: ['/admin/*', '/api/*'],
  debug: process.env.NODE_ENV === 'development',
});

export const config = {
  matcher: [
    '/((?!_next/static|_next/image|favicon.ico|.*\\..*|api).*)',
  ],
};

Environment Variables

Set up environment variables:
# Client-side (public)
NEXT_PUBLIC_SOLUTE_API_KEY=your_api_key_here
NEXT_PUBLIC_SOLUTE_HOST=https://api.solute.dev

# Server-side (private)
SOLUTE_API_KEY=your_api_key_here
SOLUTE_HOST=https://api.solute.dev
Use NEXT_PUBLIC_ prefix for client-side environment variables. Server-side variables don’t need the prefix.

Best Practices

React hooks can only be used in client components. Make sure to add 'use client' directive.
Use server-side utilities in Server Components and API routes for better performance.
Use different environment variables for client and server to keep API keys secure.
Wrap your app with SoluteProvider at the root layout level to ensure hooks work everywhere.

Next Steps