Shipeasy
Flags & ExperimentsExperiments

Experiments — A/B tests with stats built in

A/B and multivariate experiments with managed stats. statistical analysis, holdouts, segmentation — out of the box.

Shipeasy · Experiments

Was the new thing actually better?

Define a metric, ship a variant, get a defensible answer the next morning. statistical analysis, lift, p-value and 95% CI — written back to your project.

Production readyOn this page · 6 min readUpdated · May 3, 2026Works with · Server SDK

Shipeasy Experiments lets you ask "is the new thing actually better?" and get a defensible answer.

You define what you want to measure (a metric), set up variant payloads (the groups), let users land in one bucket or another, log conversions, and look at the dashboard the next morning. The platform handles assignment, exposure stitching, deduplication, daily aggregation, and the statistics.

The five building blocks

Here is how the five pieces connect — assignment happens live in the SDK, the math happens overnight:

The 5-minute mental model

You ship feature X behind a flag. You believe it'll lift purchase_conversion. So instead of just putting it behind a feature flag, you make it an experiment: half the eligible users see X, half don't. Both groups are tracked. The next day, you look at the dashboard and read either "X lifts conversion by 3.1% (p=0.002)" — or "no significant difference, scrap it."

The honest version requires more care than that summary, and the docs walk through it.

When to use a feature flag vs. when to experiment

SituationFeature flagExperiment
Is the change reversible?
Does it have a known clear win (security fix, bug)?
Do you need an answer to "did it work"?
Cheap to ship, expensive to undo (data migration)?
Affects a metric you're paid to move?

A practical workflow is to use a feature flag first (so the rollout is safe), then promote the feature flag to an experiment once the feature is stable.

The 5-minute path

From metric to result

~5 minutes setup · 24h to first stats
01 · METRIC

Define what success looks like

One number. A primary, plus a couple of guardrails (latency, error rate).

$shipeasy metrics create purchase_conversion --event purchase --query 'count_users(purchase)'
02 · EXPERIMENT

Two groups, equal weight

100% allocation, 50/50 split, two label variants. Targeting via a feature flag is optional.

$shipeasy experiments create checkout-cta
03 · WIRE

assign + track

First call logs an exposure. flags.track() on conversion. Daily aggregation does the math.

$new Client(user).getExperiment('checkout-cta', { label: 'Pay' })

Wire the SDK

$npm install @shipeasy/sdk
import { configure, Client } from "@shipeasy/sdk/server";

configure({
  apiKey: process.env.SHIPEASY_SERVER_KEY ?? "",
  attributes: (u) => ({ user_id: u.id, plan: u.plan, country: u.country }),
});

const flags = new Client(currentUser);
const result = flags.getExperiment<{ label: string }>(
  "checkout-cta",
  { label: "Pay" }, // defaultParams
);
const label = result.params.label; // "Pay" or whatever the variant assigns
// Wherever the purchase succeeds:
flags.track(user_id, "purchase", { value: orderTotal });

The first call to flags.getExperiment(...) for a given user logs an exposure event automatically. Subsequent calls in the same process don't re-log — exposures are deduplicated.

API · Client#getExperiment

The user is bound on the Client (new Client(user)); getExperiment itself takes only the name and default params.

Prop

Type

The return shape:

{
  inExperiment: boolean,   // false if stopped, holdout, or excluded
  group: string,           // "control" | "v1" | …
  params: T,               // typed payload from the assigned group
  reason: AssignmentReason // "assigned" | "holdout" | "stopped" | "excluded"
}

What the daily analysis does

Cron enqueues a job per project

A scheduled trigger on the Shipeasy fans out one queue message per project that has running experiments.

Consumer scans events store

For each project, the consumer pulls yesterday's exposures and events from Analytics Engine, joins by user_id, and aggregates per metric × group.

statistical analysis

Lift, two-sided p-value, 95% CI. Per metric, per group, vs. the control group.

Persist results

Results are persisted to your project, scoped to the project. The dashboard reads them; you can export them.

Don't peek and stop early

The p-values are valid for fixed-horizon tests. If you sneak a look every hour and stop the moment something turns significant, you'll get false wins. Pre-decide the experiment's duration based on traffic.

Don't change variants mid-flight

Changing params on a running experiment invalidates the analysis. Stop the experiment, create a new one with v2 in the name.

READY?

Run your first experiment.

A complete walk-through: define the metric, create the experiment, wire two SDK calls, read the result the next morning.

Create the metric
$shipeasy metrics create purchase_conversion --event purchase --query 'count_users(purchase)'
Create the experiment
$shipeasy experiments create checkout-cta
Was this page helpful?
✎ Edit this page

On this page