@koryla/astro
v0.1.4
Published
A/B testing for Astro sites in SSR mode. Assign variants in page frontmatter — zero client-side JavaScript, zero flicker.
Downloads
41
Readme
@koryla/astro
A/B testing for Astro sites in SSR mode. Assign variants in page frontmatter — zero client-side JavaScript, zero flicker.
Installation
npm install @koryla/astroSetup
1. Add environment variables
# .env
KORYLA_API_KEY=sk_live_...
KORYLA_API_URL=https://koryla.com2. Enable SSR in astro.config.mjs
// astro.config.mjs
export default defineConfig({
output: 'server',
})3. Use in your page
---
// src/pages/index.astro
import { getVariant } from '@koryla/astro'
const result = await getVariant(Astro.request, 'your-experiment-id', {
apiKey: import.meta.env.KORYLA_API_KEY,
apiUrl: import.meta.env.KORYLA_API_URL,
})
if (result?.isNewAssignment) {
Astro.cookies.set(result.cookieName, result.variantId, {
maxAge: 60 * 60 * 24 * 30,
sameSite: 'lax',
path: '/',
})
}
---
{result?.variantId === 'variant-b' ? (
<h1>New headline that converts better</h1>
) : (
<h1>Original headline</h1>
)}4. Create an experiment in Koryla
Go to your Koryla dashboard → New experiment, set variants and conversion URL, set to Active.
How it works
User visits /
│
▼
Astro SSR renders src/pages/index.astro frontmatter
│
├── getVariant() reads config (cached 60s)
├── reads koryla_sid cookie from Astro.request
│ ├── cookie present → use existing variant (sticky)
│ └── no cookie → assign variant by traffic weight
│
├── sets sticky cookie via Astro.cookies.set()
└── frontmatter conditionally renders the correct variant
│
▼
Browser receives HTML with the correct variant already rendered
No JS, no swap, no flickerAPI
getVariant(request, experimentId, options)
| Parameter | Type | Description |
|-----------|------|-------------|
| request | Request | Astro.request |
| experimentId | string | Experiment ID from Koryla dashboard |
| options.apiKey | string | Your sk_live_... API key |
| options.apiUrl | string | https://koryla.com |
Returns Promise<VariantResult | null>. null means the experiment wasn't found or is inactive.
interface VariantResult {
experiment: Experiment
variant: Variant // the assigned variant object
variantId: string // e.g. "abc-123"
isNewAssignment: boolean
cookieName: string // e.g. "ky_exp-id"
}Why this is better than VWO / Optimizely
| | VWO / Optimizely | @koryla/astro | |--|--|--| | When variant is decided | In the browser, after JS loads | In SSR frontmatter, before any HTML | | Flicker | Yes (page hides while swapping) | No | | Extra JS on page | ~80–150 KB | 0 KB | | Blockable by ad blockers | Yes | No | | Works without JS | No | Yes |
