Skip to main content

JavaScript

tip

If you're using React, consider using our React Client instead, which also provides full TypeScript support.

Install the latest version

Use your favorite package manager to install @reforge-com/javascript npm | github

npm install @reforge-com/javascript

Initialize the client

Initialize reforge with your SDK key:

import { reforge, Context } from "@reforge-com/javascript";

const options = {
sdkKey: "YOUR_SDK_KEY",
context: new Context({
user: {
email: "test@example.com",
},
device: { mobile: true },
}),
};

await reforge.init(options);

reforge.init will request the calculated feature flags for the provided context as a single HTTPS request. If you need to check for updates to feature flag values, you can learn more about polling below.

You aren't required to await the init -- it is a promise, so you can use .then, .finally, .catch, etc. instead if you prefer.

tip

While reforge is loading, isEnabled will return false, get will return undefined, and shouldLog will use your defaultLevel.

Feature Flags

Now you can use reforge's feature flag evaluation, e.g.

if (reforge.isEnabled("cool-feature")) {
// ... this code only evaluates if `cool-feature` is enabled for the current context
}

You can also use:

  • get to access the value of non-boolean flags

    const stringValue = reforge.get("my-string-flag");
  • getDuration for time-specific values

    const timeout = reforge.getDuration("api-timeout");
    if (timeout) {
    console.log(`Timeout: ${timeout.seconds}s (${timeout.ms}ms)`);
    }

Context

Context accepts an object with keys that are context names and key value pairs with attributes describing the context. You can use this to write targeting rules, e.g. segment your users.

import { reforge, Context } from "@reforge-com/javascript";

const options = {
sdkKey: "REFORGE_FRONTEND_SDK_KEY",
context: new Context({
user: { key: "abcdef", email: "test@example.com" },
device: { key: "hijklm", mobile: true },
}),
};

await reforge.init(options);

poll()

After reforge.init(), you can start polling. Polling uses the context you defined in init by default. You can update the context for future polling by setting it on the reforge object.

// some time after init
reforge.poll({ frequencyInMs: 300000 });

// we're now polling with the context used from `init`

// later, perhaps after a visitor logs in and now you have the context of
// their current user
reforge.updateContext({
...reforge.context,
user: { email: user.email, key: user.trackingId },
});

// updateContext will immediately load the newest from Reforge based on the
// new context. Future polling will use the new context as well.

Dynamic Config

Config values are accessed the same way as feature flag values. You can use isEnabled as a convenience for boolean values, and get works for all data types.

By default configs are not sent to client SDKs. You must enable access for each individual config. You can do this by checking the "Send to client SDKs" checkbox when creating or editing a config.

Tracking Experiment Exposures

If you're using Reforge Launch for A/B testing, you can supply code for tracking experiment exposures to your data warehouse or analytics tool of choice.

import { reforge, Context } from "@reforge-com/javascript";

const options = {
sdkKey: "REFORGE_FRONTEND_SDK_KEY",
context: new Context({
user: { key: "abcdef", email: "test@example.com" },
device: { key: "hijklm", mobile: true },
}),
afterEvaluationCallback: (key, value) => {
// call your analytics tool here...in this example we are sending data to posthog
window.posthog?.capture("Feature Flag Evaluation", {
key,
value,
});
},
};

await reforge.init(options);

afterEvaluationCallback will be called each time you evaluate a feature flag or config using get or isEnabled.

Telemetry

By default, Reforge will collect summary counts of config and feature flag evaluations to help you understand how your configs and flags are being used in the real world. You can opt out of this behavior by passing collectEvaluationSummaries: false in the options to reforge.init.

Reforge also stores the context that you pass in. The context keys are used to power autocomplete in the rule editor, and the individual values power the Contexts page for troubleshooting targeting rules and individual flag overrides. If you want to change what Reforge stores, you can pass a different value for collectContextMode.

collectContextMode valueBehavior
PERIODIC_EXAMPLEStores context values and context keys. This is the default.
SHAPE_ONLYStores context keys only.
NONEStores nothing. Context will only be used for rule evaluation.

Testing

In your test suite, you should skip reforge.init altogether and instead use reforge.hydrate to set up your test state.

it("shows the turbo button when the feature is enabled", () => {
reforge.hydrate({
turbo: true,
defaultMediaCount: 3,
});

const rendered = new MyComponent().render();

expect(rendered).toMatch(/Enable Turbo/);
expect(rendered).toMatch(/Media Count: 3/);
});

Reference

reforge Properties

propertyexamplepurpose
contextreforge.contextget the current context (after init()).
extractreforge.extract()returns the current config as a plain object of key, config value pairs
getDurationreforge.getDuration("timeout-key")returns a Duration object with seconds and ms properties for duration configs
getreforge.get('retry-count')returns the value of a flag or config evaluated in the current context
hydratereforge.hydrate(configurationObject)sets the current config based on a plain object of key, config value pairs
isEnabledreforge.isEnabled("new-logo")returns a boolean (default false) if a feature is enabled based on the current context
loadedif (reforge.loaded) { ... }a boolean indicating whether reforge content has loaded
pollreforge.poll({frequencyInMs})starts polling every frequencyInMs ms.
shouldLogif (reforge.shouldLog(...)) {returns a boolean indicating whether the proposed log level is valid for the current context
stopPollingreforge.stopPolling()stops the polling process
stopTelemetryreforge.stopTelemetry()stops telemetry collection and clears aggregators
updateContextreforge.updateContext(newContext)update the context and refetch. Pass false as a second argument to skip refetching