dDatahopdocs
Feature flags

Flags in your code

Read flags and payloads in the browser and on the server, record exposures for experiments and override values while testing.

Every flag gives your code one of these values:

ValueMeaning
true / falseBoolean flag: on or off for this user.
"control", "test", …Multivariate flag or experiment: the variant.
undefinedUnknown flag, the flag is off, or flags haven't loaded yet. Show the default.

Browser

const variant = datahop.getFeatureFlag('new-checkout')

if (variant === 'test') renderNewCheckout()
else renderOldCheckout() // 'control', false or undefined

Flags load when the page starts, and again after identify, group and reset, so targeting by plan or company applies right away. Returning visitors get the previous values instantly while fresh ones load. On a first visit, flags are undefined for a moment. To render only once they're in:

const unsubscribe = datahop.onFeatureFlags((flags) => {
  setShowBanner(flags['annual-discount-banner'] === 'test')
})

In React, call it in an effect and return unsubscribe as the cleanup. After you change a person's properties, call datahop.reloadFeatureFlags() to pick up flags that depend on them.

MethodReturnsCounts as exposure
getFeatureFlag(key)The valueYes
isFeatureEnabled(key)true for on or any variantYes
getFeatureFlagPayload(key)The payload for the user's valueNo
getAllFlags()Every flagNo

Pass { sendEvent: false } to getFeatureFlag or isFeatureEnabled to read a flag without recording an exposure.

Server (Node / Bun)

const variant = await datahop.getFeatureFlag({
  distinctId: user.id,
  key: 'new-pricing-page',
  groups: { company: user.orgId },     // needed for flags that match by company
  personProperties: { plan: 'pro' },   // values you know but haven't sent yet
})

Reading several flags for the same user in one request costs one network call. If Datahop can't be reached within a few seconds, you get undefined, so always handle the default.

Exposures and experiments

Reading a flag with getFeatureFlag or isFeatureEnabled records that the user saw it. Experiments only count people who were exposed. So:

  • Read the flag where the experience starts, such as on the pricing page and not on app start. Otherwise people who never reached the feature dilute the result.
  • Handle every variant and undefined. Show control when in doubt.
  • Logging in doesn't reshuffle anyone. A visitor who saw test before signing up still sees test after.

Once flags are loaded, the browser SDK also adds the user's flag values to every event. That lets you break down any insight by a flag, such as orders by $feature/new-checkout, without running an experiment.

Override flags while testing

Force values in your own browser for QA, demos or reproducing a bug:

datahop.overrideFeatureFlags({ 'new-checkout': 'test', 'dark-mode': true })
datahop.overrideFeatureFlags(false) // clear

Overrides stay until you clear them. They aren't recorded as exposures, so testing in your own browser never skews an experiment.

Other languages

POST /i/flags returns every flag for a user. See the SDK reference. If you use a value in an experiment, also send a $feature_flag_called event so the exposure counts.

On this page