A/B Landing Platform — Demo

Portfolio example of a split-testing platform for marketing landing pages. Each landing exists in three independent versions built with Next.js parallel routes (@v1 / @v2 / @v3). Every experiment is described by a config object next to its page (_config.ts) that controls which versions are active and their rollout percentages — the middleware just reads it.

All content is placeholder (lorem ipsum). The original production project is covered by an NDA — this repo re-implements only the generic mechanics.

/landing-alpha

VersionStatusWeightRollout
V1active5050%force
V2active3030%force
V3active2020%force

/landing-beta

VersionStatusWeightRollout
V1active6060%force
V2active4040%force
V3inactive25preview

How it works

  1. Each landing owns a _config.ts with a plain config object: declared versions, their active flag and rollout weight. Weights are relative and don't have to sum to 100. This table above is rendered from those very objects.
  2. src/middleware.ts is fully generic — it looks the config up in a registry (src/lib/split-tests.ts) and resolves the version: forced ?v= param → existing cookie (only if that version is still active) → weighted random pick.
  3. The version is written to the x-ab-version request header (so the very first server render already knows it) and persisted in an ab_{slug} cookie for 365 days, scoped to the landing path. Deactivating a version in the config automatically reassigns its audience.
  4. Each landing's layout.tsx resolves the version on the server and renders the matching parallel route slot — @v1, @v2 or @v3. Versions are fully independent pages with their own sections and themes.
  5. Inactive versions (like Landing Beta V3) never win the rollout but remain reachable via ?v=v3 — a preview mode for QA and stakeholders.