@testlyjs/react
v0.2.0
Published
Zero-config A/B testing for React and Next.js
Maintainers
Readme
@testlyjs/react
The definitive A/B Testing infrastructure for the React ecosystem.
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/react2. 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_here2. Add Middleware (Optional but Recommended)
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
