HomeGuidesAPI Reference
Submit Documentation FeedbackJoin Developer CommunityLog In

Javascript (Node)

Welcome to the quickstart guide for Optimizely's Full Stack JavaScript SDK. Follow the steps in this guide to create a feature flag, roll out a flag delivery, or run an A/B test.

Create an example app to use in the next steps.

  1. Get a free account
  2. Get your SDK key
  3. Copy the sample code

Roll out a feature flag to a percentage of user traffic.

  1. Create the feature flag
  2. Create the flag delivery rule
  3. Run your sample app
    How it works

Build an A/B test on a feature flag, and mock experiment results with an interactive command-line app.

  1. Add event tracking
  2. Pause other rules in free accounts
  3. Create the A/B test
  4. Add an event
  5. Run the A/B test
  6. See your A/B test results
  7. How it works

PART 1: Create a sample app

1. Get a free account

You need an account to follow this guide. If you do not have an account, you can register for a free account. If you already have an account navigate to your Flags-enabled project.

2. Get your SDK key

To find your SDK Key in your Optimizely project:

  1. Go to Settings > Primary Environment.
  2. Copy and save the SDK Key for your primary environment. Note: Each environment has its own SDK key.
Click image to enlargeClick image to enlarge

Click image to enlarge

3. Copy the sample code

To quickly try out the SDK:

  1. Install Optimizely. You have a couple of options:

Run without installing

Run locally

If you want to run in a demo environment, for example CodePen, without installing the SDK locally, use the following HTML script tag examples.

If you want to run using Node (best practice in production), then use the following NPM examples.

# From your project directory, run the terminal command below to install Optimizely Full Stack: 
npm install --save @optimizely/optimizely-sdk
# From your project directory, run the terminal command below to install Optimizely Full Stack: 
yarn add @optimizely/optimizely-sdk
<!-- create a blank project in CodePen or serve a blank index.html locally
and add the following content: -->

<html>
  <head>
    <!--install Optimizely-->
   <script src="https://unpkg.com/@optimizely/optimizely-sdk/dist/optimizely.browser.umd.min.js"></script>
  </head>
  <body>
  </body>
</html>
  1. From your project directory, create an empty text file called optimizely-js-quickstart.js.
  2. Copy the following code sample into the file you created in the previous step.
  3. Replace <Your_SDK_Key> with the SDK key you found in a previous step.
const optimizelySdk = require('@optimizely/optimizely-sdk');

const optimizelyClient = optimizelySdk.createInstance({
  sdkKey: '<YOUR_SDK_KEY>'
});

optimizelyClient.onReady().then(() => {
  console.log('***optimizelyClient is valid instance 2****', optimizelyClient.isValidInstance());
  if (!optimizelyClient.isValidInstance()) {
    console.log('Optimizely client invalid. Verify in Settings>Environments that you used the primary environment\'s SDK key');
    return;
  }
  let hasOnFlags = false;
  for (let i = 0; i < 10; i++) {
    // to get rapid demo results, generate random users. Each user always sees the same variation unless you reconfigure the flag rule.
    let userId = (Math.floor(Math.random() * (10000 - 1000) + 1000)).toString();

    // Create hardcoded user & bucket user into a flag variation
    let user = optimizelyClient.createUserContext(userId);

    // "product_sort" corresponds to a flag key in your Optimizely project
    let decision = user.decide('product_sort');
    let variationKey = decision.variationKey;

    // did decision fail with a critical error?
    if (variationKey === null) {
      console.log(' decision error: ', decision['reasons']);
    }

    let sortMethod = decision.variables['sort_method'];

    // get a dynamic configuration variable
    // "sort_method" corresponds to a variable key in your Optimizely project
    if (decision.enabled) {
      hasOnFlags = true;
    }

    // Mock what the users sees with print statements (in production, use flag variables to implement feature configuration)
    // always returns false until you enable a flag rule in your Optimizely project
    console.log(`\nFlag ${decision.enabled ? 'on' : 'off'}. User number ${user.getUserId()} saw flag variation: ${variationKey} and got products sorted by: ${sortMethod} config variable as part of flag rule: ${decision.ruleKey}`);
  }

  if (!hasOnFlags) {
    console.log("\n\nFlag was off for everyone. Some reasons could include:" +
      "\n1. Your sample size of visitors was too small. Rerun, or increase the iterations in the FOR loop" +
      "\n2. By default you have 2 keys for 2 project environments (dev/prod). Verify in Settings>Environments that you used the right key for the environment where your flag is toggled to ON." +
      "\nCheck your key at https://app.optimizely.com/v2/projects/" + optimizelyClient.projectConfigManager.getConfig().projectId + "/settings/implementation");
  };
});
<!DOCTYPE html>
<html>

