> ## Documentation Index
> Fetch the complete documentation index at: https://confidence.spotify.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Add a Feature Flag

> Create a feature flag, define its schema and variants, and add targeting rules to control who sees what.

By the end of this guide, you have a `header-redesign` flag with two variants, a rule that serves a variant to a test user, and code that resolves the flag.

The guide has these steps:

1. [Create a client](#create-a-client) for the website so that it can resolve
   flags.
2. [Create a flag](#create-a-flag) for the header design, and define its schema.
3. [Create variants](#create-variants) of the header.
4. [Use the flag](#use-the-flag) in the website to control the header.
5. [Force a variant for a user](#force-a-variant-for-a-user) to test a specific
   variant.
6. [Test resolving the flag](#test-flag-resolution) with an evaluation context.

Each step shows how to do it with AI first, then in the Confidence app.

<Tip>
  **Do it with AI.** Connect the [Confidence MCP servers](/docs/guides/build-with-an-ai-assistant) to your AI assistant, then run the whole guide with one prompt:

  ```text theme={null}
  Create a client called "Web client" if it doesn't exist. Create a flag called
  "header-redesign" on that client with a string property "color" and an integer
  property "size". Add a variant "default-style" (color "black", size 14) and a
  variant "new-style" (color "blue", size 16). Add an individual targeting rule
  that serves "new-style" to user_id "user-test-id", then test resolving the flag
  for that user.
  ```
</Tip>

## Before You Begin

* You need a [Confidence](https://app.confidence.spotify.com) account.
* For the AI path, [set up Confidence for your AI assistant](/docs/guides/build-with-an-ai-assistant). The Flags MCP server creates clients, flags, variants, and rules. The Docs MCP server returns SDK code snippets.

This video gives a quick overview of how feature flags work in 2 minutes and 10 seconds.

<iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/E_-U0ryfDPI?si=NeRX9vVIWtxDH62y" title="How feature flags work in Confidence" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

<Tip>
  Use this guide to set up a flag that you resolve, but without changing anything in your
  code. This way, you can use the traffic the flag receives to set up and run A/B tests or rollouts
  using the [A/B test quickstart](/docs/guides/run-an-ab-test) or the [rollout quickstart](/docs/guides/roll-out-a-change). Since the resolved flag value
  isn't used in your code, nothing changes for your users.
</Tip>

## Choose a Resolution Method That Fits Your Application

You can resolve a Confidence feature flag in two ways: by using
Confidence's managed resolver or hosting your own self-hosted resolver. Read
more about the resolution options in [the documentation](/docs/capabilities/flags/data-transfer).

## Create a Client

You must associate all feature flags with at least one [client](/docs/reference/sdks/overview). A
client can, for example, be a backend service or a website. Clients use
flags to deliver different user experiences. To resolve flags, a client must
authenticate with Confidence using client credentials.

<Note>
  Confidence includes a default client that has the same name as your Confidence account. You can use this client, or create a more specific one for web feature flags in this quickstart.
</Note>

<Tabs>
  <Tab title="With AI">
    ```text theme={null}
    Create a client called "Web client" if it doesn't exist, and give me its client secret.
    ```

    The assistant uses the Flags MCP tools `listClients`, `createClient`, and `getClientSecret`.
  </Tab>

  <Tab title="In the App">
    <Steps>
      <Step title="Go to the Clients page">
        You can find it under the **Admin** section in the sidebar in Confidence.
      </Step>

      <Step title="Click Create and name the client">
        Name the client `Web client` (unless it already exists).
      </Step>

      <Step title="Click Create credential" />
    </Steps>
  </Tab>
</Tabs>

You have now created a web client, and created the associated client
credentials. These credentials are later used to resolve the flag.

## Create a Flag

Flags let Confidence control the behavior of your application.
For example, use a flag to control which machine learning model serves a recommendation, the number
and size of tiles on a page, or a call to action message and its position on a sign-up page.
For this tutorial, create a flag that controls the color and size of a header.

The flag value has a **schema**. The value of a flag isn't a single value, but a key-value map of properties. To avoid errors and make flags
easier to work with, Confidence requires you to define a schema for
the flag value. The schema describes the shape of the flag value by defining
properties and their data types.

In this guide, your flag controls the design of a header on a website.
The design consists of color and size, so your flag needs two properties: `color` and `size`.

<Tabs>
  <Tab title="With AI">
    ```text theme={null}
    Create a flag called "header-redesign" on "Web client" with a string
    property "color" and an integer property "size".
    ```

    The assistant uses the Flags MCP tool `createFlag`, which sets the client and schema in one call.
  </Tab>

  <Tab title="In the App">
    <Steps>
      <Step title="Go to Confidence">
        Select **Flags** on the left sidebar.
      </Step>

      <Step title="Click + Create to create a new flag" />

      <Step title="Name the flag header-redesign" />

      <Step title="Select Web client in the clients dialog">
        Or select the client with the same name as your account.
      </Step>

      <Step title="Choose the flag type">
        Select **JSON**, because this flag has more than one property. A **Boolean** flag only turns a feature on or off.
      </Step>

      <Step title="Define the properties">
        For each property, enter a name and select a type. Add `color` with type **String** and `size` with type **Integer**.
      </Step>
    </Steps>

    You can add properties to an existing flag after you create it. Open the schema on the right sidebar to edit it.
  </Tab>
</Tabs>

When you create the flag, you associate the flag with a specific client. This means
only **that client** can resolve the `header-redesign` flag. Limiting which flags are available to which
clients is valuable for several reasons. For example, it prevents exposing flags to clients that run in
uncontrolled environments such as mobile apps or server-side web apps. It also saves resources when resolving flags
in batch (for example, at app start) by restricting resolution to only the relevant flags.

Now that you defined the schema, you can create variants that have specific
values for the `color` and `size` properties.

## Create Variants

The two variants for the header redesign are black with size
14, and blue with size 16.

<Tabs>
  <Tab title="With AI">
    ```text theme={null}
    Add a variant "default-style" to header-redesign with color "black" and
    size 14, and a variant "new-style" with color "blue" and size 16.
    ```

    The assistant uses the Flags MCP tool `addFlagVariant`.
  </Tab>

  <Tab title="In the App">
    <Steps>
      <Step title="Click + Create variant and name it default-style" />

      <Step title="Enter values for the default style">
        Enter `black` as the value for `color`, and `14` as the value for `size`.
      </Step>

      <Step title="Click Save" />

      <Step title="Click + Create variant and name it new-style" />

      <Step title="Enter values for the new style">
        Enter `blue` as the value for `color`, and `16` as the value for `size`.
      </Step>
    </Steps>
  </Tab>
</Tabs>

The two variants are now created, but they're not yet reaching any user.
To test your flag, use an individual targeting rule next.

## Use the Flag

When resolving a flag into a value, you specify a default value. This default value applies if a user doesn't match or
isn't assigned by a rule. The following sections show how to integrate the Confidence SDKs and set the default value for the `header-redesign` flag to `color` green and `size` 10.

To have your AI assistant write the integration code for your stack, ask it:

```text theme={null}
Show me how to resolve the header-redesign flag with the Confidence SDK in my
project, with defaults color "green" and size 10.
```

The assistant uses the Docs MCP tool `getCodeSnippetAndSdkIntegrationTips`. To write the code yourself, follow the next sections.

### Install Dependencies

You first need to install the necessary dependencies.

<CodeGroup>
  ```bash JavaScript (Web) theme={null}
  yarn add @openfeature/web-sdk @spotify-confidence/openfeature-web-provider
  ```

  ```bash JavaScript (Server) theme={null}
  yarn add @openfeature/server-sdk @spotify-confidence/openfeature-server-provider-local
  ```

  ```xml Java theme={null}
  <!-- Add to pom.xml -->
  <dependency>
      <groupId>com.spotify.confidence</groupId>
      <artifactId>openfeature-provider-local</artifactId>
      <version>latest</version>
  </dependency>
  ```

  ```bash Go theme={null}
  go get github.com/spotify/confidence-resolver/openfeature-provider/go
  go get github.com/open-feature/go-sdk
  ```

  ```toml Rust theme={null}
  # Add to Cargo.toml
  [dependencies]
  spotify-confidence-openfeature-provider-local = "<latest>"
  open-feature = "<latest>"
  ```

  ```bash Python theme={null}
  pip install confidence-openfeature-provider
  ```

  ```bash iOS theme={null}
  // When using Swift Package Manager, add the following to Package.swift
  .package(url: "git@github.com:spotify/confidence-sdk-swift.git", from: "<latest>")
  .product(name: "Confidence", package: "confidence-sdk-swift"),
  .product(name: "ConfidenceOpenFeature", package: "confidence-sdk-swift"),
  ```

  ```bash Android theme={null}
  implementation("com.spotify.confidence:openfeature-provider-android:<latest>")
  ```
</CodeGroup>

### Initialize Confidence

With dependencies installed, you can now create a Confidence provider for your
platform and connect it to the OpenFeature SDK.
You only need to do this once, preferably on app startup.

<CodeGroup>
  ```javascript JavaScript (Web) theme={null}
  import { OpenFeature } from '@openfeature/web-sdk';
  import { createConfidenceWebProvider } from '@spotify-confidence/openfeature-web-provider';

  const provider = createConfidenceWebProvider({
    clientSecret: 'your-client-secret',
    timeout: 3000,
  });

  // Set the context that is relevant for your flag, like the user ID.
  OpenFeature.setContext({
    user_id: 'user-test-id',
    plan: 'premium'
  });

  try {
    await OpenFeature.setProviderAndWait(provider);
  } catch (error) {
    console.error('Failed to initialize Confidence provider:', error);
  }
  ```

  ```typescript JavaScript (Server) theme={null}
  import { OpenFeature } from '@openfeature/server-sdk';
  import { createConfidenceServerProvider } from '@spotify-confidence/openfeature-server-provider-local';

  const provider = createConfidenceServerProvider({
    flagClientSecret: 'your-client-secret',
  });

  await OpenFeature.setProviderAndWait(provider);
  ```

  ```java Java theme={null}
  import com.spotify.confidence.OpenFeatureLocalResolveProvider;
  import dev.openfeature.sdk.OpenFeatureAPI;
  import dev.openfeature.sdk.Client;
  import dev.openfeature.sdk.MutableContext;

  // Create and register the provider
  OpenFeatureLocalResolveProvider provider =
      new OpenFeatureLocalResolveProvider("your-client-secret");
  OpenFeatureAPI.getInstance().setProviderAndWait(provider);
  ```

  ```go Go theme={null}
  import (
      "context"
      "github.com/open-feature/go-sdk/openfeature"
      "github.com/spotify/confidence-resolver/openfeature-provider/go/confidence"
  )

  ctx := context.Background()

  provider, err := confidence.NewProvider(ctx, confidence.ProviderConfig{
      ClientSecret: "your-client-secret",
  })
  if err != nil {
      log.Fatalf("Failed to create provider: %v", err)
  }

  openfeature.SetProviderAndWait(provider)
  ```

  ```rust Rust theme={null}
  use open_feature::{EvaluationContext, OpenFeature};
  use spotify_confidence_openfeature_provider_local::{ConfidenceProvider, ProviderOptions};

  #[tokio::main]
  async fn main() -> Result<(), Box<dyn std::error::Error>> {
      let options = ProviderOptions::new("your-client-secret");
      let provider = ConfidenceProvider::new(options)?;

      OpenFeature::singleton_mut()
          .await
          .set_provider(provider)
          .await;

      Ok(())
  }
  ```

  ```python Python theme={null}
  from openfeature import api
  from confidence import ConfidenceProvider

  provider = ConfidenceProvider(client_secret="your-client-secret")

  api.set_provider_and_wait(provider)
  ```

  ```swift iOS theme={null}
  import Confidence
  import ConfidenceProvider
  import OpenFeature

  let confidence = Confidence.Builder(clientSecret: "your-client-secret", loggerLevel: .NONE)
      .build()
  let provider = ConfidenceFeatureProvider(
      confidence: confidence,
      initializationStrategy: .fetchAndActivate
  )

  let ctx = ImmutableContext(
      targetingKey: "user-test-id",
      structure: ImmutableStructure(
          attributes: [
              "user_id": .string("user-test-id"),
              "plan": .string("premium")
          ]
      )
  )

  await OpenFeatureAPI.shared.setProviderAndWait(provider: provider, initialContext: ctx)
  ```

  ```kotlin Android theme={null}
  import com.spotify.confidence.ConfidenceFactory
  import com.spotify.confidence.ConfidenceFeatureProvider
  import com.spotify.confidence.ConfidenceRegion
  import com.spotify.confidence.InitialisationStrategy
  import dev.openfeature.sdk.OpenFeatureAPI
  import dev.openfeature.sdk.ImmutableContext
  import dev.openfeature.sdk.Value

  val confidence = ConfidenceFactory.create(
      context = app.applicationContext,
      clientSecret = "your-client-secret",
      region = ConfidenceRegion.EUROPE
  )

  val provider = ConfidenceFeatureProvider.create(
      confidence,
      initialisationStrategy = InitialisationStrategy.FetchAndActivate
  )

  OpenFeatureAPI.setProviderAndWait(provider)

  val evaluationContext = ImmutableContext(
      targetingKey = "user-test-id",
      attributes = mapOf(
          "user_id" to Value.String("user-test-id"),
          "plan" to Value.String("premium")
      )
  )
  OpenFeatureAPI.setEvaluationContextAndWait(evaluationContext)
  ```
</CodeGroup>

### Access the Flag

You can access the flag and its values using dot notation for nested properties.

<CodeGroup>
  ```javascript JavaScript (Web) theme={null}
  const client = OpenFeature.getClient();

  // value of header-redesign is { size: <some int>, color: <some string>}
  const size = client.getNumberValue('header-redesign.size', 10);
  const color = client.getStringValue('header-redesign.color', 'blue');
  ```

  ```typescript JavaScript (Server) theme={null}
  const client = OpenFeature.getClient();

  const context = {
    targetingKey: 'user-test-id',
    user_id: 'user-test-id',
    plan: 'premium'
  };

  // value of header-redesign is { size: <some int>, color: <some string>}
  const size = await client.getNumberValue('header-redesign.size', 10, context);
  const color = await client.getStringValue('header-redesign.color', 'blue', context);
  ```

  ```java Java theme={null}
  Client client = OpenFeatureAPI.getInstance().getClient();

  // Create evaluation context
  MutableContext ctx = new MutableContext("user-test-id");
  ctx.add("user_id", "user-test-id");
  ctx.add("plan", "premium");

  // value of header-redesign is { size: <some int>, color: <some string>}
  Integer size = client.getIntegerValue("header-redesign.size", 10, ctx);
  String color = client.getStringValue("header-redesign.color", "blue", ctx);
  ```

  ```go Go theme={null}
  client := openfeature.NewClient("my-app")

  evalCtx := openfeature.NewEvaluationContext("user-test-id", map[string]interface{}{
      "user_id": "user-test-id",
      "plan":    "premium",
  })

  // value of header-redesign is { size: <some int>, color: <some string>}
  size, _ := client.IntValue(ctx, "header-redesign.size", 10, evalCtx)
  color, _ := client.StringValue(ctx, "header-redesign.color", "green", evalCtx)
  ```

  ```rust Rust theme={null}
  let client = OpenFeature::singleton().await.create_client();

  let context = EvaluationContext::default()
      .with_targeting_key("user-test-id")
      .with_custom_field("user_id", "user-test-id")
      .with_custom_field("plan", "premium");

  // value of header-redesign is { size: <some int>, color: <some string>}
  let size = client
      .get_int_value("header-redesign.size", Some(&context), None)
      .await
      .unwrap_or(10);
  let color = client
      .get_string_value("header-redesign.color", Some(&context), None)
      .await
      .unwrap_or_else(|_| "green".to_string());
  ```

  ```python Python theme={null}
  from openfeature.evaluation_context import EvaluationContext

  client = api.get_client()

  context = EvaluationContext(
      targeting_key="user-test-id",
      attributes={
          "user_id": "user-test-id",
          "plan": "premium",
      }
  )

  # value of header-redesign is { size: <some int>, color: <some string>}
  size = client.get_integer_value("header-redesign.size", default_value=10, evaluation_context=context)
  color = client.get_string_value("header-redesign.color", default_value="blue", evaluation_context=context)
  ```

  ```swift iOS theme={null}
  let client = OpenFeatureAPI.shared.getClient()

  // value of header-redesign is { size: <some int>, color: <some string>}
  let size = client.getIntegerValue(key: "header-redesign.size", defaultValue: 10)
  let color = client.getStringValue(key: "header-redesign.color", defaultValue: "green")
  ```

  ```kotlin Android theme={null}
  val client = OpenFeatureAPI.getClient()

  // value of header-redesign is { size: <some int>, color: <some string>}
  val size = client.getIntegerValue("header-redesign.size", 10)
  val color = client.getStringValue("header-redesign.color", "blue")
  ```

  ```bash Curl theme={null}
  curl -H "Content-type: application/json" \
       --data '{
          "evaluation_context": {
            "user_id": "user-test-id",
            "plan": "premium"
          },
          "flags": ["flags/header-redesign"],
          "client_secret": "your-client-secret"
       }' \
       "https://resolver.confidence.dev/v1/flags:resolve"
  ```
</CodeGroup>

The code snippets above set two fields in the context: the `user_id` and the `plan` this user is on,
in this case `premium`.
You can use the `plan` field in the context to create targeted rules. For example, with this
information in the evaluation context, an A/B test can include only users on the premium plan as
its target audience.

This video gives a quick overview how targeting and evaluation contexts work in 2 minutes and 10 seconds.

<iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/rU82f1nRoGo?si=RvdoEFyt1OTdcOqr" title="Targeting and evaluation contexts in Confidence" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

<Note>
  If you were to run the code above you would only get the default values for the
  flag. Nothing tells the client that it should return any other
  value. To do so, you need to create flag variants and a rule that returns a variant.
</Note>

## Force a Variant For a User

To try out a variant, you can force it for a user with a specific
user ID. You do this by creating an **individual targeting rule** on the flag. Individual targeting rules let you
target specific attribute values, such as a list of user IDs. For example, you can add
the identifiers of your team members so only your team can test the new experience in its early stages.

<Tabs>
  <Tab title="With AI">
    ```text theme={null}
    Create an individual targeting rule on header-redesign that serves
    "new-style" to user_id "user-test-id".
    ```

    The assistant uses the Flags MCP tool `addOverrideRule`.
  </Tab>

  <Tab title="In the App">
    <Steps>
      <Step title="Click + Create rule and select Individual targeting" />

      <Step title="Select new-style as the variant" />

      <Step title="Enter user_id as the attribute" />

      <Step title="Type in user-test-id in the Values section and hit enter" />

      <Step title="Click Save" />

      <Step title="Enable the rule">
        Click the toggle on the rule card to enable it.
      </Step>
    </Steps>
  </Tab>
</Tabs>

If you re-run the code that fetches the flag value you now see that the flag
resolves to a value other than the default.

### Force all Variant For 50% of Employees

You can create a conditional targeting rule with a targeting audience that includes a subset
of the users in that audience. For example, you can create a conditional targeting rule that
targets 50% of the users in the `"plan": "employee"` audience. This way, provided
that all employees have their plan set to `employee`, you can test the new experience
on a subset of your colleagues.

<Tabs>
  <Tab title="With AI">
    ```text theme={null}
    Add a targeting rule on header-redesign that serves "new-style" to 50% of
    users where plan is "employee", randomized on user_id.
    ```

    The assistant uses the Flags MCP tool `addTargetingRule`.
  </Tab>

  <Tab title="In the App">
    On the flag page:

    <Steps>
      <Step title="Click + Create rule and select Conditional targeting" />

      <Step title="Select new-style as the variant" />

      <Step title="Add attribute criterion">
        In the audience section, click **Add attribute criterion** and write `plan` as field name with type `string` and click **Add**.
      </Step>

      <Step title="Set the inclusion rule to be plan is employee" />

      <Step title="Enter user_id as the randomization unit" />

      <Step title="Set the allocation to 50%" />

      <Step title="Click Save" />

      <Step title="Enable the rule">
        Click the toggle on the rule card to enable it.
      </Step>
    </Steps>
  </Tab>
</Tabs>

Since you now have two rules, the rules evaluate in the order of the list on the
flag page. If a user is eligible for the first rule, it returns a variant for the user.
If not, Confidence evaluates if the user is eligible for the second rule. In
this case, since only the user with ID `user-test-id` is eligible for the
individual targeting rule, Confidence evaluates eligibility for the second rule for everyone
else. The second rule, in turn, only targets users on the `employee` plan.

Change the priority of the rules by dragging the rule cards
into the desired order and clicking save.

## Test Flag Resolution

Test that the rule you expect returns a variant. You give an evaluation context and see which variant the flag resolves to.

<Tabs>
  <Tab title="With AI">
    ```text theme={null}
    Test resolving header-redesign for user_id "user-test-id".
    ```

    The assistant uses the Flags MCP tool `resolveFlag`. Expect the `new-style` variant.
  </Tab>

  <Tab title="In the App">
    The Resolve tester shows which rules match and which don't, together with the reasons why.

    On the page of your flag, select **Test rules** at the top of the list of rules.
    Click **Add evaluation context** and give the context you want to test to
    resolve. For example, to test the individual targeting rule for the user with ID
    `user-test-id`, add the `user_id` field with the value `user-test-id` to the evaluation
    context. Click **Resolve** to confirm that the individual targeting rule succeeds and
    returns the `new-style` variant.
  </Tab>
</Tabs>

Most of the SDKs also output log messages that redirect you to the resolve tester specifically for the
flag evaluation that the SDK performed.
The link has a message with the prefix:

> See resolves for \<flagName> in Confidence:

To share a specific test run with someone, copy the URL and send it as a link.
The link directs them to the Resolve tester with all context data preserved.

## Related Resources

<CardGroup cols={2}>
  <Card title="Create a Metric" href="/docs/guides/create-your-first-metric">
    Set up a metric to measure the impact of your flags
  </Card>

  <Card title="Launch a Rollout" href="/docs/guides/roll-out-a-change">
    Gradually release your feature to users
  </Card>

  <Card title="Launch an A/B Test" href="/docs/guides/run-an-ab-test">
    Run an experiment to compare variants
  </Card>

  <Card title="Flags Reference" href="/docs/capabilities/flags/overview">
    Deep dive into feature flag concepts and configuration
  </Card>
</CardGroup>
