---
title: Decide methods for the JavaScript SDK v6+
slug: feature-experimentation/docs/decide-methods-for-the-javascript-sdk
docTags: 
createdAt: 2026-08-05T20:39:52.000Z
---

Use the decide methods to return feature flag decisions for a user. Each decision includes whether the flag is enabled and which variation the user receives.

## Decide

Returns a decision for a specific feature flag and user.

**Minimum SDK version** – v6.0.0+

For versions 5.3.5 and below, see [JavaScript (Browser) SDK](docId\:EMuJXVhPmS6kJ_LmFDjWK) or [JavaScript (Node) SDK](docId\:wosThacvS32Gd5XY3_Zqg). See the [SDK compatibility matrix](docId\:zg27HhluF597DQiNtslCl) documentation for a list of current SDK releases and the features they support.

:::hint{type="info"}
Decide is a method of the `UserContext` object. See [OptimizelyUserContext](docId\:AxuIlxpiBQ0CfsBT2k_tx) for details.
:::

See the [OptimizelyDecision](docId:_Yl3A3irq3Y8SLn8f7i2o) for details of the returned decision object.

### Key features

- **Single experiment decision** – Returns the variation for a specific experiment.
- **Bucketing in results** – Ensures Feature Experimentation records the user in the experiment results page for proper analysis.
- **Complement to decide all method** – If you use the [decide all method](archbee-doc-SzZh7C_1dl_7tXmTs7bEq.mdx) to pre-fetch variations, you should also call the decide method for each experiment that the user interacts with. This dual approach guarantees that Feature Experimentation accurately tracks the user's participation and that the correct variation is served through caching.
- **CMAB support** – For CMAB experiments, decisions are automatically cached to reduce latency. The cache is invalidated when CMAB attributes change or TTL expires. Use CMAB-specific decide options (`IGNORE_CMAB_CACHE`, `INVALIDATE_USER_CMAB_CACHE`, and  `RESET_CMAB_CACHE`) to override default caching behavior. See the following CMAB cache control information.

### Parameters

The following table describes parameters for the decide method:

| Parameter            | Type   | Description                              |
| -------------------- | ------ | ---------------------------------------- |
| `flagKey`            | String | The key of the feature flag              |
| `options` (optional) | Array  | Array of `OptimizelyDecideOption` enums. |

### Returns

The decide method returns an [OptimizelyDecision](docId:_Yl3A3irq3Y8SLn8f7i2o) object.

If the method encounters a critical error (SDK not ready, invalid flag key, and so on), then it returns a decision with a `null` `variationKey` field and populates the `reasons` field with error messages (regardless of the `OptimizelyDecideOption.INCLUDE_REASONS` option).

### Example `decide`

The following is an example of calling the Decide method and accessing the returned OptimizelyDecision object:

```javascript
// create the user and decide which flag rule and variation they bucket into 
const attributes = {
  logged_in: true
};
const user = optimizely.createUserContext('user123', attributes);
const decision = user.decide('product_sort');

// The variation key. if null, decision failed with a critical error
const variationKey = decision['variationKey'];
if (variationKey === null) {
  console.log(' decision error: ', decision['reasons']);
}

// The flag enabled state.
const enabled = decision['enabled'];

// String variable value.
const value = decision.variables['sort_method'];

// All variable values.
const allVarValues = decision['variables'];

// Flag decision reasons.
const reasons = decision['reasons'];

// User for which the decision was made.
const userContext = decision['userContext'];
```

### Side effect

Invokes the [decision notification listener](docId\:wfUq0fCZCJ9jY1Fl1t5fx) if this listener is enabled.

## Decide (Async)

Similar to [decide](docId\:aD2SIJpA4SEjMECie93Tn), but executes asynchronously. If you are using a [user profile service](docId:3XRFFL7z9XAZ3e1EfpmjC) that implements `UserProfileServiceAsync` or if you are using Contextual Bandit rules, you must use the asynchronous version to retrieve the decision results.

**Minimum SDK version** – v6.0.0+

