JSPM

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

React hooks for A/B testing with Testly

Package Exports

  • @testlyjs/react
  • @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 (Pro Way)

To avoid Layout Shift (CLS) and ensure zero flicker, fetch variants on the server and pass them to the provider.

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

// ⚠️ Note the /server subpath!
import { getServerAssignment } from '@testlyjs/react/server';
import { cookies } from 'next/headers';

export default async function RootLayout({ children }) {
  const cookieStore = await cookies();
  const userId = cookieStore.get('testly_user_id')?.value || 'guest';

  // Fetch assignment directly in the Server Component
  const initialAssignments = await getServerAssignment({
    apiKey: process.env.TESTLY_API_KEY!,
    experimentKey: 'hero-cta-test',
    userId
  });

  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