VeroXM Docs

Content Experiments

Content Experiments is VeroXM's built-in A/B testing module: run two or more variants of a content entry, split traffic between them by weight, and track impressions and conversions until you declare a winner. It is the clearest example of why VeroXM is an experience management system rather than a plain content store - the same entry that holds your copy can also be the thing you measure and improve.

Why run experiments

Publishing is a guess about what will work. Content Experiments replaces the guess with a measurement, without adding a second tool or a separate content pipeline to maintain.

  • Higher conversion, without a rewrite. Two headlines, two calls-to-action, two onboarding steps - whichever variant actually gets more signups, add-to-carts, or click-throughs wins, instead of whichever one a team liked better in review.
  • Lower risk on a redesign. Ship the new version to a fraction of traffic first (a 10/90 or 50/50 split), watch the conversion rate, and only roll it out fully once the numbers back it up - reverting is deleting the experiment, not reverting a deploy.
  • Decisions backed by data, not opinion. Impressions and conversions are tracked per variant automatically, so “we think the shorter headline converts better” becomes a conversion-rate number your team can point to.
  • No new systems to run. A variant is just another content entry, so it goes through the same field validation, draft/publish states, and approval workflow as everything else - there is no separate experimentation service to configure, secure, or keep in sync with your content.
  • Safe by default for existing integrations. Only requests that explicitly opt in with ?experiment=1 are affected, so turning on an experiment never changes what an existing integration receives.

How it fits the content model

An experiment does not introduce a new way to store content. Each variant is an ordinary entry in the same collection as the entry being tested, so every variant gets full field validation, draft states, and approval workflow for free. The experiment itself just adds the bookkeeping on top: a name, a status (draft / running / completed), a traffic weight and running counts for each variant, and an optional winner.

Running an experiment from the dashboard

  1. Open a content entry and switch to its Experiment tab.
  2. Create an experiment and add two or more variants, each pointing at another entry in the same collection (create a copy of the entry first, then edit the copy - the variant is just a normal entry).
  3. Set a traffic weight for each variant; weights must add up to 100 before the experiment can start.
  4. Start the experiment. Traffic now splits across variants whenever your application resolves the entry through the Content API with ?experiment=1.
  5. Once you have enough data, declare a winner from the variant with the strongest conversion rate, or end the experiment without one.

Worked example: testing a homepage headline

Say a marketing team wants to know whether a benefit-led headline outperforms a feature-led one on the homepage hero entry.

  1. Duplicate the hero entry. Entry #401 keeps the original headline (“Manage content across every project”); the copy, entry #402, gets the challenger (“Ship content changes 3x faster”).
  2. Create an experiment named “Homepage hero headline” on entry #401, add both #401 and #402 as variants, and set an even 50/50 traffic split.
  3. Start the experiment.
  4. The homepage requests the hero entry with ?experiment=1 on every pageview, and calls the convert endpoint whenever a visitor clicks through to pricing.

After a week, the variant counts might look like this:

VariantHeadlineImpressionsConversionsConversion rate
#401 (original)Feature-led4,1801463.5%
#402 (challenger)Benefit-led4,2152195.2%

#402 is converting about 49% better on comparable traffic, so the team declares it the winner from the Experiment tab. The experiment moves to completed, and the dashboard keeps both entries around so the result stays auditable - nothing about how the homepage requests the entry needs to change afterward; the next step is simply publishing #402's headline as the new default.

Dashboard API

Every route below is relative to /projects/:projectId/collections/:collectionId/content/:contentId/experiments, requires a project session, and follows the same viewer/editor role gating as content editing - viewing an experiment needs viewer, changing one needs editor.

GET/

List experiments for a content entry

Requires viewer.

POST/

Create an experiment

Request body
{ "name": "Homepage hero copy" }
POST/:experimentId/variants

Add a variant

contentId must be another entry in the same collection as the entry the experiment was created on.

Request body
{ "contentId": 512, "label": "Variant B" }
DELETE/:experimentId/variants/:variantId

Remove a variant

POST/:experimentId/weights

Set traffic weights

Request body
{
  "weights": [
    { "variantId": 501, "trafficWeight": 50 },
    { "variantId": 502, "trafficWeight": 50 }
  ]
}
POST/:experimentId/start

Start the experiment

POST/:experimentId/complete

Complete the experiment

winnerVariantId is optional - omit it to end the experiment without declaring a winner.

Request body
{ "winnerVariantId": 501 }
DELETE/:experimentId

Delete an experiment

Resolving a variant from the Content API

Add ?experiment=1 to a Get One Entry request. If the entry has a running experiment, VeroXM picks a variant with a weighted-random roll against each variant's traffic weight and returns that variant's content in place of the base entry, with the experiment and variant ids attached:

GET /collections/:slug/content/:id?experiment=1
{
  "id": 502,
  "data": { "headline": "..." },
  "experiment": 14,
  "variant": 502
}

This is opt-in on purpose: existing integrations that never pass ?experiment=1 keep getting the base entry, unaffected by any experiment running on it. Variant selection is not session-sticky on the server - persist the returned variant id on your end (a cookie, local storage, a server-side session) if a visitor needs to keep seeing the same variant across requests.

Recording a conversion

POST/public/v2/projects/:uuid/experiments/variants/:variantId/convert

Record a conversion for a variant

Requires the update ability. Call this when the visitor who saw that variant completes the action you're measuring - a signup, a purchase, a click.

Response
{ "success": true }

Metrics are project-scoped

Variant ids are ordinary auto-increment integers, so conversion recording is scoped to the token's own project - a token from one project can never inflate another project's experiment counts, even if it guesses a valid-looking variant id.