<head>
  <title>Quickstart Guide</title>
  <script src="https://unpkg.com/@optimizely/optimizely-sdk/dist/optimizely.browser.umd.min.js"></script>
</head>

<body>
  <pre>Welcome to our Quickstart Guide!</pre>
  <pre id="errors"></pre>
  <pre id="experiences"></pre>
  <pre id="result"></pre>
  <script>
    var optimizelyClient = window.optimizelySdk.createInstance({
      sdkKey: '<YOUR_SDK_KEY>'
    });

    optimizelyClient.onReady().then(() => {
      var errors = document.getElementById('errors');
      if (!optimizelyClient.isValidInstance()) {
        errors.innerText = 'Optimizely client invalid. Verify in Settings>Environments that you used the primary environment\'s SDK key';

        return;
      }

      var experiences = document.getElementById('experiences');
      let hasOnFlags = false;
      for (let i = 0; i < 10; i++) {
        // to get rapid demo results, generate random users. Each user always sees the same variation unless you reconfigure the flag rule.
        let userId = (Math.floor(Math.random() * (10000 - 1000) + 1000)).toString();

        // Create hardcoded user & bucket user into a flag variation
        let user = optimizelyClient.createUserContext(userId);

        // "product_sort" corresponds to a flag key in your Optimizely project
        let decision = user.decide('product_sort');
        let variationKey = decision.variationKey;

        // did decision fail with a critical error?
        if (variationKey === null) {
          errors.innerText += `\n\ndecision error: ${decision['reasons']}`;
        }

        // get a dynamic configuration variable
        // "sort_method" corresponds to a variable key in your Optimizely project
        var sortMethod = decision.variables['sort_method'];

        if (decision.enabled) {
          hasOnFlags = true;
        }

        // Mock what the users sees with print statements (in production, use flag variables to implement feature configuration)
        // always returns false until you enable a flag rule in your Optimizely project
        experiences.innerText += `\n\nFlag ${decision.enabled ? 'on' : 'off'}. User number ${user.getUserId()} saw flag variation: ${variationKey} and got products sorted by: ${sortMethod} config variable as part of flag rule: ${decision.ruleKey}`;
      }

      var result = document.getElementById('result');
      if (!hasOnFlags) {
        result.innerText = "\n\nFlag was off for everyone. Some reasons could include:" +
          "\n1. Your sample size of visitors was too small. Rerun, or increase the iterations in the FOR loop" +
          "\n2. By default you have 2 keys for 2 project environments (dev/prod). Verify in Settings>Environments that you used the right key for the environment where your flag is toggled to ON." +
          "\n\nCheck your key at https://app.optimizely.com/v2/projects/" + optimizelyClient.projectConfigManager.getConfig().projectId + "/settings/implementation";
      };
    });
  </script>
</body>

</html>

Note: Do not run your app yet, because you still need to set up the flag in the Optimizely app.

PART 2: Run your app

After completing PART 1, your app does nothing. You need to create a flag and a flag rule in the Optimizely app to enable the app.

1. Create the feature flag

A feature flag lets you control the users that are exposed to a new feature code in your app. For this quickstart, imagine that you are rolling out a redesigned sorting feature for displaying products.
Create a flag in Optimizely named product_sort and give it a variable named sort_method:

  1. Go to Flags > Create Flag.
  2. Name the flag key product_sort and click Create Flag, which corresponds to the flag key in your sample app.
  3. Go to Default Variables and click New (+).
  4. Set the variable type to "String".
  5. Name the variable sort_method, which corresponds to the variable key in your sample app.
  6. Set the variable default value to alphabetical, which represents your old sorting method.
