Evaluate feature flags
Evaluate feature flags and variants for the current visitor in the browser.
The web SDK evaluates the feature flags you configure in Studio for the current visitor, so a feature can be on for some people and off for others without a deploy. Create and roll out flags under A/B testing → Feature flags; see Feature flags.
Feature flags are in early access. Ask us on Discord, or email support@voidhash.com on a paid plan, to turn them on for your team.
Evaluate flags
getFeatureFlags() evaluates the keys you pass, or every flag when you pass none:
const { flags, isStale } = await voidhash.getFeatureFlags(["new-pricing", "checkout-test"]);
const newPricing = flags.find((flag) => flag.key === "new-pricing")?.enabled ?? false;Each entry has key, enabled and variantKey, which is null for a flag without variants.
payload is always null: flag payloads are not delivered to browsers.
After an evaluation, read single flags synchronously:
const enabled = voidhash.isFeatureEnabled("new-pricing");
const variant = voidhash.getFeatureVariant("checkout-test")?.variantKey;A flag that is turned off, unknown or not evaluated yet reads as its default.
Defaults
A flag reads as its default until Voidhash has evaluated it: before the first answer, and when
Voidhash is unreachable and nothing is cached. Without a default it reads as false. Give a flag
whose feature must keep working during an outage the default true:
import { createVoidhashClient } from "@voidhash/web";
const voidhash = createVoidhashClient({
featureFlags: { defaults: { "new-checkout": true } },
publishableKey: "vh_pk_...",
});Defaults apply to isFeatureEnabled() and to isEnabled() from useFeatureFlags(). The flags
from getFeatureFlags() hold evaluated values only. isFeatureEnabledByDefault(key) returns a
flag's default.
In React
useFeatureFlags() evaluates the keys you pass and re-renders when their values change. It
compares keys by value, in any order:
import { useFeatureFlags } from "@voidhash/web/react";
const FLAG_KEYS = ["new-pricing", "checkout-test"];
export function Pricing() {
const { getVariant, isEnabled, isLoading } = useFeatureFlags(FLAG_KEYS);
if (isLoading) return null;
return (
<PricingTable
layout={isEnabled("new-pricing") ? "new" : "classic"}
checkoutVariant={getVariant("checkout-test")?.variantKey ?? undefined}
/>
);
}| Value | Purpose |
|---|---|
data.flags | Every evaluated entry. |
isEnabled(key) | Whether the flag is enabled; its default while unknown or loading. |
getVariant(key) | The flag's entry, or null while unknown or loading. |
isLoading | true until the first evaluation answers, at most maxWaitMs with nothing cached. |
isStale | true when values came from the cache without a successful refresh. |
isExpired | true when there are no evaluated values: before the first answer, or when Voidhash is unreachable and nothing is cached. |
error | Why the client failed to start or a refresh failed, or null. Network slowness does not set it. |
refetch() | Evaluates again from the network. |
Caching and refresh
Flags are read from the cache first, so a cached value never waits long for the network:
- Values older than
featureFlags.ttlMs, 5 minutes by default, are refreshed. A read waits at most 500 ms for the refresh, then answers from the cache withisStale: true. - With nothing cached, a read waits up to
featureFlags.maxWaitMs, 2 seconds by default, then resolves with no flags andisExpired: true. The evaluation continues in the background, and its answer is cached and announced with thefeature-flags-updatedevent. A read never rejects because of the network, so checkisExpiredto tell that you are seeing defaults. - The cache lives in
localStorageso the next page load starts with the last values.featureFlags: { persist: false }keeps it in memory. WithstoreBeforeConsent: false, flags stay in memory until consent is granted. - Flags refresh when the browser reconnects and when the tab becomes visible, at most once a minute.
identify(),signOut()andreset()evaluate flags again for the new person. After a sign-in, the anonymous visitor's values answer as stale until the user's arrive.signOut(),reset()and a switch between users clear the cache, so one person never sees another's assignment.
Feature flags work without analytics consent.
Website experiments
A flag with variants assigns each visitor a stable variant, which you can use for an A/B test on your website. The web SDK records no exposure event when a flag is read, so track your own event with the variant when the visitor sees it. A/B tests in Studio run through paywall locations in the mobile SDKs, not the web SDK.
Choose a safe default for every flag. Do not gate paid access with a flag; check access on your server instead.
Next steps
- Create and roll out flags in Studio
- Check access from your backend with Node.js, PHP, Go, Rust or over HTTP
- Track events
Something wrong or missing on this page? Tell us by email or on Discord.