JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 27
  • Score
    100M100P100Q61811F
  • License MIT

Zero-config A/B testing for React and Next.js

Package Exports

  • @testlyjs/react
  • @testlyjs/react/next
  • @testlyjs/react/server

Readme

@testlyjs/react

The definitive A/B Testing infrastructure for the React ecosystem.

NPM Version React Support Bundle Size

Testly turns A/B tests into code. Define variants directly in your frontend and let our infrastructure handle statistical distribution, user persistence, and real-time metric collection.

📖 Full Official Documentation →


🔥 Features

  • ⚡ Zero Flicker: Optimized for SSR and hydration to prevent layout shifts.
  • ⚛️ Universal: Compatible with React 16.8+, 17, 18, and 19 (Vite, Next.js, Remix).
  • 🚀 Next.js 15 Ready: Built-in support for Server Components and hydration.
  • 🛡️ Type-Safe: Native TypeScript support for variants and conversions.
  • 📦 Lightweight: Under 10KB, zero external dependencies.

🚀 Quick Start

1. Installation

npm install @testlyjs/react

2. Provider Configuration (Client-side)

Wrap your application at the highest level:

import { TestlyProvider } from '@testlyjs/react';

function Root() {
  return (
    <TestlyProvider 
      apiKey="your_api_key"
      config={{ debug: true }} // Helpful during development
    >
      <App />
    </TestlyProvider>
  );
}

3. Implementing an Experiment

Use the useExperiment hook to assign variants and track conversions.

import { useExperiment } from '@testlyjs/react';

function HeroSection() {
  const { variant, convert, loading } = useExperiment('new-landing-page');

  if (loading) return <div className="skeleton" />; // Handle loading state

  return (
    <div>
      <h1>
        {variant === 'variant-b' 
          ? 'Experience the future of A/B testing' 
          : 'Testing made simple'}
      </h1>
      <button onClick={() => convert('signup-click')}>
        Get Started
      </button>
    </div>
  );
}

🏗️ Next.js 15 / SSR Integration (Zero-Config)

With version 0.2.0, integration is now almost entirely automatic.

1. Setup Environment

Add your API key to your .env.local:

TESTLY_API_KEY=your_api_key_here

Create a middleware.ts file to ensure every user has a persistent ID:

import { createTestlyMiddleware } from '@testlyjs/react/next';

export const middleware = createTestlyMiddleware();

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

3. Server-side Fetch (app/layout.tsx)

The SDK will automatically find your API key and the user's ID from cookies.

import { getServerAssignment } from '@testlyjs/react/server';

export default async function RootLayout({ children }) {
  // ZERO-CONFIG: No need to pass API Key or User ID manually anymore!
  const initialAssignments = await getServerAssignment({
    experimentKey: 'my-hero-test'
  });

  return (
    <TestlyClientProvider initialAssignments={initialAssignments}>
      {children}
    </TestlyClientProvider>
  );
}

2. Client Provider Wrapper (components/TestlyClientProvider.tsx)

'use client';
import { TestlyProvider } from '@testlyjs/react';

export function TestlyClientProvider({ children, initialAssignments }) {
  return (
    <TestlyProvider 
      apiKey={process.env.NEXT_PUBLIC_TESTLY_KEY!}
      initialAssignments={initialAssignments}
    >
      {children}
    </TestlyProvider>
  );
}

🛠️ Debugging & Monitoring

Debug Mode

Enable debug: true in the configuration to see detailed logs in the browser console about assignments, impressions, and conversions.

<TestlyProvider config={{ debug: true }}>

Custom Logging

Capture all SDK events (like analytics) using the onLog callback:

<TestlyProvider 
  config={{ 
    onLog: (event) => {
      console.log('[Testly Event]', event);
      // Send to your own analytics if needed
    } 
  }}
>

Console Indicators

  • [Testly] Tracking impression...: SDK successfully recorded a view.
  • [Testly] ✅ Conversion recorded...: Success!
  • [Testly] ❌ TRACKING BLOCKED: Check your API key or experiment ID.

📘 API Reference

useExperiment(key, options)

Returns the current variant for a specific experiment.

  • variant: The assigned variant key (or null).
  • loading: Boolean indicating if the SDK is still initializing or fetching.
  • convert(type, metadata): Function to track a conversion for THIS experiment.

useConversion()

A global hook to track conversions across ALL active experiments on the current page.

const convert = useConversion();
convert('global-purchase', { value: 99.90 });

🛡️ Resilience

  • LocalStorage Caching: Variants are cached locally to ensure a consistent user experience and zero-latency on return visits.
  • Automatic Deduplication: Conversions are only tracked once per session/user (configurable).
  • Graceful Fallbacks: If the API is unreachable, the SDK fails silently and uses your provided fallback values.

MIT © Testly