create variablecreate variable

create variable

  1. Click Save at the lower right corner to save the variable.
  2. Go to Variations and click the default "on" variation. A variation is a wrapper for a collection of variable values.
  3. Set the sort_method variable value to popular_first, which represents your new sorting method.
create variationcreate variation

create variation

  1. Click Save.

2. Create the flag delivery rule

Your sample app still does not do anything because you need to make and enable a flag rule in the app.

Make a targeted delivery rule for the "on" variation for the product_sort flag. A targeted delivery lets you gradually release a feature flag to users, but with the flexibility to roll it back if you encounter bugs.

  1. Verify that you are in your primary environment (since you are using the primary environment SDK key):
verify the environment in which you make the ruleverify the environment in which you make the rule

verify the environment in which you make the rule

  1. Click Add Rule and select Targeted Delivery.
  2. Set the traffic slider to 50%. This delivers the flag to 50% of everyone who triggers the flag in this environment. You can roll out or roll back the product_sort flag to a percentage of traffic whenever you want.
  3. From the Deliver drop-down, select On.
  4. Click Save.
configure a targeted deliveryconfigure a targeted delivery

configure a targeted delivery

  1. Enable the flag for your flag rule:

3. Run your sample app

In terminal, run your js file: node optimizely-js-quickstart.js. Output appears similar to the following:

Flag on. User number 6998 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: targeted_delivery

Flag on. User number 1177 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: targeted_delivery

Flag on. User number 9714 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: targeted_delivery

Flag on. User number 4140 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: targeted_delivery

Flag on. User number 4994 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: targeted_delivery

Flag off. User number 8700 saw flag variation: off and got products sorted by: alphabetical config variable as part of flag rule: default-rollout-208-19963693913

Flag off. User number 9912 saw flag variation: off and got products sorted by: alphabetical config variable as part of flag rule: default-rollout-208-19963693913

Flag on. User number 6560 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: targeted_delivery

Flag on. User number 9252 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: targeted_delivery

Flag on. User number 6582 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: targeted_delivery

Note: You will not get exactly 50% of your user traffic in the "on" variation, since you are working with such small numbers of visitors. Also, the users who got an 'off' flag did not make it into the 50% traffic you set, so they fell through to the default "Off" rule (default-rollout in the preceding print statements):

4. How it works

So far, you:

  • Created a flag, flag variable, and a flag variation (wrapper for your variables) in the Optimizely app
  • Implemented a flag in your app with the Decide method

What is going on in your sample app?

How it works: decide to show a user a flag

The SDK’s Decide method determines whether to show or hide the feature flag for a specific user.

Note: You can reuse this method for different flag rules -- whether for delivering to more traffic, or running an experiment to show different sorting methods to just a portion of users.

After you learn which sorting method works best to increase sales, roll out the product sort flag to all traffic with the method set to the optimum value. 😀
In your sample app:

var user = optimizelyClient.createUserContext(userID);
// "product_sort" corresponds to the flag key you create in the Optimizely app
var decision = user.decide('product_sort');

Note: Optionally include attributes when you create your user (not shown in your sample app), so that you can target specific audiences. For example:

var attributes = { logged_in: true };
var user = optimizely.createUserContext('user123', attributes);

How it works: configure flag variations

You can dynamically configure a flag variation using flag variables. In your sample app:

// always returns false until you enable a flag rule in the Optimizely app
if (decision.enabled) 
{
  // "sort_method" corresponds to variable key you define in Optimizely app
 var sortMethod = decision.variables['sort_method'];
 console.log('sort_method: ', sortMethod);
}

For your product_sort flag, you can configure variations with different sort_method values, sorting by popular products, relevant products, promoted products, and so on. You can set different values for the sort method at any time in the Optimizely app.

PART 3: Run an A/B test

This tutorial just guided you through a targeted delivery because it is the simplest flag rule. However, you often want to A/B test how users react to feature flag variations before you roll out a feature flag delivery.