```javascript
import {
  createInstance,
  createPollingProjectConfigManager,
  createBatchEventProcessor,
  createOdpManager,
  createVuidManager,
  UserProfile,
  Client,
} from "@optimizely/optimizely-sdk";

const pollingConfigManager = createPollingProjectConfigManager({
  sdkKey: "YOUR_SDK_KEY", // Replace with your SDK key
});

const batchEventProcessor = createBatchEventProcessor();

const odpManager = createOdpManager();

const vuidManager = createVuidManager({
  enableVuid: true,
});

// Simulated async implementation of UserProfileServiceAsync using timeouts
export class InMemoryUserProfileServiceAsync {
  private store = new Map();

  async lookup(userId: string): Promise<UserProfile> {
    return new Promise((resolve) => {
      setTimeout(() => {
        const profile = this.store.get(userId);
        resolve(profile ?? { user_id: userId, experimentBucketMap: {} });
      }, 10); // simulate async delay
    });
  }

  async save(profile: UserProfile): Promise<void> {
    return new Promise((resolve) => {
      setTimeout(() => {
        this.store.set(profile.user_id, profile);
        resolve();
      }, 10); // simulate async delay
    });
  }
}

const optimizelyClient = createInstance({
  projectConfigManager: pollingConfigManager,
  eventProcessor: batchEventProcessor,
  odpManager: odpManager,
  vuidManager: vuidManager,
  userProfileServiceAsync: new InMemoryUserProfileServiceAsync(),
});

const getDecision = async (client: Client, userId: string, flagKey: string) => {
  try {
    await client.onReady();
    const user = client.createUserContext(userId);
    if (!user) {
      throw new Error("Failed to create user context");
    }
    try {
      const res = await user.decideAsync(flagKey);
      return res;
    } catch (err) {
      console.error("Error in decideAsync:", err);
    }
  } catch (err) {
    console.error("Error initializing client", err);
  }
};

if(optimizelyClient) {
  getDecision(optimizelyClient, "user123", "flag_key").then((decision) => {
    console.log("Decision:", decision);
  });
}
```

## Decide all

Returns decisions for all active (unarchived) flags for a user.

**Minimum SDK version** – v6.0.0+

For versions 5.3.5 and below, see [JavaScript (Browser) SDK](docId\:EMuJXVhPmS6kJ_LmFDjWK) or [JavaScript (Node) SDK](docId\:wosThacvS32Gd5XY3_Zqg). See the [SDK compatibility matrix](docId\:zg27HhluF597DQiNtslCl) documentation for a list of current SDK releases and the features they support.

### Description

Use the decide all method to retrieve decisions for all active flags before rendering content. This is particularly useful when you need to serve the correct cached version of your page or component based on the user's variation. For example when using an [edge worker](../../developer-docs/optimizely-edge-agent/introduction-to-optimizely-edge-agent/index.mdx) or [cloud function](../../developer-docs/optimizely-feature-experimentation-at-the-edge/get-started-edge-functions.mdx).

### Key features

- **Pre-rendering decision** – Lets you know all variation assignments ahead of time.
- **Cache control** – Lets you serve the correct cached content based on the user's pre-determined variations.
- **Delay experiment tracking** – Use `DISABLE_DECISION_EVENT` to prevent the SDK from recording a decision before the user sees the feature. This ensures that participation is only tracked when the experience is delivered.
- **CMAB support** – For CMAB experiments (SDK v5.2.0+), decisions are automatically cached to reduce latency. The cache is invalidated when CMAB attributes change or TTL expires. Use CMAB-specific decide options (`ignoreCmabCache`, `invalidateUserCmabCache`, `resetCmabCache`) to override default caching behavior. See [CMAB cache control](archbee-doc-SXro2YIwdH2k9jGnXKaLr.mdx).

### Parameters

The following table describes parameters for the decide all method:

| Parameter            | Type  | Description                                                            |
| -------------------- | ----- | ---------------------------------------------------------------------- |
| `options` (optional) | Array | Array of [OptimizelyDecideOption](docId\:aD2SIJpA4SEjMECie93Tn) enums. |

### Returns

Returns a map of [OptimizelyDecisions](docId:_Yl3A3irq3Y8SLn8f7i2o).

If the method fails for all flags (for example, the SDK is not ready or the user context is invalid), then it returns an empty map. If the method detects an error for a specific flag, it returns error messages in the `reasons` field of the decision for that flag.

### Example `decideAll`

```javascript
const attributes = {
  logged_in: true
};

const user = optimizely.createUserContext('user123', attributes);
// make decisions for all active (unarchived) flags in the project for a user
let decisions = user.decideAll();
// or only for enabled flags
decisions = user.decideAll([OptimizelyDecideOption.ENABLED_FLAGS_ONLY]);

const flagKeys = Object.keys(decisions);
const decisionForFlag1 = decisions['flag_1'];
```

### Side effects

Invokes the [decision notification listener](docId\:wfUq0fCZCJ9jY1Fl1t5fx) if this listener is enabled.

