npm package: @runab/js
Description: JavaScript SDK for runab. Tiny (~1.2kb gzipped). Zero dependencies.
Author: runab
Latest version: 0.5.0

# @runab/js

> JavaScript SDK for runab. Tiny (~1.2kb gzipped). Zero dependencies.

[![npm version](https://img.shields.io/npm/v/@runab/js.svg)](https://www.npmjs.com/package/@runab/js)
[![npm downloads](https://img.shields.io/npm/dm/@runab/js.svg)](https://www.npmjs.com/package/@runab/js)

**Version:** 0.5.0  
**Last Published:** December 2025

---

## Quick Start

The easiest way to get started:

```bash
npx @runab/js init
```

This interactive wizard will:
1. Ask for your site key (from [runab.io/dashboard](https://runab.io/dashboard))
2. Help you create or connect a test
3. Set up everything automatically for your framework

---

## Manual Installation

```bash
npm install @runab/js
```

---

## Usage

### React (Client Components)

```tsx
import { RunabProvider, useVariant, useTrackConversion } from '@runab/js/react'

function App() {
  return (
    <RunabProvider siteKey="pk_abc123">
      <Hero />
    </RunabProvider>
  )
}

function Hero() {
  const variant = useVariant('hero-test')
  const track = useTrackConversion('hero-test')

  if (!variant) return <Skeleton />

  return (
    <div>
      {variant === 'A' ? <HeroA /> : <HeroB />}
      <button onClick={track}>Get Started</button>
    </div>
  )
}
```

### Next.js (Edge Middleware)

```ts
// middleware.ts
import { runabMiddleware } from '@runab/js/next'

export const middleware = runabMiddleware({
  siteKey: 'pk_abc123',
  tests: ['hero-test', 'pricing-test']
})

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

### Next.js (Server Components)

```tsx
import { getVariant } from '@runab/js/next'

export default async function Page() {
  const variant = await getVariant('hero-test')
  return variant === 'A' ? <HeroA /> : <HeroB />
}
```

### Vanilla JavaScript

```ts
import { init, getVariant, trackConversion } from '@runab/js'

init({ siteKey: 'pk_abc123' })

const variant = getVariant('hero-test')
if (variant === 'A') {
  // Show version A
} else {
  // Show version B
}

// Track conversion
button.onclick = () => trackConversion('hero-test')
```

### HTML Script Tag

```html
<script 
  src="https://cdn.runab.io/snippet.js" 
  data-site-key="pk_abc123" 
  data-tests="hero-test"
  async
></script>

<script>
  const variant = window.runab.getVariant('hero-test')
  if (variant === 'B') {
    // Show variant B
  }
</script>
```

---

## URL Split Tests

Test different URLs against each other without writing code. Visitors are randomly split between your control URL and variant URL.

### HTML Script Tag (Simplest)

```html
<!-- Add this to your control page (URL A) -->
<script 
  src="https://cdn.runab.io/snippet.js" 
  data-site-key="pk_abc123" 
  data-url-split="landing-test:https://example.com/landing-v2"
  async
></script>
```

Visitors assigned to variant B are automatically redirected to the variant URL.

### JavaScript

```ts
import { init, handleUrlSplit } from '@runab/js'

init({ siteKey: 'pk_abc123' })

// On your control page - redirects B visitors to variant URL
handleUrlSplit('landing-test', 'https://example.com/landing-v2')
```

### How It Works

1. Visitor lands on your control page (URL A)
2. SDK assigns them to variant A or B (50/50 split)
3. If variant B → automatically redirects to variant URL
4. Query parameters are preserved during redirect
5. Assignment is stored in a cookie for consistency

---

## API Reference

### Core (`@runab/js`)

| Function | Description |
|----------|-------------|
| `init(config)` | Initialize the SDK |
| `getVariant(testId)` | Get assigned variant ('A' or 'B') |
| `trackConversion(testId)` | Track a conversion event |
| `handleUrlSplit(testId, variantUrl)` | Redirect B visitors to variant URL |
| `getVisitorId()` | Get the visitor ID |
| `forceVariant(testId, variant)` | Force a variant (localhost only) |

### React (`@runab/js/react`)

| Export | Description |
|--------|-------------|
| `RunabProvider` | Context provider component |
| `useVariant(testId)` | Hook to get variant |
| `useTrackConversion(testId)` | Hook to get tracking function |

### Next.js (`@runab/js/next`)

| Export | Description |
|--------|-------------|
| `runabMiddleware(config)` | Edge middleware factory |
| `withRunab(middleware, config)` | Wrap existing middleware |
| `getVariant(testId, request?)` | Get variant in Server Components |
| `getVisitorId(request?)` | Get visitor ID server-side |

---

## Bundle Size

```
@runab/js          3.7kb (1.2kb gzipped)
@runab/js/react    4.5kb (1.5kb gzipped)
@runab/js/next     1.2kb (0.5kb gzipped)
```

---

## CLI

```bash
npx @runab/js init
```

The interactive CLI will guide you through:
1. Entering your site key
2. Creating or connecting a test
3. Automatic framework detection (Next.js, Vite, CRA, static HTML)
4. Setting up middleware (Next.js) or script tags
5. Showing you exactly how to use it in your code

---

## Links

- [Documentation](https://runab.io/docs)
- [Dashboard](https://runab.io/dashboard)
- [GitHub](https://github.com/runab/runab-js)

---

## License

MIT