The following table shows the difference between flag deliveries and A/B tests:

Targeted delivery rule

A/B test rule

You can roll out your flag to a percentage of your general user base (or to specific audiences), or roll back if you hit bugs.

Experiment by A/B testing a flag before you invest in delivering, so you know what to build. Track how users behave in flag variations, then interpret your experiment results using the Optimizely Stats Engine.

Now A/B test the "on" variation of your product_sort flag!

1. Add event tracking

You need to add a Track Event method to your sample app , so you can mock-up user events and then see metrics.

  1. Delete your old sample code, and paste in the following code.
  2. Remember to replace your SDK key again.
  3. Do not run your app yet because you still need to set up the A/B test in the Optimizely app.
const optimizelySdk = require('@optimizely/optimizely-sdk');
const readline = require("readline");

// For more instantiation configuration, see the Javascript SDK reference 
const optimizelyClient = optimizelySdk.createInstance({
  sdkKey: '<YOUR_SDK_KEY>'
});

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

optimizelyClient.onReady().then(() => {
  if (!optimizelyClient.isValidInstance()) {
    console.log('Optimizely client invalid. Verify in Settings>Environments that you used the primary environment\'s SDK key');
    return;
  }
  runExperiment();

  // mock tracking a user event so you can see some experiment reports
  function mockPurchase(user) {
    return new Promise(function (resolve) {
      rl.question('Pretend that user ' + user.getUserId() + ' made a purchase? y/n\n', function(answer) {
        // track a user event you defined in the Optimizely app
        if (answer === 'y') {
          user.trackEvent('purchase');
          console.log("Optimizely recorded a purchase in experiment results for user " + user.getUserId());
        } else {
          console.log("Optimizely didn't record a purchase in experiment results for user " + user.getUserId());
        }
        resolve(answer);
      });
    });
  };

  async function runExperiment() {
    let hasOnFlags = false;
    for (let i = 0; i < 4; i++) {
      // to get rapid demo results, generate random users. Each user always sees the same variation unless you reconfigure the flag rule.
      let userId = (Math.floor(Math.random() * (10000 - 1000) + 1000)).toString();

      // Create hardcoded user & bucket user into a flag variation
      let user = optimizelyClient.createUserContext(userId);

      // "product_sort" corresponds to a flag key in your Optimizely project
      let decision = user.decide('product_sort');
      let variationKey = decision.variationKey;

      // did decision fail with a critical error?
      if (variationKey === null) {
        console.log(' decision error: ', decision['reasons']);
      }
      // get a dynamic configuration variable
      // "sort_method" corresponds to a variable key in your Optimizely project
      let sortMethod = decision.variables['sort_method'];
      if (decision.enabled) {
        hasOnFlags = true;
      }

      // Mock what the users sees with print statements (in production, use flag variables to implement feature configuration)
      // always returns false until you enable a flag rule in your Optimizely project
      console.log(`\n\nFlag ${decision.enabled ? 'on' : 'off'}. User number ${user.getUserId()} saw flag variation: ${variationKey} and got products sorted by: ${sortMethod} config variable as part of flag rule: ${decision.ruleKey}`);
      await mockPurchase(user);
    }

    if (!hasOnFlags) {
      console.log("\n\nFlag was off for everyone. Some reasons could include:" +
        "\n1. Your sample size of visitors was too small. Rerun, or increase the iterations in the FOR loop" +
        "\n2. By default you have 2 keys for 2 project environments (dev/prod). Verify in Settings>Environments that you used the right key for the environment where your flag is toggled to ON." +
        "\nCheck your key at https://app.optimizely.com/v2/projects/" + optimizelyClient.projectConfigManager.getConfig().projectId + "/settings/implementation");
    } else {
      console.log("\n\nDone with your mocked A/B test. " +
        "\nCheck out your report at https://app.optimizely.com/v2/projects/" + optimizelyClient.projectConfigManager.getConfig().projectId + "/reports" +
        "\nBe sure to select the environment that corresponds to your SDK key");
    }
  }
});
<!DOCTYPE html>
<html>