## Decide all (Async)

Similar to [Decide All](docId\:aD2SIJpA4SEjMECie93Tn), but executes asynchronously. If you are using a [user profile service](docId:3XRFFL7z9XAZ3e1EfpmjC) that implements `UserProfileServiceAsync` or if you are using `Contextual Bandit` rules, you must use the asynchronous version to retrieve the decision results.

```javascript
const getDecisions = async (client: Client, userId: string) => {
  try {
    await client.onReady();
    const user = client.createUserContext(userId);
    if (!user) {
      throw new Error("Failed to create user context");
    }
    try {
      const res = await user.decideAllAsync();
      return res;
    } catch (err) {
      console.error("Error in decideAllAsync", err);
    }
  } catch (err) {
    console.error("Error in client onReady", err);
  }
};
```

## Decide for keys

Returns a map of flag decisions for specified flag keys.

**Minimum SDK version** – v6.0.0+

For versions 5.3.5 and below, see [JavaScript (Browser) SDK](docId\:EMuJXVhPmS6kJ_LmFDjWK) or [JavaScript (Node) SDK](docId\:wosThacvS32Gd5XY3_Zqg). See the [SDK compatibility matrix](docId\:zg27HhluF597DQiNtslCl) documentation for a list of current SDK releases and the features they support.

### Parameters

The following table describes parameters for the decide For keys method:

| Parameter            | Type  | Description                                                            |
| -------------------- | ----- | ---------------------------------------------------------------------- |
| `keys`               | Array | Array of string flag keys.                                             |
| `options` (optional) | Array | Array of [OptimizelyDecideOption](docId\:aD2SIJpA4SEjMECie93Tn) enums. |

### Returns

Returns a map of `OptimizelyDecisions`. For information, see [OptimizelyDecision](docId:_Yl3A3irq3Y8SLn8f7i2o).

If the method fails for all flags (for example, the SDK is not ready or the user context is invalid), then it returns an empty map. If the method detects an error for a specific flag, it returns error messages in the `reasons` field of the decision for that flag.

### Example `decideForKeys`

```javascript
// make decisions for specific flags
const keys = ['flag_1', 'flag_2'];
const decisions = user.decideForKeys(keys);
const decision1 = decisions['flag_1'];
const decision2 = decisions['flag_2'];
```

### Side effects

Invokes the [decision notification listener](docId\:wfUq0fCZCJ9jY1Fl1t5fx) if this listener is enabled.

## Decide for keys (Async)

Similar to [Decide for keys](docId\:aD2SIJpA4SEjMECie93Tn), but executes asynchronously. If you are using a [user profile service](docId:3XRFFL7z9XAZ3e1EfpmjC) that implements `UserProfileServiceAsync` or if you are using `Contextual Bandit` rules, you must use the asynchronous version to retrieve the decision results.

```javascript
const getDecisions = async (client: Client, userId: string, keys: string[]) => {
  try {
    await client.onReady();
    const user = client.createUserContext(userId);
    if (!user) {
      throw new Error("Failed to create user context");
    }
    try {
      const res = await user.decideForKeysAsync(keys);
      return res;
    } catch (err) {
      console.error("Error in decideForKeysAsync", err);
    }
  } catch (err) {
    console.error("Error in client onReady", err);
  }
};
```

## `OptimizelyDecideOption`

The following table lists the `OptimizelyDecideOption` enum with an explanation what happens if you set them. In addition to setting these options individually for a decide method, you can also set them as global defaults when you instantiate the Optimizely client. See [Initialize JavaScript SDK](docId\:D3OtVcQbPLi14ePcRND31).

