Shipeasy
Flags & ExperimentsCase studies

Count an exposure only when the variant is actually seen

Resolve a variant in a prefetch or lazy component with logExposure:false, then log the exposure by hand the moment it renders.

Production readyOn this page · 3 min readUpdated · June 19, 2026Works with · @shipeasy/sdk · server + client

Your experiment lives in a tab that most users never open. But your server loader resolves the variant for everyone up front to render the page — so every user gets an exposure, including the ones who never see the tab. Your "exposed" population is now mostly people who weren't exposed to anything, and the effect you're measuring is diluted toward zero.

The fix is manual exposure: resolve the variant without counting it, then count it at the exact moment it renders.

The shape: decouple resolving from logging. Pass logExposure: false when you read the variant, and call logExposure later, once, when the user actually sees it.

1. Resolve without logging

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

configure({ apiKey: process.env.SHIPEASY_SERVER_KEY! });

const flags = new Client({ user_id: "u_4f2a" });
const result = flags.getExperiment(
  "checkout_button",
  { color: "blue" }, // default params
  { logExposure: false }, // resolve only — no exposure yet
);

If a whole engine should never auto-log, set it once at construction instead:

import { Engine } from "@shipeasy/sdk/server";

const engine = new Engine({
  apiKey: process.env.SHIPEASY_SERVER_KEY!,
  disableAutoExposure: true,
});

2. Log it when the variant renders

Fire the exposure from the code path that mounts the variant — not the loader:

// in the component / handler that actually shows the variant —
// the client is already bound to the user, so pass just the experiment name
flags.logExposure("checkout_button");

If you're holding the Engine directly rather than a bound Client, pass the user too: engine.logExposure({ user_id: "u_4f2a" }, "checkout_button"). In the browser the visitor is already identified, so the bound call is the same: flags.logExposure("checkout_button").

Exactly once, on render

A duplicate exposure for the same user/experiment is deduped by the pipeline, but the clean contract is: suppress the auto-exposure, then call logExposure exactly once — when the user sees the variant, not when you computed it.

Rollout & measurement plan

  • "Exposed" should mean "saw it." With manual exposure your denominator is the people who actually reached the surface, so the measured lift is the real one.
  • Audit the render path. The bug to avoid is logging in a code path that runs even when the component doesn't mount — put the logExposure call as close to the render as you can.
  • Prefetch + lazy UI are the classic cases. Server loaders, tabs, modals, and routes that may never open are exactly where auto-exposure over-counts.
Was this page helpful?
✎ Edit this page

On this page