<head>
  <title>Quickstart Guide</title>
  <script src="https://unpkg.com/@optimizely/optimizely-sdk/dist/optimizely.browser.umd.min.js"></script>
</head>

<body>
  <pre>Welcome to our Quickstart Guide!</pre>
  <pre id="errors"></pre>
  <pre id="experiences"></pre>
  <pre id="result"></pre>
  <script>
    // For more instantiation configuration, see the Javascript SDK reference 
    var optimizelyClient = window.optimizelySdk.createInstance({
      sdkKey: '<YOUR_SDK_KEY>'
    });
    optimizelyClient.onReady().then(() => {
      var errors = document.getElementById('errors');
      if (!optimizelyClient.isValidInstance()) {
        errors.innerText = 'Optimizely client invalid. Verify in Settings>Environments that you used the primary environment\'s SDK key';
        return;
      }
      var experiences = document.getElementById('experiences');
      let hasOnFlags = false;
      for (let i = 0; i < 4; i++) {
        // to get rapid demo results, generate random users. Each user always sees the same variation unless you reconfigure the flag rule.
        let userId = (Math.floor(Math.random() * (10000 - 1000) + 1000)).toString();

        // Create hardcoded user & bucket user into a flag variation
        let user = optimizelyClient.createUserContext(userId);

        // "product_sort" corresponds to a flag key in your Optimizely project
        let decision = user.decide('product_sort');
        let variationKey = decision.variationKey;

        // did decision fail with a critical error?
        if (variationKey === null) {
          errors.innerText += `\n\ndecision error: ${decision['reasons']}`;
        }
        // get a dynamic configuration variable
        // "sort_method" corresponds to a variable key in your Optimizely project
        let sortMethod = decision.variables['sort_method'];
        if (decision.enabled) {
          hasOnFlags = true;
        }

        // Mock what the users sees with print statements (in production, use flag variables to implement feature configuration)
        // always returns false until you enable a flag rule in your Optimizely project
        experiences.innerText += `\n\n\nFlag ${decision.enabled ? 'on' : 'off'}. User number ${user.getUserId()} saw flag variation: ${variationKey} and got products sorted by: ${sortMethod} config variable as part of flag rule: ${decision.ruleKey}`;
        mockPurchase(user, experiences);
      }

      // mock tracking a user event so you can see some experiment reports
      function mockPurchase(user, experiences) {
        var question = '\nPretend that user ' + user.getUserId() + ' made a purchase? y/n';
        experiences.innerText += question;
        var answer = prompt(question);
        experiences.innerText += ("\n" + answer);
        // track a user event you defined in the Optimizely app
        if (answer == 'y') {
          user.trackEvent('purchase');
          experiences.innerText += ("\nOptimizely recorded a purchase in experiment results for user " + user.getUserId());
        }
        else {
          experiences.innerText += ("\nOptimizely didn't record a purchase in experiment results for user " + user.getUserId());
        }
      }

      var result = document.getElementById('result');
      if (!hasOnFlags) {
        result.innerText = "\nFlag was off for everyone. Some reasons could include:" +
          "\n1. Your sample size of visitors was too small. Rerun, or increase the iterations in the FOR loop" +
          "\n2. By default you have 2 keys for 2 project environments (dev/prod). Verify in Settings>Environments that you used the right key for the environment where your flag is toggled to ON." +
          "\n\nCheck your key at https://app.optimizely.com/v2/projects/" + optimizelyClient.projectConfigManager.getConfig().projectId + "/settings/implementation";
      } else {
        result.innerText = "\nDone with your mocked A/B test. " +
          "\nCheck out your report at https://app.optimizely.com/v2/projects/" + optimizelyClient.projectConfigManager.getConfig().projectId + "/reports" +
          "\nBe sure to select the environment that corresponds to your SDK key"
      }
    });
  </script>
</body>

</html>

2. Pause other rules in free accounts

If you have a free account, you need to pause the Targeted Delivery you created earlier in this quickstart before you save your A/B test:

3. Create the A/B test

