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

# Subscribing to flag changes

<View title="Developer" />

<View title="Federal docs" />

<View title="EU docs" />

This topic explains how to configure each SDK to allow applications to subscribe to flag change notifications. This feature is available for client-side and server-side SDKs.

## Subscribe to flag change notifications

Flag change notifications allow your application to react to and consider flag changes immediately instead of waiting for your code to re-evaluate a flag. Some common use cases include updating content as part of a promotion, enabling/disabling feature code paths efficiently, showing outage bulletins to end users, and granting entitlements to groups of end users. You can register multiple listeners, and they will run in parallel.

### Avoid infinite loops in identify calls

Use caution if you use a flag change notification to trigger an `identify` call. This can lead to an infinite loop where the flag changes the context, which changes the flag, which changes the context, and so on. For example, you may include additional application information if a flag is true, but you will need to make sure that the inclusion of that information does not cause the flag to toggle.

### Unregister listeners when you are done

When you subscribe to flag changes, you register a handler function with the LaunchDarkly client. The SDK keeps a reference to that function so it can call it whenever the flag updates. Disable listeners when you are done by unregistering them to avoid memory leaks.

Details about each SDK's configuration are available in the SDK-specific sections below.

* [Client-side SDKs](#client-side-sdks)
* [Server-side SDKs](#server-side-sdks)

## Client-side SDKs

This feature is available in the following client-side SDKs:

* [.NET (client-side)](#net-client-side)
* [Android](#android)
* [C++ (client-side)](#c-client-side)
* [Electron](#electron)
* [Flutter](#flutter)
* [iOS](#ios)
* [JavaScript](#javascript)
* [Node.js (client-side)](#nodejs-client-side)
* [React Native](#react-native)
* [Roku](#roku)
* [Vue](#vue)

### .NET (client-side)

<Accordion title="Expand .NET (client-side) code sample">
  The client uses an event pattern which allows your app to subscribe to feature flag changes in real time.

  To subscribe to feature flag changes, register listeners for change events from the SDK:

  <CodeGroup>
    ```csharp title=".NET SDK (C#)" lines wrap theme={null}
    client.FlagTracker.FlagValueChanged += (sender, eventArgs) => {
        if (eventArgs.Key == "key-for-flag-i-am-watching") {
            DoSomethingWithNewFlagValue(eventArgs.NewValue.AsBool);
        }
    };
    ```
  </CodeGroup>

  The `FlagValueChangeEvent` includes the `Key`, `OldValue`, `NewValue`, and `Deleted` properties. Since flag values can be of any type, `OldValue` and `NewValue` are represented as `LdValue`. Use properties like `AsBool`, `AsString`, `AsInt`, etc. to convert to the desired type.

  To learn more, read [`IFlagTracker`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/client/api/LaunchDarkly.Sdk.Client.Interfaces.IFlagTracker.html).
</Accordion>

### Android

<Accordion title="Expand Android code sample">
  The client uses a listener pattern which allows your app to subscribe to feature flag changes in real time.

  To subscribe to feature flag changes, register listeners for change events from the SDK:

  <CodeGroup>
    ```java title="Java" lines wrap theme={null}
    String flagKey = "yourFlagKey";

    FeatureFlagChangeListener listener = new FeatureFlagChangeListener() {
        @Override
        public void onFeatureFlagChange(String flagKey) {
            try {
                boolean newValue = LDClient.get().boolVariation(flagKey, false);
            } catch (LaunchDarklyException e) {
                // LDClient.get() throws if the client has not been initialized
            }
        }
    };

    LDClient.get().registerFeatureFlagListener(flagKey, listener);
    ```

    ```kotlin title="Kotlin" lines wrap theme={null}
    val flagKey = "yourFlagKey"

    val listener = FeatureFlagChangeListener {
        val newValue = LDClient.get().boolVariation(flagKey, false)
    }

    LDClient.get().registerFeatureFlagListener(flagKey, listener)
    ```
  </CodeGroup>

  The flag key passed to `onFeatureFlagChange` is the key of the updated flag, which lets a single listener be registered for multiple flags.

  You can also disable listeners by unregistering them:

  <CodeGroup>
    ```java title="Java" lines wrap theme={null}
    LDClient.get().unregisterFeatureFlagListener(flagKey, listener);
    ```

    ```kotlin title="Kotlin" lines wrap theme={null}
    LDClient.get().unregisterFeatureFlagListener(flagKey, listener)
    ```
  </CodeGroup>

  <Note>
    **Availability**

    These calls have been available since v2.8.0:

    * `LDAllFlagsListener`
    * `LDClient.registerAllFlagsListener`
    * `LDClient.unregisterAllFlagsListener`
  </Note>

  Additionally, we provide an update listener interface for when you want to be notified when the flag cache is updated. The application provides a class implementing `LDAllFlagsListener` which provides the SDK with the method `onChange`. Whenever the SDK's flag cache is updated, it calls the `onChange` method with a list of flag keys for flags that were updated during the update to the flag cache. If no flag values changed, this list is empty.

  Here is an example:

  <CodeGroup>
    ```java title="Java" lines wrap theme={null}
    LDAllFlagsListener listener = new LDAllFlagsListener() {
        @Override
        public void onChange(List<String> flagKeys) {
            // Get new values for flagKeys or other operations
        }
    };

    // register all flags listener
    LDClient.get().registerAllFlagsListener(listener);
    // when done with all flags listener it should be unregistered
    LDClient.get().unregisterAllFlagsListener(listener);
    ```

    ```kotlin title="Kotlin" lines wrap theme={null}
    val listener = LDAllFlagsListener {
        // Get new values for flag keys (from implicit "it" list variable) or other operations
    }

    // register all flags listener
    LDClient.get().registerAllFlagsListener(listener)
    // when done with all flags listener it should be unregistered
    LDClient.get().unregisterAllFlagsListener(listener)
    ```
  </CodeGroup>
</Accordion>

### C++ (client-side)

<Accordion title="Expand C++ (client-side) code sample">
  The client exposes an interface which allows your app to subscribe to feature flag changes in real time.

  To subscribe to feature flag changes, register listeners for change events from the SDK:

  <CodeGroup>
    ```cpp title="C++ SDK v3.0 (native)" lines wrap theme={null}
    auto listener = client.FlagNotifier().OnFlagChange("example-flag-key", [](auto event) {
      if (event->Deleted()) {
        std::cout << "The flag was deleted" << std::endl;
      } else {
        std::cout << "The flag was " << event->OldValue() << " and now it is " << event->NewValue() << std::endl;
      }
    });

    /* Then, you can disconnect the listener later */
    listener->Disconnect();
    ```
  </CodeGroup>

  If you are working in C, there are a few more steps:

  1. Define a callback to receive the flag change notification:

  <CodeGroup>
    ```c title="C++ SDK v3.0 (C binding), define callback" lines wrap theme={null}
    void OnFlagChange(char const* flag_key,
                          LDValue new_value,
                          LDValue old_value,
                          bool deleted,
                          void* user_data) {
         if (deleted) {
           printf("The flag %s was deleted\n", flag_key);
         } else {
           printf("The flag %s was updated\n", flag_key);
         }
    }
    ```
  </CodeGroup>

  2. Assign the callback by creating a listener connection:

  <CodeGroup>
    ```c title="C++ SDK v3.0 (C binding), create listener connection" lines wrap theme={null}
    struct LDFlagListener listener;
    LDFlagListener_Init(&listener);

    listener.FlagChanged = OnFlagChange;

    /* You may optionally assign the UserData pointer, which will be passed into FlagChanged. */
    /* listener.UserData = &some_struct; */

    LDListenerConnection connection =
           LDClientSDK_FlagNotifier_OnFlagChange(sdk, "example-flag-key", listener);

    /* You can disconnect the listener later */
     LDListenerConnection_Disconnect(connection);
    ```
  </CodeGroup>

  3. Ensure the connection is freed when you are done with it:

  <CodeGroup>
    ```c title="C++ SDK v3.0 (C binding), free connection" lines wrap theme={null}
    LDListenerConnection_Free(connection);
    ```
  </CodeGroup>

  To learn more, read [`FlagNotifier`](https://launchdarkly.github.io/cpp-sdks/libs/client-sdk/docs/html/classlaunchdarkly_1_1client__side_1_1Client.html#a0406a57e9c751b013696f6f7663a7170).
</Accordion>

### Electron

<Accordion title="Expand Electron code sample">
  The client uses an event emitter pattern which allows your app to subscribe to feature flag changes in real time.

  To subscribe to a specific feature flag change, register a listener for a `change:flag-key` event from the SDK:

  <CodeGroup>
    ```js title="JavaScript" lines wrap theme={null}
    client.on('change:example-flag-key', (context) => {
      const newValue = client.variation('example-flag-key', false);
      console.log('example-flag-key changed to: ' + newValue);
    });
    ```
  </CodeGroup>

  Or, you can listen for all feature flag changes:

  <CodeGroup>
    ```js title="JavaScript" lines wrap theme={null}
    client.on('change', (context, changedKeys) => {
      changedKeys.forEach((key) => {
        console.log('Flag ' + key + ' changed');
      });
    });
    ```
  </CodeGroup>

  Subscribing to `change` events automatically turns on streaming mode, unless you have explicitly set `streaming` to `false`.
</Accordion>

### Flutter

<Accordion title="Expand Flutter code sample">
  The client uses an observer pattern which allows your app to subscribe to feature flag changes in real time.

  To subscribe to feature flag changes, register listeners for change events from the SDK:

  <CodeGroup>
    ```dart title="Flutter SDK v4" lines wrap theme={null}
    final sub = client.flagChanges.listen((changeEvent) {
      for(var flagKey in changeEvent.keys) {
        print(client.jsonVariation(flagKey, LDValue.ofString('default')));
      }
    });
    ```
  </CodeGroup>

  `flagChanges` is a stream that emits all flag changes, so you can use a single listener for multiple flags.

  You can disable listeners by unregistering them:

  <CodeGroup>
    ```dart title="Flutter SDK v4" lines wrap theme={null}
    sub.cancel();
    ```
  </CodeGroup>

  You can also use `flagChanges` if you want to be notified any time the flag cache is updated. The application provides a callback that is activated whenever the SDK receives new flag data from the service. It calls with a list of flag keys that were updated. If no flag values changed, this list is empty.

  To learn more, read [`flagChanges`](https://pub.dev/documentation/launchdarkly_flutter_client_sdk/latest/launchdarkly_flutter_client_sdk/LDClient/flagChanges.html).
</Accordion>

### iOS

<Accordion title="Expand iOS code sample">
  The client uses an observer pattern which allows your app to subscribe to feature flag changes in real time. To subscribe to feature flag changes, register listeners for change events from the SDK.

  The SDK provides methods for listening to a single flag, all flags, or no change to any flag. `observeFlagsUnchanged` is called when the SDK successfully receives an update or comes back online but no flags have changed. If the value of the flag changes, the method executes the handler. It passes in the `changedFlag` containing the old and new flag values, and old and new flag value source.

  The SDK retains only weak references to the owner, which lets the client app freely destroy owners without issues. Client apps should use a capture list specifying `[weak self]` inside handlers to avoid retain cycles causing a memory leak.

  The SDK executes handlers on the main thread. `LDChangedFlag` does not know the type of `oldValue` or `newValue`. The client app should cast the value into the type needed.

  <Warning>
    **LDObserverOwner Lifecycle**

    The lifetime of the `LDObserverOwner` must extend for at least as long as you want to receive flag change notifications.
  </Warning>

  To configure the client:

  <CodeGroup>
    ```swift title="Swift" maxLines=0 expandable lines wrap theme={null}
    let flagKey = "example-flag-key"
    let flagObserverOwner = flagKey as LDObserverOwner

    let client = LDClient.get()!

    // Observe a specific flag
    client.observe(keys: [flagKey], owner: flagObserverOwner, handler: { [weak self] changedFlags in
        if let changedFlag = changedFlags[flagKey] {
            let newValue = client.boolVariation(forKey: flagKey, defaultValue: false)
            print("Flag \(flagKey) changed to: \(newValue)")
        }
    })

    client.stopObserving(owner: flagObserverOwner)

    // Observe when flags are unchanged
    client.observeFlagsUnchanged(owner: self) {
        client.stopObserving(owner: self as LDObserverOwner)
    }

    // Observe all flag changes
    client.observeAll(owner: self) { [weak self] changedFlags in
        for (key, changedFlag) in changedFlags {
            print("\(key) changed from \(changedFlag.oldValue) to \(changedFlag.newValue)")
        }
        client.stopObserving(owner: self as LDObserverOwner)
    }
    ```

    ```objectivec title="Objective-C" lines wrap theme={null}
    __weak typeof(self) weakSelf = self;
    [[LDClient get] observeKeys:self.flagKeys owner:self handler:^(NSDictionary<NSString *,LDChangedFlag *> * _Nonnull changedFlags) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        for (NSString* flagKey in changedFlags.allKeys) {
            LDChangedFlag *changedFlag = changedFlags[flagKey];
            NSLog(@"Flag %@ changed from %@ to %@", flagKey, changedFlag.oldValue, changedFlag.newValue);
        }
    }];
    [[LDClient get] observeFlagsUnchangedWithOwner:self handler:^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        // No flags changed
    }];
    ```
  </CodeGroup>
</Accordion>

### JavaScript

<Accordion title="Expand JavaScript code sample">
  The client uses an event emitter pattern which allows your app to subscribe to feature flag changes in real time.

  To subscribe to all feature flag changes, register listeners for change events from the SDK:

  <CodeGroup>
    ```js title="JavaScript v4.0" lines wrap theme={null}
    client.on('change', (context, changedKeys) => {
      changedKeys.forEach(flagKey => {
        const flagValue = client.variation(flagKey, defaultValue);
      });
    });
    ```

    ```js title="JavaScript v3.x" lines wrap theme={null}
    client.on('change', (context, changedKeys) => {
      console.log('flags changed:', changedKeys);
    });
    ```
  </CodeGroup>

  The `changedKeys` array contains the keys of all flags that have changed. You can also subscribe to specific flags.

  Here's how:

  <CodeGroup>
    ```js title="JavaScript v4.0" lines wrap theme={null}
    client.on('change:example-flag-key', (context) => {
      const flagValue = client.variation('example-flag-key', false);
    });
    ```

    ```js title="JavaScript v3.x" lines wrap theme={null}
    client.on('change:example-flag-key', (context) => {
      const newValue = client.variation('example-flag-key', false);
      console.log('example-flag-key changed to:', newValue);
    });
    ```
  </CodeGroup>
</Accordion>

### Node.js (client-side)

<Accordion title="Expand Node.js (client-side) code sample">
  The client uses an event emitter pattern which allows your app to subscribe to feature flag changes in real time.

  To subscribe to all feature flag changes, register listeners for change events from the SDK:

  <CodeGroup>
    ```js title="JavaScript" lines wrap theme={null}
    client.on('change', (context, changedKeys) => {
      console.log('flags changed:', changedKeys);
    });
    ```
  </CodeGroup>

  The `changedKeys` array contains the keys of all flags that have changed. You can also subscribe to specific flags.

  Here's how:

  <CodeGroup>
    ```js title="JavaScript" lines wrap theme={null}
    client.on('change:example-flag-key', (context) => {
      const newValue = client.variation('example-flag-key', false);
      console.log('example-flag-key changed to:', newValue);
    });
    ```
  </CodeGroup>
</Accordion>

### React Native

<Accordion title="Expand React Native code sample">
  The client uses an event emitter pattern which allows your app to subscribe to feature flag changes in real time. The available event types include `error` and `change`.

  To subscribe to all feature flag changes, register listeners for change events from the SDK. Here's how:

  <CodeGroup>
    ```js title="React Native SDK v10" lines wrap theme={null}
    const changeHandler = (context: LDContext, changedKeys: string[]) => {
      console.log('listening to change');
    };
    client.on('change', changeHandler);
    ```
  </CodeGroup>

  You can also disable listeners by unregistering them:

  <CodeGroup>
    ```js title="React Native SDK v10" lines wrap theme={null}
    const changeHandler = (context: LDContext, changedKeys: string[]) => {
      console.log('listening to change');
    };
    client.off('change', changeHandler);
    ```
  </CodeGroup>

  To learn more, read [`on`](https://launchdarkly.github.io/js-core/packages/sdk/react-native/docs/classes/LDClientImpl.html#on) and [`off`](https://launchdarkly.github.io/js-core/packages/sdk/react-native/docs/classes/LDClientImpl.html#off).
</Accordion>

### Vue

<Accordion title="Expand Vue code sample">
  The Vue SDK subscribes to flag change events automatically when you use a variation composable or a variation detail composable, which opens a streaming connection. Your component re-renders when the flag value changes. In most cases you do not need to register a listener yourself.

  To disable streaming, set `streaming` to `false` in `ldOptions`. To subscribe to change events yourself, retrieve the client with `useLDClient()` and use the underlying JavaScript SDK's `on()` and `off()` methods.

  Here is an example of a variation composable, which subscribes to that flag's change events for you:

  <CodeGroup>
    ```html title="Vue SDK v3.0" lines wrap theme={null}
    <script setup>
    import { useBoolVariation } from '@launchdarkly/vue-client-sdk'

    // The SDK listens for `change:example-flag-key` and stops listening when the component unmounts.
    const showNewFeature = useBoolVariation('example-flag-key', false)
    </script>

    <template>
      <div v-if="showNewFeature">The new feature is on.</div>
    </template>
    ```
  </CodeGroup>

  To run your own logic when a flag changes, register a listener on the client. Unregister it when the component's scope is disposed:

  <CodeGroup>
    ```html title="Vue SDK v3.0, all flags" lines wrap theme={null}
    <script setup>
    import { onScopeDispose } from 'vue'
    import { useLDClient } from '@launchdarkly/vue-client-sdk'

    const ldClient = useLDClient()

    const onChange = (context, changedKeys) => {
      console.log('flags changed:', changedKeys)
    }

    ldClient.on('change', onChange)
    onScopeDispose(() => ldClient.off('change', onChange))
    </script>
    ```

    ```html title="Vue SDK v3.0, a specific flag" lines wrap theme={null}
    <script setup>
    import { onScopeDispose } from 'vue'
    import { useLDClient } from '@launchdarkly/vue-client-sdk'

    const ldClient = useLDClient()

    const onChange = () => {
      console.log('example-flag-key changed to:', ldClient.boolVariation('example-flag-key', false))
    }

    ldClient.on('change:example-flag-key', onChange)
    onScopeDispose(() => ldClient.off('change:example-flag-key', onChange))
    </script>
    ```
  </CodeGroup>
</Accordion>

## Server-side SDKs

This feature is available in the following server-side SDKs:

* [.NET (server-side)](#net-server-side)
* [Go](#go)
* [Java](#java)
* [Node.js (server-side)](#nodejs-server-side)
* [Python](#python)
* [Ruby](#ruby)

### .NET (server-side)

<Accordion title="Expand .NET (server-side) code sample">
  <Warning>
    **This feature is not available in all SDK versions**

    The .NET SDK only supports subscribing to flag changes in versions 6.0.0 and higher.
  </Warning>

  The SDK provides an event-based mechanism to notify you when flag configurations change. [`LDClient.FlagTracker`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.LdClient.html#LaunchDarkly_Sdk_Server_LdClient_FlagTracker) returns an interface for this mechanism, [`IFlagTracker`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Interfaces.IFlagTracker.html).

  Any event handler that you add to the [`IFlagTracker.FlagChanged`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Interfaces.IFlagTracker.html#LaunchDarkly_Sdk_Server_Interfaces_IFlagTracker_FlagChanged) event will be called with a [`FlagChangeEvent`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Interfaces.FlagChangeEvent.html) whenever there is a change in any feature flag's configuration, or in anything else that could indirectly affect the flag value, such as a prerequisite flag or a segment that the flag uses.

  The event data consists only of the flag key. It does not contain a flag value, because in server-side SDKs, there is no such thing as a flag value except when it is evaluated for a specific context.

  The listener method is called synchronously from a background task.

  Here's how:

  <CodeGroup>
    ```csharp title="C#" lines wrap theme={null}
    void LogWheneverAnyFlagChanges(LdClient client) {
        client.FlagTracker.FlagChanged += (sender, eventArgs) =>
        {
            Console.WriteLine("Flag \"{0}\" has changed", eventArgs.Key);
        };
    }
    ```
  </CodeGroup>

  To listen for changes in flag values for a specific flag key and context, use [`IFlagTracker.FlagValueChangeHandler()`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Interfaces.IFlagTracker.html#LaunchDarkly_Sdk_Server_Interfaces_IFlagTracker_FlagValueChangeHandler_). It calls your code with a [`FlagValueChangeEvent`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Interfaces.FlagValueChangeEvent.html). This is equivalent to re-evaluating the flag for that context whenever there is a change in that flag. Because flag values can have different data types, the value is reported using the general type [`LdValue`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.LdValue.html).

  <CodeGroup>
    ```csharp title=".NET SDK v7.0+ (C#)" lines wrap theme={null}
    void LogWheneverOneFlagChangesForOneContext(LdClient client, string flagKey, Context context) {
        client.FlagTracker.FlagChanged += client.FlagTracker.FlagValueChangeHandler(
            flagKey,
            context,
            (sender, eventArgs) =>
            {
                Console.WriteLine(
                    "Flag \"{0}\" for context \"{1}\" has changed from {2} to {3}",
                    flagKey,
                    context.Key,
                    eventArgs.OldValue,
                    eventArgs.NewValue
                );
            });
    }
    ```
  </CodeGroup>
</Accordion>

### Go

<Accordion title="Expand Go code sample">
  The Go SDK provides a channel-based mechanism to notify you when flag configurations change. The [`LDClient.GetFlagTracker()`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7#LDClient.GetFlagTracker) method returns an interface for this mechanism called [`FlagTracker`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7/interfaces#FlagTracker).

  Calling `GetFlagTracker().AddFlagChangeListener()` provides a channel that receives a [`FlagChangeEvent`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7/interfaces#FlagChangeEvent) whenever there is a change in any feature flag's configuration. These changes include anything that could indirectly affect the flag value, such as a prerequisite flag or a segment that the flag uses.

  The event data consists only of the flag key. It does not contain a flag value, because in server-side SDKs, flags only have values when they are evaluated for a specific evaluation context.

  <CodeGroup>
    ```go title="Go SDK" lines wrap theme={null}
    import (
        "log"
        ld "github.com/launchdarkly/go-server-sdk/v7"
    )

    func logWheneverAnyFlagChanges(client *ld.LDClient) {
        updateCh := client.GetFlagTracker().AddFlagChangeListener()
        go func() {
            for event := range updateCh {
                log.Printf("Flag %q has changed", event.Key)
            }
        }()
    }
    ```
  </CodeGroup>

  To listen for changes in flag values for a specific flag key and context, use `GetFlagTracker().AddFlagValueChangeListener()`, which provides [`FlagValueChangeEvent`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7/interfaces#FlagValueChangeEvent)s. This is equivalent to re-evaluating the flag for that context whenever `AddFlagChangeListener()` reports a change in that flag. Because flag values can have different data types, the value is reported using the general type [`ldvalue.Value`](https://pkg.go.dev/github.com/launchdarkly/go-sdk-common/v3/ldvalue#Value).

  <CodeGroup>
    ```go title="Go SDK" expandable lines wrap theme={null}
    import (
        "log"
        ld "github.com/launchdarkly/go-server-sdk/v7"
        "github.com/launchdarkly/go-sdk-common/v3/ldcontext"
        "github.com/launchdarkly/go-sdk-common/v3/ldvalue"
    )

    func logWheneverOneFlagChangesForOneUser(client *ld.LDClient, flagKey string, context ldcontext.Context) {
        updateCh := client.GetFlagTracker().AddFlagValueChangeListener(flagKey, context, ldvalue.Null())
        go func() {
            for event := range updateCh {
                log.Printf("Flag %q for context %q has changed from %s to %s", event.Key,
                    context.Key(), event.OldValue, event.NewValue)
            }
        }()
    }
    ```
  </CodeGroup>

  If you are using scoped clients, use `CurrentContext()` to pass in the scoped client's current context. There is not an `AddFlagValueChangeListener` method in the `LDScopedClient`.

  <Warning>
    **LDScopedClient is in beta**

    `LDScopedClient` is in beta. It is still undergoing testing and active development. Its functionality may change without notice, including becoming backwards incompatible.
  </Warning>

  With both of these methods, it is the caller's responsibility to consume values from the channel. Letting values accumulate in the channel can cause an SDK goroutine to be blocked.

  <Warning>
    **The flag change event channel can fill**

    If you call `GetFlagTracker().AddFlagChangeListener()` and fail to read from the provided channel, the channel will eventually fill up. When this happens, the SDK's reconnections are blocked.

    To prevent this, make sure to read flag change events from the provided channel, even if you choose to discard the updates.
  </Warning>
</Accordion>

### Java

<Accordion title="Expand Java code sample">
  <Warning>
    **This feature is not available in all SDK versions**

    The Java SDK only supports subscribing to flag changes in versions 5.0.0 and higher.
  </Warning>

  The SDK provides a listener-based mechanism to notify you when flag configurations change. The [`LDClient.getFlagTracker()`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/LDClient.html#getFlagTracker--) method returns an interface for this mechanism, [`FlagTracker`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/interfaces/FlagTracker.html).

  Calling [`getFlagTracker().addFlagChangeListener`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/interfaces/FlagTracker.html#addFlagChangeListener-com.launchdarkly.sdk.server.interfaces.FlagChangeListener-) calls your listener with a [`FlagChangeEvent`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/interfaces/FlagChangeEvent.html) whenever there is a change in any feature flag's configuration, or in anything else that could indirectly affect the flag value, such as a prerequisite flag or a user segment that the flag uses.

  The event data consists only of the flag key. It does not contain a flag value, because in server-side SDKs, there is no such thing as a flag value except when it is evaluated for a specific set of user properties.

  The listener method is called from a worker thread.

  Here's how:

  <CodeGroup>
    ```java title="Java" lines wrap theme={null}
    void logWheneverAnyFlagChanges(LDClient client) {
        client.getFlagTracker().addFlagChangeListener(event -> {
            System.out.printf("Flag \"%s\" has changed\n", event.getKey());
        });
    }
    ```
  </CodeGroup>

  To listen for changes in flag values for a specific flag key and context, use [`getFlagTracker().addFlagValueChangeListener`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/interfaces/FlagTracker.html#addFlagValueChangeListener-java.lang.String-com.launchdarkly.sdk.LDContext-com.launchdarkly.sdk.server.interfaces.FlagValueChangeListener-), which provides [`FlagValueChangeEvent`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/interfaces/FlagValueChangeEvent.html)s. This is equivalent to re-evaluating the flag for that context whenever `addFlagChangeListener()` reports a change in that flag. Because flag values can have different data types, the value is reported using the general type [`LDValue`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/LDValue.html).

  <CodeGroup>
    ```java title="Java SDK v6.0+" lines wrap theme={null}
    void logWheneverOneFlagChangesForOneContext(LDClient client, String flagKey, LDContext context) {
        client.getFlagTracker().addFlagValueChangeListener(flagKey, context, event -> {
            System.out.printf("Flag \"%s\" for context \"%s\" has changed from %s to %s\n", event.getKey(),
                context.getKey(), event.getOldValue(), event.getNewValue());
        });
    }
    ```
  </CodeGroup>
</Accordion>

### Node.js (server-side)

<Accordion title="Expand Node.js (server-side) code sample">
  The SDK provides an event-based mechanism to notify you when flag configurations change.

  For example, imagine you have a feature flag named `example-flag-key`. If the SDK detects a change in `example-flag-key`'s configuration, or in anything else that could indirectly affect the flag value, such as a prerequisite flag or a user segment that `example-flag-key` uses, it emits two events.

  These events are:

  * `"update"` and
  * `"update:example-flag-key"`

  You can listen for `"update:example-flag-key"` if you only want to know about updates affecting that flag specifically, or `"update"` if you want to be notified about all updates.

  For both of these event kinds, an extra parameter is sent to event listeners. This object has the single property `key`, with its value set to the flag key. If you listened for the general `"update"` event, this lets you know which flag changed.

  The event parameter does not contain the flag value. In server-side SDKs, there is no such thing as a flag value except when it is evaluated for a specific set of user properties.

  To find out what the effect, if any, of the configuration change was, call `variation()` after receiving an update event.

  Here is an example:

  <CodeGroup>
    ```js title="JavaScript" lines wrap theme={null}
    client.on('update', (param) => {
      console.log('a flag was changed: ' + param.key);
    });

    client.on('update:example-flag-key', () => {
      console.log('the example-flag-key flag was changed');
    });
    ```
  </CodeGroup>
</Accordion>

### Python

<Accordion title="Expand Python code sample">
  <Warning>
    **This feature is not available in all SDK versions**

    The Python SDK only supports subscribing to flag changes in versions 9.1.0 and higher.
  </Warning>

  The SDK provides a listener-based mechanism to notify you when flag configurations change. The [`LDClient#flag_tracker`](https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-main.html#ldclient.client.LDClient.flag_tracker) method returns an interface for this mechanism, [`FlagTracker`](https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-extending.html#ldclient.interfaces.FlagTracker).

  Calling [`flag_tracker.add_listener`](https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-extending.html#ldclient.interfaces.FlagTracker.add_listener) calls your listener with a [`FlagChange`](https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-extending.html#ldclient.interfaces.FlagChange) event whenever there is a change to any of the following:

  * the flag's configuration
  * the prerequisite flag's configuration
  * a segment used by the flag

  The event data consists only of the flag key. It does not contain a flag value, because server-side SDKs only evaluate flags when you provide a specific context.

  The listener method is called from the caller's thread.

  Here's how:

  <CodeGroup>
    ```python title="Python" lines wrap theme={null}
    def flag_change_listener(flag_change):
        print(f"{flag_change.key} has changed")


    listener = ldclient.get().flag_tracker.add_listener(flag_change_listener)
    ```
  </CodeGroup>

  To listen for changes in flag values for a specific flag key and context, use [`flag_tracker.add_flag_value_change_listener`](https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-extending.html#ldclient.interfaces.FlagTracker.add_flag_value_change_listener), which provides [`FlagValueChange`](https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-extending.html#ldclient.interfaces.FlagValueChange) events. This is equivalent to re-evaluating the flag for that context whenever `add_listener` reports a change in that flag.

  <CodeGroup>
    ```python title="Python" lines wrap theme={null}
    def flag_value_change_listener(flag_change):
        print(f"{flag_change.key} has changed from {flag_change.old_value} to {flag_change.new_value}")


    listener = ldclient.get().flag_tracker.add_flag_value_change_listener('example-flag-key', context, flag_value_change_listener)
    ```
  </CodeGroup>
</Accordion>

### Ruby

<Accordion title="Expand Ruby code sample">
  <Warning>
    **This feature is not available in all SDK versions**

    The Ruby SDK only supports subscribing to flag changes in versions 7.2.0 and higher.
  </Warning>

  The SDK provides a listener-based mechanism to notify you when flag configurations change. The [`LDClient#flag_tracker`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/LDClient.html#flag_tracker-instance_method) method returns an interface for this mechanism, [`FlagTracker`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/Interfaces/FlagTracker.html).

  Calling [`flag_tracker.add_listener`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/Interfaces/FlagTracker.html#add_listener-instance_method) calls your listener with a [`FlagChange`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/Interfaces/FlagChange.html) event whenever there is a change to any of the following:

  * the flag's configuration
  * the prerequisite flag's configuration
  * a segment used by the flag

  The event data consists only of the flag key. It does not contain a flag value, because server-side SDKs only evaluate flags when you provide a specific context.

  The listener method is called from a worker thread.

  Here's how:

  <CodeGroup>
    ```ruby title="Ruby" lines wrap theme={null}
    class Listener
        def update(status)
            puts "Flag #{status.key} has changed"
        end
    end

    client.flag_tracker.add_listener(Listener.new)
    ```
  </CodeGroup>

  To listen for changes in flag values for a specific flag key and context, use [`flag_tracker.add_flag_value_change_listener`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/Interfaces/FlagTracker.html#add_flag_value_change_listener-instance_method), which provides [`FlagValueChange`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/Interfaces/FlagValueChange.html) events. This is equivalent to re-evaluating the flag for that context whenever `add_listener` reports a change in that flag.

  <CodeGroup>
    ```ruby title="Ruby" lines wrap theme={null}
    class Listener
        def update(changed)
            puts "Flag #{changed.key} has changed from #{changed.old_value} to #{changed.new_value}"
        end
    end

    client.flag_tracker.add_flag_value_change_listener("example-flag-key", context, Listener.new)
    ```
  </CodeGroup>
</Accordion>

### Roku

<Accordion title="Expand Roku code sample">
  You can use Roku's `observeField` method on your node to respond to changes in flags.

  Here's how:

  <CodeGroup>
    ```brightscript title="BrightScript" lines wrap theme={null}

    ' replace "onFeatureChange" with the name of your handler functions
    launchDarklyNode.observeField("flags", "onFeatureChange")

    ```
  </CodeGroup>
</Accordion>