| `OptimizelyDecideOption`                             | If set                                                                                                                                                                                                                                                                                                    |
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `OptimizelyDecideOption.DISABLE_DECISION_EVENT`      | Prevents the SDK from dispatching an [impression](docId\:aRWQl1CvmQlxTciHZ4kJE) event when serving a variation. This disables decision tracking on the [Optimizely Experiment Results page](docId\:b_Ei_dvf1d-E1PCa3cC-n) and the [decision notification listener](docId\:wfUq0fCZCJ9jY1Fl1t5fx).         |
| `OptimizelyDecideOption.ENABLED_FLAGS_ONLY`          | Returns decisions only for flags that are currently enabled. Used with the [decide all method](docId\:aD2SIJpA4SEjMECie93Tn) and [decide for keys method](docId\:aD2SIJpA4SEjMECie93Tn). When this option is not set, the JavaScript SDK returns all decisions regardless of whether the flag is enabled. |
| `OptimizelyDecideOption.IGNORE_USER_PROFILE_SERVICE` | Bypasses the user profile service (both lookup and save) for the decision. When this option is not set, user profile service overrides audience targeting, traffic allocation, and experiment mutual exclusion groups.                                                                                    |
| `OptimizelyDecideOption.INCLUDE_REASONS`             | Adds log messages to the reasons field of the decision. Critical errors are always returned, even if this option is not set.                                                                                                                                                                              |
| `OptimizelyDecideOption.EXCLUDE_VARIABLES`           | Excludes flag variable values from the decision result. Use this option to minimize the returned decision by skipping large JSON variables.                                                                                                                                                               |
| `OptimizelyDecideOption.IGNORE_CMAB_CACHE`           | Ignore the cache while deciding CMAB experiments. CMAB is in beta. See the [Get decision for Contextual Bandits (CMABs)](docId\:aD2SIJpA4SEjMECie93Tn) section.                                                                                                                                           |
| `OptimizelyDecideOption.RESET_CMAB_CACHE`            | If the user is bucketed into a CMAB experiment, reset the whole CMAB cache before fetching a decision for the CMAB experiment. See the [Get decision for Contextual Bandits (CMABs)](docId\:aD2SIJpA4SEjMECie93Tn) section.                                                                               |
| `OptimizelyDecideOption.INVALIDATE_USER_CMAB_CACHE`  | If the user is bucketed into a CMAB experiment, invalidate the previously cached decision for the experiment and user combination. See the [Get decision for Contextual Bandits (CMABs)](docId\:aD2SIJpA4SEjMECie93Tn) section.                                                                           |

The following code sample shows how to implement the `OptimizelyDecideOption` as a global default and locally in a decide method call.

```javascript
import {
  createBatchEventProcessor,
  createInstance,
  createOdpManager,
  createPollingProjectConfigManager,
  OptimizelyDecideOption
} from "@optimizely/optimizely-sdk";

const SDK_KEY="YOUR_SDK_KEY";

const pollingConfigManager = createPollingProjectConfigManager({
  sdkKey: SDK_KEY,
  autoUpdate: true,
  updateInterval: 60000, // 1 minute
});

const batchEventProcessor = createBatchEventProcessor();
const odpManager = createOdpManager();

const optimizelyClient = createInstance({
  projectConfigManager: pollingConfigManager,
  eventProcessor: batchEventProcessor,
  odpManager: odpManager,
  defaultDecideOptions: [OptimizelyDecideOption.DISABLE_DECISION_EVENT]
});


optimizelyClient.onReady().then(() => {
  const user = optimizelyClient.createUserContext('user123');
  if (!user) {
    throw new Error('failed to create user context');
  }

  // set additional options in a decide call
  const decisionResults = user.decideAll(
    [
      OptimizelyDecideOption.ENABLED_FLAGS_ONLY,
      OptimizelyDecideOption.IGNORE_USER_PROFILE_SERVICE,
    ]
  );

  console.log(decisionResults);
}).catch((err) => {
  // handle error
});
```

## Best practices

- **Early and late invocation**
  - Use the decide all method early in your application's rendering process to load the correct cached content. For example, on the [CDN with an Edge SDK](../../developer-docs/optimizely-feature-experimentation-at-the-edge/content-delivery-networks.mdx).
  - Use the decide method at the point of user interaction or when you must ensure Feature Experimentation records the decision in your experiment analytics.
- **Combining methods** – When using the decide and decide all methods, always pair the decide all method with the decide method for each experiment the user encounters. This prevents discrepancies between served content and analytics data.
- **Parameter management** – Ensure you use the `DISABLE_DECISION_EVENT` option with the decide all method to avoid premature bucketing, then use the decide method to handle the decision event when the user experiences the content.

## Get decision for Contextual Bandits (CMABs)

You must use async decide methods (`decideAsync`, `decideForKeysAsync`, or `decideAllAsync`) to get decisions for CMAB rules. Synchronous decide methods skip CMAB rules. See [Configure the CMAB cache for the JavaScript SDK](docId\:kxPR-2paWRm962k7NNEjI) and [Initialize the JavaScript SDK v6+](docId\:D3OtVcQbPLi14ePcRND31) for details on CMAB decisions.

## Source files

The language and platform source files containing the implementation for JavaScript is available on [GitHub](https://github.com/optimizely/javascript-sdk/blob/master/lib/optimizely/index.ts).