To create and launch an experiment in your Optimizely project:

  1. Go to Rules for your flag.
  2. Click Add Rule > A/B Test.
create new A/B testcreate new A/B test

create new A/B test

4. Add an event

In an experiment, you will track users' relevant actions to measure how users react to your feature flag variations. You need to define the actions you want to track:

  1. Click on the Metrics field.
  2. Click "Create new event".
Click image to enlargeClick image to enlarge

Click image to enlarge

  1. For the Event Key, enter purchase and click Create Event. (You want to know whether the new sorting flag helps customers figure out what to buy, so track whether the user makes a purchase after they were shown the products in a new order.)
  1. Leave the defaults (measure Increase in unique conversions).
Click image to enlargeClick image to enlarge

Click image to enlarge

  1. Click Add Metric.
  2. Leave the default "Off" variation as a control. Select the "On" variation you configured in a previous step:
  1. Click Save.

Note: You are not limited to two variations; you can also create A/B/ tests with multiple variations. For example:

A/B test with multiple variationsA/B test with multiple variations

A/B test with multiple variations

Double check your flag to ensure that it is on so your experiment can run:

Click image to enlargeClick image to enlarge

Click image to enlarge

5. Run the A/B test

In terminal, run your js file: node <filename.js>. Output appears similar to the following:

Flag on. User number 1496 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: experiment_1
Pretend that user 1496 made a purchase? y/n
n
Optimizely didn't record a purchase in experiment results for user 1496


Flag off. User number 1194 saw flag variation: off and got products sorted by: alphabetical config variable as part of flag rule: experiment_1
Pretend that user 1194 made a purchase? y/n
y
Optimizely recorded a purchase in experiment results for user 1194


Flag off. User number 5815 saw flag variation: off and got products sorted by: alphabetical config variable as part of flag rule: experiment_1
Pretend that user 5815 made a purchase? y/n
y
Optimizely recorded a purchase in experiment results for user 5815


Flag on. User number 1248 saw flag variation: on and got products sorted by: popular_first config variable as part of flag rule: experiment_1
Pretend that user 1248 made a purchase? y/n
y
Optimizely recorded a purchase in experiment results for user 1248


Flag off. User number 9580 saw flag variation: off and got products sorted by: alphabetical config variable as part of flag rule: experiment_1
Pretend that user 9580 made a purchase? y/n
n
Optimizely didn't record a purchase in experiment results for user 9580


Done with your mocked A/B test.
Check out your report at https://app.optimizely.com/v2/projects/19957465438/reports
Be sure to select the environment that corresponds to your SDK key

6. See your A/B test results

Go to the Reports tab to see your experiment results.

Results look something like the following:

Notes:

  • You might not see the exact user traffic percentages you configured for your flag variations until you have larger numbers of users.
  • You might not see your user traffic immediately. Refresh the browser to refresh traffic.
  • Your experiment results will not tell you a winning variation until you have a large number of visitors, (on the order of 100,000).

7. How it works

For an A/B test, you need a way to tell Optimizely when a user made a purchase in your app and map this event in your app code to the specific event you created in Optimizely. Luckily the SDK has a method for that! Use the Track Event method and pass in the key for the event you created (purchase). In your sample app:

// Track how users behave when they see a flag variation
// e.g., after your app processed a purchase, let Optimizely know what happened:
user.trackEvent('purchased');

Note: Optionally add tags to your event to enrich it (not shown in your sample app). You can also use reserve tag keys like revenue to track quantitative results. For example:

var tags = {
  category: 'shoes',
  revenue: 6432,
};

user.trackEvent('purchase', tags);

Event tracking is currently supported only for experiment rules, not delivery rules. Tracking for deliveries will be supported in a future release.

Either way, you should include event tracking when you implement a flag because it can help you integrate with a third-party analytics platform, and it gives you flexibility when you create A/B tests.

Congratulations! You successfully set up and launched your first Optimizely Full Stack experiment. While this example focused on optimizing sales, Optimizely’s experimentation platform can support an open-ended set of experimentation use cases.

See our documentation to learn more ways to optimize your software using experimentation.


Did this page help you?