# Configcat > This endpoint updates the permissions of a Member identified by the`userId`. This endpoint can also be used to move a Member between Permission Groups within a Product. Only a single Permission Group --- # Source: https://configcat.com/docs/api/reference/add-member-to-group.md # Update Member Permissions Copy page This endpoint updates the permissions of a Member identified by the `userId`. This endpoint can also be used to move a Member between Permission Groups within a Product. Only a single Permission Group can be set per Product. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When the update was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/advanced/team-management/saml/identity-providers/adfs.md # ADFS Identity Provider Copy page Connect ConfigCat with Active Directory Federation Services (ADFS) via SAML. ## Introduction[​](#introduction "Direct link to Introduction") Each SSO Identity Provider requires specific information to configure a SAML integration. The following guide will walk you through how you can connect ConfigCat with ADFS as a SAML Identity Provider. ## 1. Collect SAML Metadata from ConfigCat[​](#1-collect-saml-metadata-from-configcat "Direct link to 1. Collect SAML Metadata from ConfigCat") * Open your organization's authentication settings on the [ConfigCat Dashboard](https://app.configcat.com/organization/authentication). ![ConfigCat authentication settings](/docs/assets/saml/dashboard/authentication.png) * Click `ADD SAML IDENTITY PROVIDER`. ![ConfigCat Add Identity Provider](/docs/assets/saml/dashboard/add_idp.png) * Give a name for your Identity Provider, and click `Create`. ![ConfigCat Name Identity Provider](/docs/assets/saml/dashboard/adfs_name.png) * From the next section of the dialog, copy the following values and save them for further use. * `Entity ID` * `Assertion Consumer Service` ![ConfigCat SAML configuration](/docs/assets/saml/dashboard/acs_entity_id_1.png) ## 2. Configure a Relying Party Trust[​](#2-configure-a-relying-party-trust "Direct link to 2. Configure a Relying Party Trust") * Open the ADFS Management console, and click `Add Relying Party Trust`. ![ADFS add relying party trust](/docs/assets/saml/adfs/2_add_relying_party.png) * Make sure the `Claims aware` option is selected, and click `Start`. ![ADFS claims aware](/docs/assets/saml/adfs/3_claims_aware.png) * Select the `Enter data about this relying party manually` option, and click `Next`. ![ADFS manual relying party setup](/docs/assets/saml/adfs/4_manual_metadata.png) * Type a descriptive `Display name`, and click `Next`. ![ADFS display name](/docs/assets/saml/adfs/5_name.png) * No action required on the `Configure Certificate` pane, click `Next`. ![ADFS certificate configuration](/docs/assets/saml/adfs/6_configure_cert.png) * Select the `Enable support for the SAML 2.0 WebSSO protocol` option, and paste the value of `Assertion Consumer Service` from [Step 1](#1-collect-saml-metadata-from-configcat) into the `Relying party SAML 2.0 SSO service URL` field.
Then, Click `Next`. ![ADFS acs URL](/docs/assets/saml/adfs/7_acs_url.png) * Paste the value of `Entity ID` from [Step 1](#1-collect-saml-metadata-from-configcat) into the `Relying party trust identifier` field, and click `Add`.
Then, click `Next`. ![ADFS entity ID](/docs/assets/saml/adfs/8_add_entity_id.png) * No action required on the `Choose Access Control Policy` pane, click `Next`. ![ADFS Access Control Policy](/docs/assets/saml/adfs/9_access_control_policy.png) * Review the changes, then click `Next`. ![ADFS add trust](/docs/assets/saml/adfs/10_ready_to_add_trust.png) * The Relying Party Trust is now successfully added, make sure the `Configure claims issuance policy for this application` option is checked, and click `Close`. ![ADFS finish configuration](/docs/assets/saml/adfs/11_finish_party.png) ## 3. Configure Claims Issuance Policy[​](#3-configure-claims-issuance-policy "Direct link to 3. Configure Claims Issuance Policy") * After adding the Relying Party Trust, the following dialog should appear.
Click `Add rule`. ![ADFS edit claims](/docs/assets/saml/adfs/12_edit_claims.png) * Select `Send LDAP Attributes as Claims` as the `Claim rule template`, and click `Next`. ![ADFS LDAP claims](/docs/assets/saml/adfs/13_ldap_claims.png) * Apply the following, and click `Finish`. * Add a descriptive `Claim rule name`. * Select `Active Directory` as `Attribute store`. * Select `User-Principal-Name` as `LDAP Attribute`. * Select `Name ID` as `Outgoing Claim Type`. ![ADFS unc to nameid](/docs/assets/saml/adfs/14_unc_to_nameid.png) * Click `OK`. ![ADFS finish claims](/docs/assets/saml/adfs/15_finish_claims.png) ## 4. Configure ConfigCat with SAML Details from ADFS[​](#4-configure-configcat-with-saml-details-from-adfs "Direct link to 4. Configure ConfigCat with SAML Details from ADFS") You can choose one of the following options to configure ConfigCat with SAML Identity Provider metadata. * Metadata URL * Manual Configuration - Select `Endpoints`, and copy the URL Path of the `Federation Metadata` endpoint. ![ADFS metadata url path](/docs/assets/saml/adfs/metadata_url.png) - Type the URL into the `Metadata URL` field at ConfigCat in the following format: `https://[ADFS-DOMAIN]/[FEDERATION-METADATA-URL-PATH]`. ![ADFS metadata url](/docs/assets/saml/adfs/cc_metadata_new.png) - Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) - Click on `Save`. * Select `Endpoints`, and save the URL Path of the `SAML 2.0/WS-Federation` endpoint. ![ADFS SAML verification](/docs/assets/saml/adfs/login_url.png) * Select `Certificates`, then select the `Token Signing` certificate, and click `View Certificate`. ![ADFS certificates](/docs/assets/saml/adfs/view_cert.png) * On the `Details` tab click `Copy to File`. ![ADFS cert details](/docs/assets/saml/adfs/copy_cert_to_file.png) * Click `Next`. ![ADFS cert wizard](/docs/assets/saml/adfs/cert_wizard.png) * Select the `Base-64 encoded X.509 (.CER)` option, and click `Next`. ![ADFS export base64](/docs/assets/saml/adfs/cert_export_base64.png) * Browse the location where the certificate should be exported, and click `Next`. ![ADFS cert name](/docs/assets/saml/adfs/cert_name.png) * Click `Finish`. ![ADFS finish cert](/docs/assets/saml/adfs/cert_finish.png) * Click `OK`. ![ADFS cert OK](/docs/assets/saml/adfs/cert_export_ok.png) * Type the `SAML 2.0/WS-Federation` endpoint into the `Sign-on URL` field in the following format: `https://[ADFS-DOMAIN]/[WS-FEDERATION-URL-PATH]`. Then, paste the exported `Token Signing` certificate into the `X.509 Certificate` field. ![ConfigCat manual configuration](/docs/assets/saml/adfs/cc_manual_new.png) * Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) * Click on `Save`. ## 5. Sign In[​](#5-sign-in "Direct link to 5. Sign In") * Go to the [ConfigCat Log In](https://app.configcat.com) page, and click `COMPANY ACCOUNT - SAML`. ![ConfigCat SAML login](/docs/assets/saml/dashboard/saml_login.png) * Sign in with your company email address. ![ConfigCat SAML company login](/docs/assets/saml/dashboard/company_email.png) * ConfigCat will redirect you to the ADFS sign in page. Type your credentials, and click `Sign in`. ![ADFS log in](/docs/assets/saml/adfs/login.png) * You should be redirected to ConfigCat signed in with your company account. ## 6. Next Steps[​](#6-next-steps "Direct link to 6. Next Steps") * Configure the [auto-assignment of users](https://configcat.com/docs/advanced/team-management/auto-assign-users.md). --- # Source: https://configcat.com/docs/glossary/alpha-testing.md # Alpha Testing - The Unsung Hero of Product Development Copy page ## Introduction[​](#introduction "Direct link to Introduction") In the vast world of software development, testing plays a pivotal role in ensuring that products not only function as intended but also provide a seamless user experience. Among the various testing methodologies, alpha testing often stands out as a critical early-stage evaluation process. Let's delve into the nuances of alpha testing and understand its significance in the product development lifecycle. ## What is Alpha Testing?[​](#what-is-alpha-testing "Direct link to What is Alpha Testing?") Alpha testing is an in-house testing methodology conducted to identify bugs and issues before a product is released to a select group of external users. Typically performed by developers or QA teams, this type of testing is done in a controlled environment and aims to mimic real-world scenarios to ensure the software's functionality and reliability. ## The Objectives of Alpha Testing[​](#the-objectives-of-alpha-testing "Direct link to The Objectives of Alpha Testing") * **Bug Identification**: Detecting and addressing glitches, errors, and other issues. * **Functionality Verification**: Ensuring all features work as intended. * **Usability Assessment**: Evaluating the product's user-friendliness and overall experience. * **Performance Evaluation**: Checking the software's response times, load times, and overall efficiency. ## The Alpha Testing Process[​](#the-alpha-testing-process "Direct link to The Alpha Testing Process") * **Planning**: Setting the scope, objectives, and timelines for the test. * **Environment Setup**: Creating a controlled environment that simulates real-world usage. * **Test Execution**: Running a series of tests, both manual and automated, to evaluate different aspects of the software. * **Feedback Collection**: Gathering insights and observations from the testing team. * **Issue Resolution**: Addressing and rectifying identified problems before moving to the next testing phase. ## Why Alpha Testing is Crucial[​](#why-alpha-testing-is-crucial "Direct link to Why Alpha Testing is Crucial") * **Early Detection**: Catching issues early on can save time, effort, and resources in the later stages of development. * **Internal Feedback**: Gaining valuable insights from the team members who are familiar with the product's objectives and design. * **Risk Mitigation**: Reducing the chances of major issues appearing in subsequent testing phases or post-launch. * **Enhanced User Experience**: Ensuring that the end-users get a product that is polished, functional, and user-friendly. ## Challenges in Alpha Testing and Solutions[​](#challenges-in-alpha-testing-and-solutions "Direct link to Challenges in Alpha Testing and Solutions") * **Limited Perspective**: Being an internal process, alpha testing might miss issues that external users might encounter. Solution: Diverse testing teams and scenario simulations. * **Environment Limitations**: The controlled environment might not perfectly mimic all real-world scenarios. Solution: Use of virtual machines and diverse testing tools. * **Feedback Management**: Handling and prioritizing the feedback can be challenging. Solution: Use of feedback management tools and regular team sync-ups. ## Conclusion[​](#conclusion "Direct link to Conclusion") Alpha testing, while often overshadowed by its successor, beta testing, holds immense value in the software development process. By ensuring that a product is rigorously tested in its early stages, developers can pave the way for smoother subsequent testing phases and, ultimately, a successful product launch. As the adage goes, "Well begun is half done," and alpha testing ensures that software development begins on the right foot. --- # Source: https://configcat.com/docs/integrations/amplitude.md # Amplitude - Add feature flag changes to your charts Copy page ## Overview[​](#overview "Direct link to Overview") There are two available integration opportunities between ConfigCat and Amplitude: * [Monitoring your feature flag change events in Amplitude with Annotations](#annotations) * [Sending feature flag evaluation analytics to Amplitude Experiments](#experiments) ## Monitoring your feature flag change events in Amplitude with Annotations[​](#annotations "Direct link to Monitoring your feature flag change events in Amplitude with Annotations") Every feature flag change in ConfigCat is annotated on the Amplitude charts as a vertical line and some details are added automatically about the change. ![amplitude\_chart](/docs/assets/amplitude_chart.png) ### Installation[​](#installation "Direct link to Installation") 1. Have an [Amplitude subscription.](https://www.amplitude.com/) 2. Get an [Amplitude API Key and Secret Key.](https://www.docs.developers.amplitude.com/analytics/find-api-credentials/) ![amplitude\_apikey\_secretkey](/docs/assets/amplitude_apikey_secretkey.png) 3. Open the [integrations tab](https://app.configcat.com/product/integrations) on ConfigCat Dashboard. 4. Click on Amplitude's **Connect** button and set your Amplitude API key and Secret key. 5. You're all set. Go ahead and make some changes on your feature flags, then check your charts in Amplitude. ### Un-installation[​](#un-installation "Direct link to Un-installation") 1. Open the [integrations tab](https://app.configcat.com/product/integrations) on ConfigCat Dashboard. 2. Click on Amplitude's **Connected** button. 3. Select the connection from the **Connected** dropdown. 4. Click the **Disconnect** button in the edit dialog. 5. Click **Yes** in the confirmation dialog. ### Chart Annotation[​](#chart-annotation "Direct link to Chart Annotation") Every annotation sent to Amplitude by ConfigCat has: * **Name:** A brief summary of the change. * **Description:** A direct link to the Product/Config/Environment of the feature flag in ConfigCat. ![amplitude\_annotation](/docs/assets/amplitude_annotation.png) ## Sending feature flag evaluation analytics to Amplitude Experiments[​](#experiments "Direct link to Sending feature flag evaluation analytics to Amplitude Experiments") Ensures that feature flag evaluations are logged into [Amplitude Experiments](https://amplitude.com/docs/experiment/). With this integration, you can have advanced analytics about your feature flag usages, A/B test results. ### Setup[​](#setup "Direct link to Setup") 1. **Install SDKs:** Add both the ConfigCat SDK and Amplitude SDK to your application. 2. **Configure SDKs:** * **ConfigCat SDK:** Initialize with your ConfigCat SDK key. * **Amplitude SDK:** Set up with your Amplitude ApiKey. 3. **Integrate Feature Flag Evaluations:** * During the initialization of the ConfigCat SDK, subscribe to the `flagEvaluated` hook. * Send feature flag evaluation data to Amplitude using the `$exposure` event name. Include the following parameters: * `flag_key`: the feature flag's key. * `variant`: the evaluated feature flag's value or variation ID * `variation_id` (optional): the evaluated feature flag's variation ID * You can use the [Identify API](https://www.docs.developers.amplitude.com/analytics/apis/identify-api/) in Amplitude to enrich all your events with feature flag metadata. This way you can easily group/filter your existing Amplitude events by feature flag evaluations. Code samples: * JavaScript, Node, SSR * React * Python * Go * Java * Android * Swift (iOS) * Other languages ```js const configCatClient = configcat.getClient("#YOUR_SDK_KEY", PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', evaluationDetails => { // Send an `$exposure` event. amplitude.track('$exposure', { 'flag_key': evaluationDetails.key, 'variant': evaluationDetails.value, 'variation_id': evaluationDetails.variationId }); // Use the identify API. const identifyEvent = new amplitude.Identify(); identifyEvent.set("configcat_" + evaluationDetails.key, evaluationDetails.value); amplitude.identify(identifyEvent); }), }); ``` ```tsx hooks.on('flagEvaluated', evaluationDetails => { // Send an `$exposure` event. amplitude.track('$exposure', { 'flag_key': evaluationDetails.key, 'variant': evaluationDetails.value, 'variation_id': evaluationDetails.variationId }); // Use the identify API. const identifyEvent = new amplitude.Identify(); identifyEvent.set("configcat_" + evaluationDetails.key, evaluationDetails.value); amplitude.identify(identifyEvent); }), }} > ``` ```python def on_flag_evaluated(evaluation_details): # Send an `$exposure` event. amplitude.track( BaseEvent( event_type="$exposure", user_id=evaluation_details.user.get_identifier(), event_properties={ "flag_key": evaluation_details.key, "variant": evaluation_details.value, "variation_id": evaluation_details.variation_id } )) # Use the identify API. identify_obj=Identify() identify_obj.set(f'configcat_{evaluationDetails.key}', evaluation_details.value) amplitude.identify(identify_obj, EventOptions(user_id=evaluation_details.user.get_identifier())) pass client = configcatclient.get('#YOUR-SDK-KEY#', ConfigCatOptions( hooks=Hooks(on_flag_evaluated=on_flag_evaluated) ) ) ``` ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", Hooks: &configcat.Hooks{OnFlagEvaluated: func(details *configcat.EvaluationDetails) { // Send an `$exposure` event. amplitude.Track(amplitude.Event{ UserID: details.Data.User.(*configcat.UserData).Identifier, EventType: "$exposure", EventProperties: map[string]interface{}{ "flag_key": details.Data.Key, "variant": details.Value, "variation_id": details.Data.VariationID, }, }) // Use the identify API. identifyObj := amplitude.Identify{} identifyObj.Set("configcat_" + details.Data.Key, details.Value) amplitude.Identify(identifyObj, amplitude.EventOptions{UserID: details.Data.User.(*configcat.UserData).Identifier}) }}}) ``` ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.hooks().addOnFlagEvaluated(details -> { // Send an `$exposure` event. JSONObject eventProps = new JSONObject(); eventProps.put("flag_key", details.getKey()); eventProps.put("variant", details.getValue()); eventProps.put("variation_id", details.getVariationId()); Event event = new Event("$exposure", details.getUser().getIdentifier()); amplitude.logEvent(event); // Use the identify API. JSONObject userProps = new JSONObject(); userProps.put("configcat_" + details.getKey(), details.getValue()); Event updateUser = new Event("$identify", details.getUser().getIdentifier()); updateUser.userProperties = userProps; amplitude.logEvent(event); }); }); ``` ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.hooks().addOnFlagEvaluated(details -> { // Send an `$exposure` event. amplitude.track( "$exposure", mutableMapOf( "flag_key" to details.getKey(), "variant" to details.getValue(), "variation_id" to details.getVariationId() )) // Use the identify API. val identify = Identify() identify.set("configcat_" + details.getKey(), details.getValue()) }); }); ``` ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.hooks.addOnFlagEvaluated { details in // Send an `$exposure` event. let event = BaseEvent( eventType: "$exposure", eventProperties: [ "flag_key": details.key, "variant": details.value, "variation_id": details.variationId ?? "" ] ) // Use the identify API. let identify = Identify() identify.set(property: "configcat_" + details.key, value: details.value) amplitude.identify(identify: identify) } } ``` While our documentation primarily provides code examples for languages that Amplitude natively supports and has an official SDK, you can integrate with other languages by sending an event to Amplitude with a third-party SDK or with using the [Amplitude's Upload request API](https://www.docs.developers.amplitude.com/analytics/apis/http-v2-api/#upload-request). 1. **Subscribe to the FlagEvaluated hook** in the ConfigCat SDK. 2. **Send an event to Amplitude** using the `$exposure` event name. Include the following event properties: * `flag_key`: the feature flag's key from the FlagEvaluated hook's EvaluationDetails * `variant`: the evaluated feature flag's value or the variationId from the FlagEvaluated hook's EvaluationDetails * `variation_id`: the evaluated feature flag's value or the variationId from the FlagEvaluated hook's EvaluationDetails * `user_id` (optional): in case you are using the tracking in a backend component or you don't identify all your event sendings to Amplitude with user details, you have to send the `user_id` property as well to identify your user. You can use the User object's Identifier property from the FlagEvaluated hook or a value that best describes your user. note For Text feature flags with lengthy values (e.g., JSON), send the `variationId` instead of the `value` as the `variant` to Amplitude. The `variationId` is a hashed version of the feature flag value, accessible on the ConfigCat Dashboard by enabling the *Show VariationIDs to support A/B testing* setting. Learn more [here](https://app.configcat.com/product/preferences). 4. Deploy your application and wait for feature flag evaluations to happen so Experiments in Amplitude could be populated. ### Usage with Experiments[​](#usage-with-experiments "Direct link to Usage with Experiments") Check your Experiments page in Amplitude and select your feature flag as the Experiment. ### Usage with custom chart[​](#usage-with-custom-chart "Direct link to Usage with custom chart") If you don't have access to the Experiments feature in Amplitude, you can create a custom chart based on the `Exposure` event. You can filter for your feature flag keys with the `Flag Key` property and visualize the different variants by using the `Variant` property as a Breakdown. Example: ![Amplitude custom chart](/docs/assets/amplitude/customchart.png) ### Usage with enriched user properties for your custom events.[​](#usage-with-enriched-user-properties-for-your-custom-events "Direct link to Usage with enriched user properties for your custom events.") If you use the [Identify API](https://www.docs.developers.amplitude.com/analytics/apis/identify-api/) approach, you'll be able to use the feature flag evaluation data in your current reports. You can Group Segments by your feature flag evaluations: ![Amplitude chart with enriched data](/docs/assets/amplitude/enriched.png) ## Useful Resources[​](#useful-resources "Direct link to Useful Resources") * [A/B Testing in Android Kotlin with ConfigCat and Amplitude - Blog post](https://configcat.com/blog/2023/06/09/how-to-ab-test-kotlin/) * [Discover User Insights with Amplitude and ConfigCat - Blog post](https://configcat.com/blog/2024/09/24/user-insights-amplitude-configcat/) * [A/B testing in React with Amplitude and ConfigCat - Blog post](https://configcat.com/blog/2022/05/18/measuring-the-impact-of-a-test-variation-in-react/) * [A/B Testing in iOS with Feature Flags and Amplitude](https://configcat.com/blog/2023/01/24/how-to-implement-ab-testing-in-ios/) * [ConfigCat Integrations API](https://configcat.com/docs/api/reference/integrations/) --- # Source: https://configcat.com/docs/sdk-reference/android.md # Android (Java) SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/android-sdk.svg?style=social)](https://github.com/configcat/android-sdk/stargazers) [![Android CI](https://github.com/configcat/android-sdk/actions/workflows/android-ci.yml/badge.svg?branch=master)](https://github.com/configcat/android-sdk/actions/workflows/android-ci.yml) [![Maven Central](https://img.shields.io/maven-central/v/com.configcat/configcat-android-client)](https://central.sonatype.com/artifact/com.configcat/configcat-android-client) [![Javadocs](https://javadoc.io/badge/com.configcat/configcat-android-client.svg)](https://javadoc.io/doc/com.configcat/configcat-android-client) [![Coverage Status](https://img.shields.io/sonar/coverage/configcat_android-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_android-sdk) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=configcat_android-sdk\&metric=alert_status)](https://sonarcloud.io/dashboard?id=configcat_android-sdk) info This SDK is mainly for Java-based Android applications. For a more modern Android development experience, check our [Kotlin Multiplatform SDK](https://configcat.com/docs/sdk-reference/kotlin.md). [ConfigCat Android (Java) SDK on GitHub](https://github.com/configcat/android-sdk) ### Compatibility[​](#compatibility "Direct link to Compatibility") The minimum supported Android SDK version is 21 (Lollipop). ### R8 (ProGuard)[​](#r8-proguard "Direct link to R8 (ProGuard)") When you use R8 or ProGuard, the aar artifact automatically applies the [included rules](https://github.com/configcat/android-sdk/blob/master/configcat-proguard-rules.pro) for the SDK. ## Getting Started[​](#getting-started "Direct link to Getting Started") ### 1. Add the ConfigCat SDK to your project[​](#1-add-the-configcat-sdk-to-your-project "Direct link to 1. Add the ConfigCat SDK to your project") build.gradle ```groovy dependencies { implementation 'com.configcat:configcat-android-client:10.+' } ``` ### 2. Import the ConfigCat SDK[​](#2-import-the-configcat-sdk "Direct link to 2. Import the ConfigCat SDK") ```java import com.configcat.*; ``` ### 3. Create the *ConfigCat* client with your *SDK Key*[​](#3-create-the-configcat-client-with-your-sdk-key "Direct link to 3-create-the-configcat-client-with-your-sdk-key") ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); ``` ### 4. Get your setting value[​](#4-get-your-setting-value "Direct link to 4. Get your setting value") ```java boolean isMyAwesomeFeatureEnabled = client.getValue(Boolean.class, "", false); if (isMyAwesomeFeatureEnabled) { doTheNewThing(); } else { doTheOldThing(); } // Or asynchronously client.getValueAsync(Boolean.class, "", false) .thenAccept(isMyAwesomeFeatureEnabled -> { if (isMyAwesomeFeatureEnabled) { doTheNewThing(); } else { doTheOldThing(); } }); ``` ### 5. Stop *ConfigCat* client[​](#5-stop-configcat-client "Direct link to 5-stop-configcat-client") You can safely shut down all clients at once or individually and release all associated resources on application exit. ```java ConfigCatClient.closeAll(); // closes all clients client.close(); // closes a specific client ``` ## Creating the *ConfigCat Client*[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `ConfigCatClient.get("#YOUR-SDK-KEY#")` returns a client with default options. ### Customizing the *ConfigCat Client*[​](#customizing-the-configcat-client "Direct link to customizing-the-configcat-client") To customize the SDK's behavior, you can pass an additional `Consumer` parameter to the `get()` static factory method where the `Options` class is used to set up the *ConfigCat Client*. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.pollingMode(PollingModes.autoPoll()); options.logLevel(LogLevel.INFO); }); ``` These are the available options on the `Options` class: | Options | Description | | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataGovernance(DataGovernance)` | Optional, defaults to `Global`. Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `Global`, `EuOnly`. | | `baseUrl(string)` | Optional, sets the CDN base url (forward proxy, dedicated subscription) from where the sdk will download the config JSON. | | `httpClient(OkHttpClient)` | Optional, sets the underlying `OkHttpClient` used to download the feature flags and settings over HTTP. [More about the HTTP Client](#httpclient). | | `cache(ConfigCache)` | Optional, sets a custom cache implementation for the client. [More about cache](#custom-cache). | | `pollingMode(PollingMode)` | Optional, sets the polling mode for the client. [More about polling modes](#polling-modes). | | `logLevel(LogLevel)` | Optional, defaults to `WARNING`. Sets the internal log level. [More about logging](#logging). | | `flagOverrides(OverrideDataSource, OverrideBehaviour)` | Optional, sets the local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | `defaultUser(User)` | Optional, sets the default user. [More about default user](#default-user). | | `offline(boolean)` | Optional, defaults to `false`. Indicates whether the SDK should be initialized in offline mode. [More about offline mode](#online--offline-mode). | | `hooks()` | Optional, used to subscribe events that the SDK sends in specific scenarios. [More about hooks](#hooks). | | `logFilter(LogFilterFunction)` | Optional, sets a custom log filter. [More about log filtering](#log-filtering). | caution We strongly recommend you to use the `ConfigCatClient` as a Singleton object in your application. The `ConfigCatClient.get("#YOUR-SDK-KEY#")` static factory method constructs singleton client instances for your SDK keys. These clients can be closed all at once with the `ConfigCatClient.closeAll()` method or individually with `client.close()`. ## Anatomy of `getValue()`[​](#anatomy-of-getvalue "Direct link to anatomy-of-getvalue") | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `classOfT` | **REQUIRED.** The type of the setting. | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | ```java boolean value = client.getValue( Boolean.class, // Setting type "keyOfMySetting", // Setting Key User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"), // Optional User Object false // Default value ); ``` caution It is important to provide an argument for the `classOfT` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | Type parameter `T` | | -------------- | --------------------- | | On/Off Toggle | `boolean` / `Boolean` | | Text | `String` | | Whole Number | `int` / `Integer` | | Decimal Number | `double` / `Double` | It's important to note that providing any other type for the type parameter will result in an `IllegalArgumentException`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `classOfT` | **REQUIRED.** The type of the setting. | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | ```java client.getValueAsync( Boolean.class, // Setting type "keyOfMySetting", // Setting Key User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"), // Optional User Object false // Default value ).thenAccept(isMyAwesomeFeatureEnabled -> { if (isMyAwesomeFeatureEnabled) { doTheNewThing(); } else { doTheOldThing(); } }); ``` caution It is important to provide an argument for the `classOfT` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. ## Anatomy of `getValueDetails()`[​](#anatomy-of-getvaluedetails "Direct link to anatomy-of-getvaluedetails") `getValueDetails()` is similar to `getValue()` but instead of returning the evaluated value only, it gives more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `classOfT` | **REQUIRED.** The type of the setting. | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | ```java EvaluationDetails details = client.getValueDetails( Boolean.class, // Setting type "keyOfMySetting", // Setting Key User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"), // Optional User Object false // Default value ); // Or asynchronously client.getValueDetailsAsync( Boolean.class, // Setting type "keyOfMySetting", // Setting Key User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"), // Optional User Object false // Default value ).thenAccept(details -> { // Use the details result }); ``` caution It is important to provide an argument for the `classOfT` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The details result contains the following information: | Property | Type | Description | | -------------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `getValue()` | `boolean` / `String` / `int` / `double` | The evaluated value of the feature flag or setting. | | `getKey()` | `String` | The key of the evaluated feature flag or setting. | | `isDefaultValue()` | `boolean` | True when the default value passed to `getValueDetails()` is returned due to an error. | | `getError()` | `String` | In case of an error, this property contains the error message. | | `getUser()` | `User` | The User Object that was used for evaluation. | | `getMatchedPercentageOption()` | `PercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `getMatchedTargetingRule()` | `TargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `getFetchTimeUnixMilliseconds()` | `long` | The last download time of the current config in unix milliseconds format. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. ```java User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"); // Optional User Object ``` ```java User user = User.newBuilder().build("john@example.com"); ``` ### Customized User Object creation[​](#customized-user-object-creation "Direct link to Customized User Object creation") | Builder options | Description | | --------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier()` | **REQUIRED.** Unique identifier of a user in your application. Can be any value, even an email address. | | `email()` | Optional parameter for easier Targeting Rule definitions. | | `country()` | Optional parameter for easier Targeting Rule definitions. | | `custom()` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. e.g. User role, Subscription type. | ```java java.util.Map customAttributes = new java.util.HashMap(); customAttributes.put("SubscriptionType", "Pro"); customAttributes.put("UserRole", "Admin"); User user = User.newBuilder() .email("john@example.com") .country("United Kingdom") .custom(customAttributes) .build("#UNIQUE-USER-IDENTIFIER#"); // UserID ``` The `Custom` dictionary also allows attribute values other than `String` values: ```java java.util.Map customAttributes = new java.util.HashMap(); customAttributes.put("Rating", 4.5); customAttributes.put("RegisteredAt", new Date("2023-11-22 12:34:56 +00:00")); customAttributes.put("Roles", new String[]{"Role1", "Role2"}); User user = User.newBuilder() .email("john@example.com") .country("United Kingdom") .custom(customAttributes) .build("#UNIQUE-USER-IDENTIFIER#"); ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `String` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `String` values, * all other values are automatically converted to `String` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `String` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `Double` values and all other numeric values which can safely be converted to `Double`, * accept `String` values containing a properly formatted, valid `Double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `Double` values representing a second-based Unix timestamp and all other numeric values which can safely be converted to `Double`, * accept `String` values containing a properly formatted, valid `Double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays and list of `String`, * accept `String` values containing a valid JSON string which can be deserialized to an array of `String`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") There's an option to set a default User Object that will be used at feature flag and setting evaluation. It can be useful when your application has a single user only, or rarely switches users. You can set the default User Object either on SDK initialization: ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.defaultUser(User.newBuilder().build("john@example.com")); }); ``` or with the `setDefaultUser()` method of the ConfigCat client. ```java client.setDefaultUser(User.newBuilder().build("john@example.com")); ``` Whenever the `getValue[Async]()`, `getValueDetails[Async]()`, or `getAllValues[Async]()` methods are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.defaultUser(User.newBuilder().build("john@example.com")); }); // The default user will be used at the evaluation process. boolean value = client.getValue(Boolean.class, "keyOfMySetting", false); ``` When the `user` parameter is specified on the requesting method, it takes precedence over the default user. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.defaultUser(User.newBuilder().build("john@example.com")); }); User otherUser = User.newBuilder().build("brian@example.com"); // otherUser will be used at the evaluation process. boolean value = client.getValue(Boolean.class, "keyOfMySetting", otherUser, false); ``` For deleting the default user, you can do the following: ```java client.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValue()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle.
[More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the the `autoPollIntervalInSeconds` option parameter of the `PollingModes.autoPoll()` to change the polling interval. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.pollingMode(PollingModes.autoPoll(60 /* polling interval in seconds */)); }); ``` Available options: | Option Parameter | Description | Default | | --------------------------- | --------------------------------------------------------------------------------------------------- | ------- | | `autoPollIntervalInSeconds` | Polling interval. | 60 | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5 | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValue()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValue()` will return the setting value after the cache is updated. Use the `cacheRefreshIntervalInSeconds` parameter of the `PollingModes.lazyLoad()` to set cache lifetime. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.pollingMode(PollingModes.lazyLoad(60 /* the cache will expire in 120 seconds */)); }); ``` Available options: | Option Parameter | Description | Default | | ------------------------------- | ----------- | ------- | | `cacheRefreshIntervalInSeconds` | Cache TTL. | 60 | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefresh()` is your application's responsibility. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.pollingMode(PollingModes.manualPoll()); }); client.forceRefresh(); ``` > `getValue()` returns `defaultValue` if the cache is empty. Call `forceRefresh()` to update the cache. ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `onClientReady(ClientCacheState)`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after instantiation. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `ClientCacheState` argument. * `onConfigChanged(Map)`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `onFlagEvaluated(EvaluationDetails)`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetails()`](#anatomy-of-getvaluedetails). * `onError(String)`: This event is emitted when an error occurs within the client. You can subscribe to these events either on SDK initialization: ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.hooks().addOnFlagEvaluated(details -> { /* handle the event */ }); }); ``` or with the `getHooks()` property of the ConfigCat client: ```java client.getHooks().addOnFlagEvaluated(details -> { /* handle the event */ }); ``` ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases when you'd want to prevent the SDK from making HTTP calls, you can put it in offline mode: ```java client.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To put the SDK back in online mode, you can do the following: ```java client.setOnline(); ``` > With `client.isOffline()` you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LOCAL_ONLY`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LOCAL_OVER_REMOTE`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.REMOTE_OVER_LOCAL`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can load your feature flag & setting overrides from a `Map` structure. ```java Map map = new HashMap<>(); map.put("enabledFeature", true); map.put("disabledFeature", false); map.put("intSetting", 5); map.put("doubleSetting", 3.14); map.put("stringSetting", "test"); ConfigCatClient client = ConfigCatClient.get("localhost", options -> { options.flagOverrides(OverrideDataSource.map(map), OverrideBehaviour.LOCAL_ONLY); }); ``` ## `getAllKeys()`, `getAllKeysAsync()`[​](#getallkeys-getallkeysasync "Direct link to getallkeys-getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeys()` or `getAllKeysAsync()` method of the `ConfigCatClient`. ```java ConfigCatClient client = new ConfigCatClient("#YOUR-SDK-KEY#"); java.util.Collection keys = client.getAllKeys(); ``` ```java ConfigCatClient client = new ConfigCatClient("#YOUR-SDK-KEY#"); client.getAllKeysAsync().thenAccept(keys -> { // use the keys }); ``` ## `getAllValues()`, `getAllValuesAsync()`[​](#getallvalues-getallvaluesasync "Direct link to getallvalues-getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a User Object is optional. ```java ConfigCatClient client = new ConfigCatClient("#YOUR-SDK-KEY#"); Map settingValues = client.getAllValues(); // invoke with User Object User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#") Map settingValuesTargeting = client.getAllValues(user); ``` ```java ConfigCatClient client = new ConfigCatClient("#YOUR-SDK-KEY#"); client.getAllValuesAsync().thenAccept(settingValues -> { }); // invoke with User Object User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#") client.getAllValuesAsync(user).thenAccept(settingValuesTargeting -> { }); ``` ## `getAllValueDetails()`, `getAllValueDetailsAsync()`[​](#getallvaluedetails-getallvaluedetailsasync "Direct link to getallvaluedetails-getallvaluedetailsasync") Evaluates and returns the detailed values of all feature flags and settings. Passing a User Object is optional. ```java User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"); ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); List> allValueDetails = client.getAllValueDetails(user); ``` ```java User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"); ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); client.getAllValueDetailsAsync(user).thenAccept(allValueDetails -> { }); ``` ## Cache[​](#cache "Direct link to Cache") The SDK by default uses a memory-only cache. If you want to change the default behavior, you can either use the built-in `SharedPreferencesCache` or your custom cache implementation. The `SharedPreferencesCache` implementation uses the Android `SharedPreferences` to store the downloaded `config JSON`. `SharedPreferencesCache` has a dependency on `android.content.Context`, so it won't be enabled by default. The cache can be explicitly set by providing an appropriate `Context`. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.cache(new SharedPreferencesCache(getApplicationContext())); // Use ConfigCat's shared preferences cache. }); ``` ### Custom cache[​](#custom-cache "Direct link to Custom cache") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can subclass the [`ConfigCache`](https://github.com/configcat/android-sdk/blob/master/src/main/java/com/configcat/ConfigCache.java) abstract class and call the `cache` method with your implementation in the setup callback of `ConfigCatClient.get`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```java public class MyCustomCache extends ConfigCache { @Override public String read(String key) { // here you have to return with the cached value } @Override public void write(String key, String value) { // here you have to store the new value in the cache } } ``` Then use your custom cache implementation: ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.cache(new MyCustomCache()); // inject your custom cache }); ``` info The Android SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## HttpClient[​](#httpclient "Direct link to HttpClient") The ConfigCat SDK internally uses an [OkHttpClient](https://github.com/square/okhttp) instance to fetch the latest config JSON over HTTP. You have the option to override the internal Http client with your customized one. ### HTTP Proxy[​](#http-proxy "Direct link to HTTP Proxy") If your application runs behind a proxy you can do the following: ```java Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxyHost", proxyPort)); ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.httpClient(new OkHttpClient.Builder() .proxy(proxy) .build()); }); ``` ### HTTP Timeout[​](#http-timeout "Direct link to HTTP Timeout") You can set the maximum wait time for a ConfigCat HTTP response by using OkHttpClient's timeouts. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { .httpClient(new OkHttpClient.Builder() .readTimeout(2, TimeUnit.SECONDS) // set the read timeout to 2 seconds .build()); }); ``` OkHttpClient's default timeout is 10 seconds. > As the ConfigCatClient SDK maintains the whole lifetime of the internal http client, it's being closed simultaneously with the ConfigCatClient, refrain from closing the http client manually. ### Force refresh[​](#force-refresh "Direct link to Force refresh") Call the `forceRefresh()` method on the client to download the latest config JSON and update the cache. ## Logging[​](#logging "Direct link to Logging") The SDK uses the facade of [slf4j](https://www.slf4j.org) for logging, so you can use any of the slf4j implementation packages. You can change the verbosity of the logs by passing a `LogLevel` parameter to the ConfigCatClientBuilder's `logLevel` function. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.logLevel(LogLevel.INFO); }); ``` Available log levels: | Level | Description | | --------- | --------------------------------------------------------------------------------------- | | `NO_LOG` | Turn the logging off. | | `ERROR` | Only error level events are logged. | | `WARNING` | Default. Errors and Warnings are logged. | | `INFO` | Errors, Warnings and feature flag evaluation is logged. | | `DEBUG` | All of the above plus debug info is logged. Debug logs can be different for other SDKs. | Info level logging helps to inspect how a feature flag was evaluated: ```bash INFO com.configcat.ConfigCatClient - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"","Email":"configcat@example.com","Country":"US","SubscriptionType":"Pro","Role":"Admin","version":"1.0.0"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'False' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'True' => MATCH, applying rule Returning 'True'. ``` ### Logging Implementation[​](#logging-implementation "Direct link to Logging Implementation") You have the flexibility to use any slf4j implementation for logging with ConfigCat. However, some logger implementations may not display debug level messages by default. In these cases, you simply need to adjust the logger configuration to receive all log messages from the ConfigCat SDK. Examples for [android-logger](https://github.com/configcat/android-sdk/blob/master/samples/android-kotlin/app/src/android-logger.properties) and [logback](https://github.com/configcat/android-sdk/blob/master/samples/android-java/app/src/main/assets/logback.xml) are available under the [Sample Apps](#sample-apps) section. ### Log Filtering[​](#log-filtering "Direct link to Log Filtering") You can define a custom log filter by implementing the `LogFilterFunction` interface. The `apply` method will be called by the *ConfigCat SDK* each time a log event occurs (and the event passes the minimum log level specified by the `logLevel` option). That is, the `apply` method allows you to filter log events by `logLevel`, `eventId`, `message` or `exception`. The formatted message string can be obtained by calling `toString()` on the `message` parameter. If the `apply` method returns `true`, the event will be logged, otherwise it will be skipped. ```java // Filter out events with id 1001 from the log. LogFilterFunction filterLogFunction = ( LogLevel logLevel, int eventId, Object message, Throwable exception) -> eventId != 1001; ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> options.logFilter(filterLogFunction)); ``` caution Please make sure that your log filter logic doesn't perform heavy computation and doesn't block the executing thread. A complex or incorrectly implemented log filter can degrade the performance of the SDK. ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the ConfigCat SDK that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Sample App[​](#sample-apps "Direct link to Sample App") [Android App with auto polling and change listener](https://github.com/configcat/android-sdk/tree/master/samples) ## Guides[​](#guides "Direct link to Guides") See [this](https://configcat.com/blog/2022/01/24/feature-flags-in-android/) guide on how to use ConfigCat's Android SDK. ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat Android SDK's repository on GitHub](https://github.com/configcat/android-sdk) * [ConfigCat Android SDK's javadoc page](https://javadoc.io/doc/com.configcat/configcat-android-client) * [ConfigCat Android SDK on Maven Central](https://search.maven.org/artifact/com.configcat/configcat-android-client) --- # Source: https://configcat.com/docs/sdk-reference/openfeature/angular.md # Using ConfigCat's OpenFeature Provider in Angular Copy page ## Getting started[​](#getting-started "Direct link to Getting started") OpenFeature offers an [Angular SDK](https://github.com/open-feature/js-sdk/tree/main/packages/angular) to streamline the use of OpenFeature in Angular applications. This SDK is built on top of the [OpenFeature JavaScript Web SDK](https://github.com/open-feature/js-sdk/blob/main/packages/web). Since ConfigCat implements [a provider](https://configcat.com/docs/sdk-reference/openfeature/js.md) for the Web SDK, you can use ConfigCat with the OpenFeature Angular SDK, as explained below. ### 1. Install the Angular SDK and the ConfigCat provider[​](#1-install-the-angular-sdk-and-the-configcat-provider "Direct link to 1. Install the Angular SDK and the ConfigCat provider") ```bash npm i @openfeature/angular-sdk @openfeature/config-cat-web-provider ``` ### 2. Initialize the Angular SDK[​](#2-initialize-the-angular-sdk "Direct link to 2. Initialize the Angular SDK") The `ConfigCatWebProvider.create()` function takes the SDK key and an optional `options` argument containing additional configuration options for the underlying [ConfigCat client](https://configcat.com/docs/sdk-reference/js/browser.md#creating-the-configcat-client): * For applications using modules: ```ts import { NgModule } from '@angular/core'; import { BooleanFeatureFlagDirective, type EvaluationContext, OpenFeatureModule } from '@openfeature/angular-sdk'; import { ConfigCatWebProvider } from '@openfeature/config-cat-web-provider'; import { createConsoleLogger, LogLevel } from '@configcat/sdk'; const configCatProvider = ConfigCatWebProvider.create('#YOUR-SDK-KEY#', { // Specify options for the underlying ConfigCat client logger: createConsoleLogger(LogLevel.Info), setupHooks: (hooks) => hooks.on('clientReady', () => console.log('Client is ready!')), // ... }); // Set the initial context for your evaluations const initialContext: EvaluationContext = { targetingKey: 'user-1', admin: false }; @NgModule({ declarations: [ // ... ], imports: [ // ... OpenFeatureModule.forRoot({ provider: configCatProvider, context: initialContext }), // Alternatively, you can import the directive directly in your components BooleanFeatureFlagDirective ], exports: [ // Not needed if you import the directive directly in your components BooleanFeatureFlagDirective ], bootstrap: [/* ... */] }) export class AppModule { } ``` * For applications using standalone components: ```ts import { type ApplicationConfig, importProvidersFrom } from '@angular/core'; import { type EvaluationContext, OpenFeatureModule } from '@openfeature/angular-sdk'; import { ConfigCatWebProvider } from '@openfeature/config-cat-web-provider'; import { createConsoleLogger, LogLevel } from '@configcat/sdk'; const configCatProvider = ConfigCatWebProvider.create('#YOUR-SDK-KEY#', { // Specify options for the underlying ConfigCat client logger: createConsoleLogger(LogLevel.Info), setupHooks: (hooks) => hooks.on('clientReady', () => console.log('Client is ready!')), // ... }); // Set the initial context for your evaluations const initialContext: EvaluationContext = { targetingKey: 'user-1', admin: false }; export const appConfig: ApplicationConfig = { providers: [ // ... importProvidersFrom( OpenFeatureModule.forRoot({ provider: configCatProvider, context: initialContext }) ) ] }; ``` ### 3. Use your feature flag[​](#3-use-your-feature-flag "Direct link to 3. Use your feature flag") ```html
This is shown when the feature flag is enabled.
This is shown when the feature flag is disabled. This is shown when the feature flag is initializing. This is shown when the feature flag is reconciling. ``` ## Evaluation Context[​](#evaluation-context "Direct link to Evaluation Context") An [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context) in the OpenFeature specification is a container for arbitrary contextual data that can be used as a basis for feature flag evaluation. You can find [here](https://configcat.com/docs/sdk-reference/openfeature/js.md#evaluation-context) how the ConfigCat provider translates these evaluation contexts to ConfigCat [User Objects](https://configcat.com/docs/sdk-reference/js/browser.md#user-object). ## Advanced features[​](#advanced-features "Direct link to Advanced features") Read the documentation of the [OpenFeature Angular SDK](https://openfeature.dev/docs/reference/technologies/client/web/angular/) to learn more about the advanced capabilities of the SDK. ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat OpenFeature Provider's repository on GitHub](https://github.com/open-feature/js-sdk-contrib/tree/main/libs/providers/config-cat-web) * [ConfigCat OpenFeature Provider in NPM](https://www.npmjs.com/package/@openfeature/config-cat-web-provider) --- # Source: https://configcat.com/docs/api/reference/audit-logs.md # Audit logs Copy page Access audit log entries. ## [📄️ List Audit log items for Product](https://configcat.com/docs/api/reference/get-auditlogs.md) [This endpoint returns the list of Audit log items for a given Product](https://configcat.com/docs/api/reference/get-auditlogs.md) ## [📄️ List Deleted Settings](https://configcat.com/docs/api/reference/get-deleted-settings.md) [This endpoint returns the list of Feature Flags and Settings that were deleted from the given Config.](https://configcat.com/docs/api/reference/get-deleted-settings.md) ## [📄️ List Audit log items for Organization](https://configcat.com/docs/api/reference/get-organization-auditlogs.md) [This endpoint returns the list of Audit log items for a given Organization](https://configcat.com/docs/api/reference/get-organization-auditlogs.md) --- # Source: https://configcat.com/docs/advanced/team-management/saml/identity-providers/auth0.md # Auth0 Identity Provider Copy page Connect ConfigCat with Auth0 via SAML. ## Introduction[​](#introduction "Direct link to Introduction") Each SSO Identity Provider requires specific information to configure a SAML integration. The following guide will walk you through how you can connect ConfigCat with Auth0 as a SAML Identity Provider. ## 1. Create an Application in Auth0[​](#1-create-an-application-in-auth0 "Direct link to 1. Create an Application in Auth0") * Log in to [Auth0](https://auth0.com/auth/login), select `Applications` from the menu, then click `Create Application`. ![Auth0 applications](/docs/assets/saml/auth0/applications.png) * Enter a descriptive `Name`, select `Regular Web Applications`, then click `Create`. ![Auth0 app name](/docs/assets/saml/auth0/app_name.png) * Select the `Addons` tab, and click `SAML2`. ![Auth0 enable SAML](/docs/assets/saml/auth0/enable_saml.png) The next step will guide you on how to collect the information required for the appearing configuration dialog. ## 2. Configure SAML for the Auth0 Application[​](#2-configure-saml-for-the-auth0-application "Direct link to 2. Configure SAML for the Auth0 Application") * Open your organization's authentication settings on the [ConfigCat Dashboard](https://app.configcat.com/organization/authentication). ![ConfigCat authentication settings](/docs/assets/saml/dashboard/authentication.png) * Click `ADD SAML IDENTITY PROVIDER`. ![ConfigCat Add Identity Provider](/docs/assets/saml/dashboard/add_idp.png) * Give a name for your Identity Provider, and click `Create`. ![ConfigCat Name Identity Provider](/docs/assets/saml/dashboard/auth0_name.png) * From the next section of the dialog, copy the following values and paste them into the Auth0 configuration dialog. * `Entity ID` -> `"audience": ""` in the configuration JSON below. * `Assertion Consumer Service` -> `Application Callback URL` * For `Settings`, use the following JSON value: ```text { "audience": "", "signatureAlgorithm": "rsa-sha256", "nameIdentifierProbes": [ "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" ] } ``` ![ConfigCat ACS configuration](/docs/assets/saml/dashboard/acs_entity_id_1.png) ![Auth0 ACS configuration](/docs/assets/saml/auth0/auth0_acs_eid.png) * Click on `Save`. ## 3. Configure ConfigCat with SAML Details from Auth0[​](#3-configure-configcat-with-saml-details-from-auth0 "Direct link to 3. Configure ConfigCat with SAML Details from Auth0") You can choose one of the following options to configure ConfigCat with SAML Identity Provider metadata. * Metadata URL * Manual Configuration - Copy the URL of `Identity Provide metadata`. ![Auth0 metadata URL](/docs/assets/saml/auth0/metadata_url.png) - Paste the copied value into the `Metadata URL` field at ConfigCat. ![ConfigCat metadata URL](/docs/assets/saml/auth0/cc_metadata_url_new.png) - Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) - Click on `Save`. * Copy the value of `Identity Provider Login URL` and download the `Identity Provider Certificate`, then paste them into the Configuration dialog at ConfigCat. ![Auth0 manual configuration](/docs/assets/saml/auth0/manual.png)![ConfigCat manual configuration](/docs/assets/saml/auth0/cc_manual_new.png) * Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) * Click on `Save`. ## 4. Sign In[​](#4-sign-in "Direct link to 4. Sign In") * Go to the [ConfigCat Log In](https://app.configcat.com) page, and click `COMPANY ACCOUNT - SAML`. ![ConfigCat SAML login](/docs/assets/saml/dashboard/saml_login.png) * Sign in with your company email address assigned to the Auth0 application. ![ConfigCat SAML company login](/docs/assets/saml/dashboard/company_email.png) * ConfigCat will redirect you to Auth0's sign in page. Type your credentials, and click `Continue`. ![Auth0 login](/docs/assets/saml/auth0/login.png) * You should be redirected to ConfigCat signed in with your company account. ## 5. Next Steps[​](#5-next-steps "Direct link to 5. Next Steps") * Configure the [auto-assignment of users](https://configcat.com/docs/advanced/team-management/auto-assign-users.md). --- # Source: https://configcat.com/docs/advanced/team-management/auto-assign-users.md # Auto-assign Users Copy page All new users who sign up with a [verified email domain](https://configcat.com/docs/advanced/team-management/domain-verification.md) will be automatically added to your organization. Furthermore, you can also set which Organization roles / Product permissions they should get upon on-boarding. ## Steps to configure[​](#steps-to-configure "Direct link to Steps to configure") * Open your organization's authentication settings on the [ConfigCat Dashboard](https://app.configcat.com/organization/authentication). ![Authentication settings](/docs/assets/saml/dashboard/authentication.png) * Select the domain you want to configure, and click `RE-CONFIGURE` (or just `CONFIGURE` if you haven't configured it yet) under the `Auto-assign status`. ![Auto-assign configuration](/docs/assets/saml/dashboard/auto_assign_config_new.png) * In the dialog that appears, you can select which `Organization roles` and `Product permissions` should be assigned to the newly registered users. ![Auto-assign setup](/docs/assets/saml/dashboard/auto_assign_set_new.png) * When you are ready, just hit `Save`. --- # Source: https://configcat.com/docs/advanced/team-management/saml/identity-providers/azure-ad.md # Entra ID (Azure AD) Identity Provider Copy page Connect ConfigCat with Entra ID via SAML. ## Introduction[​](#introduction "Direct link to Introduction") Each SSO Identity Provider requires specific information to configure a SAML integration. The following guide will walk you through how you can connect ConfigCat with Entra ID as a SAML Identity Provider. ## 1. Create an Entra ID Enterprise Application[​](#1-create-an-entra-id-enterprise-application "Direct link to 1. Create an Entra ID Enterprise Application") * Log in to the [Azure Portal](https://portal.azure.com/), go to the `Entra ID` resource, and select `Enterprise applications`. ![Entra ID enterprise applications](/docs/assets/saml/azure-ad/eapplications.png) * Click on `New application`. ![Entra ID new application](/docs/assets/saml/azure-ad/new_app.png) * Click on `Create your own application`. ![Entra ID create own application](/docs/assets/saml/azure-ad/create_app.png) * Enter a descriptive `App name`, select the `Integrate any other application you don't find in the gallery (Non-gallery)` option, then click `Create`. ![Entra ID app name](/docs/assets/saml/azure-ad/app_name.png) * On the `Manage` section of the application, select `Single sign-on`, then select `SAML`. ![Entra ID enable SAML](/docs/assets/saml/azure-ad/enable_saml.png) The next step will guide you on how to collect the information required for Configuring SAML in the application. ## 2. Configure SAML for the Azure Enterprise Application[​](#2-configure-saml-for-the-azure-enterprise-application "Direct link to 2. Configure SAML for the Azure Enterprise Application") * Open your organization's authentication settings on the [ConfigCat Dashboard](https://app.configcat.com/organization/authentication). ![ConfigCat authentication settings](/docs/assets/saml/dashboard/authentication.png) * Click `ADD SAML IDENTITY PROVIDER`. ![ConfigCat Add Identity Provider](/docs/assets/saml/dashboard/add_idp.png) * Give a name for your Identity Provider, and click `Create`. ![ConfigCat Name Identity Provider](/docs/assets/saml/dashboard/aad_name.png) * From the next section of the dialog, copy the following values and paste them into the Enterprise application. * `Entity ID` -> `Identifier (Entity ID)` * `Assertion Consumer Service` -> `Reply URL (Assertion Consumer Service URL)` ![ConfigCat SAML configuration](/docs/assets/saml/dashboard/acs_entity_id_1.png) ![Entra ID URL configuration](/docs/assets/saml/azure-ad/saml_urls.png) ![Entra ID URLs](/docs/assets/saml/azure-ad/aad_acs_eid.png) ## 3. Configure ConfigCat with SAML Details from Azure[​](#3-configure-configcat-with-saml-details-from-azure "Direct link to 3. Configure ConfigCat with SAML Details from Azure") You can choose one of the following options to configure ConfigCat with SAML Identity Provider metadata. * Metadata URL * Manual Configuration - Copy the value of `App Federation Metadata Url`. ![Entra ID metadata URL](/docs/assets/saml/azure-ad/metadata_url.png) - Paste the copied value into the `Metadata URL` field at ConfigCat. ![ConfigCat Entra ID metadata URL](/docs/assets/saml/azure-ad/cc_metadata_new.png) - Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) - Click on `Save`. * Copy the value of `Login URL` and download the `Certificate (Base64)`, then paste them into the Configuration dialog at ConfigCat. ![Entra ID metadata login URL](/docs/assets/saml/azure-ad/metadata_logon.png)![Entra ID metadata certificate](/docs/assets/saml/azure-ad/metadata_cert.png)![ConfigCat Entra ID manual configuration](/docs/assets/saml/azure-ad/cc_manual_new.png) * Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) * Click on `Save`. ## 4. Assign Users to the Enterprise Application[​](#4-assign-users-to-the-enterprise-application "Direct link to 4. Assign Users to the Enterprise Application") To let users authenticate via SAML, you need to assign individual users or groups to the Enterprise application. * Select `Users and groups` on the `Manage` section of the menu. ![Entra ID users and groups](/docs/assets/saml/azure-ad/users_groups.png) * Click `Add user/group`, then select the users or groups you want to assign. ![Entra ID add user/group](/docs/assets/saml/azure-ad/add_users.png) ## 5. Sign In[​](#5-sign-in "Direct link to 5. Sign In") * Go to the [ConfigCat Log In](https://app.configcat.com) page, and click `COMPANY ACCOUNT - SAML`. ![ConfigCat SAML login](/docs/assets/saml/dashboard/saml_login.png) * Sign in with your company email address assigned to the Enterprise application. ![ConfigCat SAML company login](/docs/assets/saml/dashboard/company_email.png) * ConfigCat will redirect you to Microsoft's sign in page. Type your credentials for sign-in. ![Entra ID sign in page](/docs/assets/saml/azure-ad/login.png) * You should be redirected to ConfigCat signed in with your company account. ## 6. Next Steps[​](#6-next-steps "Direct link to 6. Next Steps") * Configure [User provisioning (SCIM)](https://configcat.com/docs/advanced/team-management/scim/scim-overview.md) * or configure the [auto-assignment of users](https://configcat.com/docs/advanced/team-management/auto-assign-users.md) if you don't want to provision your users with your Identity Provider. --- # Source: https://configcat.com/docs/advanced/code-references/azure-devops.md # Azure DevOps - Scan your source code for feature flags Copy page This section describes how to use the [ConfigCat CLI](https://configcat.com/docs/advanced/cli.md) in [Azure DevOps Pipelines](https://docs.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in Azure DevOps [Pipeline Variables](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables) with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![Azure secrets](/docs/assets/cli/scan/azure_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Create a new or open your existing `azure-pipelines.yml` file, and add the following [job](https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema#job) to your `jobs` definition. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml - job: configcat_scan_and_upload container: configcat/cli:azure-devops-2.4.2 pool: vmImage: ubuntu-latest steps: - checkout: self persistCredentials: true - script: configcat scan $(Build.Repository.LocalPath) --config-id=PASTE-YOUR-CONFIG-ID-HERE --repo=$(Build.Repository.Name) --branch=$(Build.SourceBranchName) --file-url-template="$(Build.Repository.Uri)?path={filePath}&version=GC{commitHash}&line={lineNumber}&lineStartColumn=1&lineEndColumn=1" --commit-url-template="$(Build.Repository.Uri)/commit/{commitHash}" --runner="ConfigCat Azure DevOps Job" --upload --non-interactive name: scan_repository env: CONFIGCAT_API_PASS: $(CONFIGCAT_API_PASS) CONFIGCAT_API_USER: $(CONFIGCAT_API_USER) ``` info If you are using a different VCS than Azure DevOps' Git, you should set the `--file-url-template` and `--commit-url-template` according to your VCS provider. 4. Commit & push your changes. Scan reports are uploaded for each branch of your repository that triggers the job. --- # Source: https://configcat.com/docs/glossary/beta-testing.md # Beta Testing - Navigating the Road to Market Readiness Copy page ## Introduction[​](#introduction "Direct link to Introduction") Beta testing stands as a critical milestone before a software product meets its audience. This phase is the trial test, bridging the gap between internal development and user experience. Let's explore the role of beta testing in software development and its significance in refining software products. ## What is Beta Testing in Software Development?[​](#what-is-beta-testing-in-software-development "Direct link to What is Beta Testing in Software Development?") Beta testing in software development involves releasing a near-complete version of the software to a selected group of external users. This phase follows alpha testing and is crucial for gathering feedback under real usage conditions to fine-tune the software before its official release. ## The Objectives of Beta Testing in Software Development[​](#the-objectives-of-beta-testing-in-software-development "Direct link to The Objectives of Beta Testing in Software Development") * **Gathering User Feedback**: Collecting insights about user experiences and preferences. * **Assessing Market Response**: Evaluating how the software is perceived and received in the market. * **Identifying Real-World Bugs**: Detecting issues that might have been missed during internal testing. * **Refinement for Market Launch**: Adjusting and improving the software based on user feedback. ## The Beta Testing Process in Software Development[​](#the-beta-testing-process-in-software-development "Direct link to The Beta Testing Process in Software Development") * **Selection of Beta Testers**: Recruiting a diverse and representative sample of the target user base. * **Distribution of Beta Version**: Providing the beta software to the chosen testers. * **Monitoring and Feedback Collection**: Observing user interactions and gathering structured feedback. * **Analysis and Iteration**: Analyzing user feedback to identify areas for improvement and implementing changes. * **Release Readiness Assessment**: Evaluating if the software is ready for public launch based on tester feedback. ## Why Beta Testing is Crucial in Software Development[​](#why-beta-testing-is-crucial-in-software-development "Direct link to Why Beta Testing is Crucial in Software Development") * **Insights from Real Users**: Obtaining feedback from actual users in varied real-world scenarios. * **Market Acceptance Evaluation**: Gauging the market's reaction and the software's readiness for launch. * **Enhancement of Software Quality**: Identifying and fixing bugs, and polishing features to improve overall quality. * **Building Early User Base**: Establishing an initial user community and fostering early adopter loyalty. ## Challenges in Beta Testing for Software and Solutions[​](#challenges-in-beta-testing-for-software-and-solutions "Direct link to Challenges in Beta Testing for Software and Solutions") * **Diverse User Scenarios**: Testers may have different usage patterns and environments. Solution: Carefully select a diverse group of beta testers. * **Handling Feedback Effectively**: Managing a large volume of feedback can be challenging. Solution: Implement structured feedback collection tools and clear guidelines. * **Maintaining Tester Engagement**: Keeping beta testers motivated and engaged throughout the process. Solution: Provide incentives for participation and maintain open, responsive communication channels. ## Conclusion[​](#conclusion "Direct link to Conclusion") Beta testing in software development is more than just a phase; it's a strategic approach to ensuring that the software not only functions but also resonates with its intended audience. It’s a vital step in the journey towards launching a software product that is not just functional, but also aligned with user expectations and market demands. Through beta testing, software developers can pave the way for a successful product launch, grounded in quality, user satisfaction, and market readiness. --- # Source: https://configcat.com/docs/advanced/code-references/bitbucket-pipe.md # Bitbucket Pipe - Scan your source code for feature flags Copy page This section describes how to use ConfigCat's [Bitbucket Pipe](https://bitbucket.org/product/features/pipelines/integrations?p=configcat/scan-repository-pipe) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. You can find more information about Bitbucket Pipelines [here](https://bitbucket.org/product/features/pipelines). ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in secure pipeline variables with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![Bitbucket Pipe secrets](/docs/assets/cli/scan/pipe_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Add the following snippet to the script section of your `bitbucket-pipelines.yml` file. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml - pipe: configcat/scan-repository-pipe:1.8.1 variables: CONFIG_ID: 'PASTE-YOUR-CONFIG-ID-HERE' # LINE_COUNT: '3' # optional # TIMEOUT: '1800' # optional # SUB_FOLDER: '/src' # optional # EXCLUDE_KEYS: > # optional # flag_key_to_exclude_1 # flag_key_to_exclude_2 # ALIAS_PATTERNS: (\w+) = :CC_KEY,const (\w+) = feature_flags\.enabled\(:CC_KEY\) # optional # USAGE_PATTERNS: feature_flags\.enabled\(:CC_KEY\) # VERBOSE: 'true' # optional ``` 4. Commit & push your changes. Scan reports are uploaded for each branch of your repository that triggers the job. ## Available Options[​](#available-options "Direct link to Available Options") | Parameter | Description | Required | Default | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------- | | `CONFIG_ID` | ID of the ConfigCat config to scan against. | ☑ | | | `CONFIGCAT_API_HOST` | ConfigCat Management API host. | | `api.configcat.com` | | `LINE_COUNT` | Context line count before and after the reference line. (min: 1, max: 10) | | 4 | | `TIMEOUT` | Scan timeout in seconds (default: 1800, min: 60). If the scan does not finish within this time, it is aborted. No partial results are returned. The command exits with a timeout error. | | 1800 | | `SUB_FOLDER` | Sub-folder to scan, relative to the repository root folder. | | | | `EXCLUDE_KEYS` | List of feature flag keys that must be excluded from the scan report. | | | | `ALIAS_PATTERNS` | Comma delimited list of custom regex patterns used to search for additional aliases. | | | | `USAGE_PATTERNS` | Comma delimited list of custom regex patterns that describe additional feature flag key usages. | | | | `VERBOSE` | Turns on detailed logging. | | false | --- # Source: https://configcat.com/docs/integrations/bitbucket.md # Bitbucket - Scan your code for feature flag usages Copy page ConfigCat's [Bitbucket Pipe](https://bitbucket.org/product/features/pipelines/integrations?p=configcat/scan-repository-pipe) has the ability to scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. This feature makes the elimination of the technical debt easier, as it can show which repositories reference your feature flags and settings in one centralized place on your [Dashboard](https://app.configcat.com). [Here](https://configcat.com/docs/advanced/code-references/overview.md) you can find more details about how this feature works. This section describes how to use ConfigCat's [Bitbucket Pipe](https://bitbucket.org/product/features/pipelines/integrations?p=configcat/scan-repository-pipe) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. You can find more information about Bitbucket Pipelines [here](https://bitbucket.org/product/features/pipelines). ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in secure pipeline variables with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![Bitbucket Pipe secrets](/docs/assets/cli/scan/pipe_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Add the following snippet to the script section of your `bitbucket-pipelines.yml` file. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml - pipe: configcat/scan-repository-pipe:1.8.1 variables: CONFIG_ID: 'PASTE-YOUR-CONFIG-ID-HERE' # LINE_COUNT: '3' # optional # TIMEOUT: '1800' # optional # SUB_FOLDER: '/src' # optional # EXCLUDE_KEYS: > # optional # flag_key_to_exclude_1 # flag_key_to_exclude_2 # ALIAS_PATTERNS: (\w+) = :CC_KEY,const (\w+) = feature_flags\.enabled\(:CC_KEY\) # optional # USAGE_PATTERNS: feature_flags\.enabled\(:CC_KEY\) # VERBOSE: 'true' # optional ``` 4. Commit & push your changes. Scan reports are uploaded for each branch of your repository that triggers the job. ## Available Options[​](#available-options "Direct link to Available Options") | Parameter | Description | Required | Default | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------- | | `CONFIG_ID` | ID of the ConfigCat config to scan against. | ☑ | | | `CONFIGCAT_API_HOST` | ConfigCat Management API host. | | `api.configcat.com` | | `LINE_COUNT` | Context line count before and after the reference line. (min: 1, max: 10) | | 4 | | `TIMEOUT` | Scan timeout in seconds (default: 1800, min: 60). If the scan does not finish within this time, it is aborted. No partial results are returned. The command exits with a timeout error. | | 1800 | | `SUB_FOLDER` | Sub-folder to scan, relative to the repository root folder. | | | | `EXCLUDE_KEYS` | List of feature flag keys that must be excluded from the scan report. | | | | `ALIAS_PATTERNS` | Comma delimited list of custom regex patterns used to search for additional aliases. | | | | `USAGE_PATTERNS` | Comma delimited list of custom regex patterns that describe additional feature flag key usages. | | | | `VERBOSE` | Turns on detailed logging. | | false | --- # Source: https://configcat.com/docs/advanced/code-references/bitrise-step.md # Bitrise - Scan your source code for feature flags Copy page This section describes how to use ConfigCat's [Bitrise Step](https://www.bitrise.io/integrations/steps/configcat-feature-flag-sync) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. [Bitrise](https://www.bitrise.io/) is full-featured mobile CI/CD platform. You can find more information about Bitrise Steps [here](https://devcenter.bitrise.io/en/steps-and-workflows/introduction-to-steps.html). ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in secure pipeline variables with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![Bitrise secrets](/docs/assets/cli/scan/bitrise_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Add the following step to the workflows section of your `bitrise.yml` file. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml - configcat-feature-flag-sync@0: inputs: - configcat_config_id: 'PASTE-YOUR-CONFIG-ID-HERE' # required # - line-count: 3 # optional # - sub-folder: 'src' # optional # - exclude-keys: > # optional # flag_key_to_exclude_1 # flag_key_to_exclude_2 # - alias-patterns: "(\w+) = :CC_KEY,const (\w+) = feature_flags\.enabled\(:CC_KEY\)" # optional # - usage-patterns: feature_flags\.enabled\(:CC_KEY\) # optional # - verbose: true # optional ``` 4. Commit & push your changes. Scan reports are uploaded for each branch of your repository that triggers the job. ## Available Options[​](#available-options "Direct link to Available Options") | Parameter | Description | Required | Default | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------- | | `configcat_config_id` | The [config ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id) tells the step which feature flags it should search for in your source code. | ☑ | | | `configcat_api_host` | ConfigCat Management API host. | | `api.configcat.com` | | `line_count` | Code snippet line count before and after the reference line. (min: 1, max: 10) | | 4 | | `sub_folder` | Sub-folder to scan, relative to the repository root folder. | | | | `exclude-keys` | List of feature flag keys that must be excluded from the scan report. | | | | `alias-patterns` | Comma delimited list of custom regex patterns used to search for additional aliases. | | | | `usage-patterns` | Comma delimited list of custom regex patterns that describe additional feature flag key usages. | | | | `verbose` | Turns on detailed logging. | | false | --- # Source: https://configcat.com/docs/integrations/bitrise.md # Bitrise - Scan your code for feature flag usages Copy page ConfigCat's [Bitrise Step](https://www.bitrise.io/integrations/steps/configcat-feature-flag-sync) has the ability to scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. This feature makes the elimination of the technical debt easier, as it can show which repositories reference your feature flags and settings in one centralized place on your [Dashboard](https://app.configcat.com). [Here](https://configcat.com/docs/advanced/code-references/overview.md) you can find more details about how this feature works. This section describes how to use ConfigCat's [Bitrise Step](https://www.bitrise.io/integrations/steps/configcat-feature-flag-sync) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. [Bitrise](https://www.bitrise.io/) is full-featured mobile CI/CD platform. You can find more information about Bitrise Steps [here](https://devcenter.bitrise.io/en/steps-and-workflows/introduction-to-steps.html). ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in secure pipeline variables with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![Bitrise secrets](/docs/assets/cli/scan/bitrise_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Add the following step to the workflows section of your `bitrise.yml` file. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml - configcat-feature-flag-sync@0: inputs: - configcat_config_id: 'PASTE-YOUR-CONFIG-ID-HERE' # required # - line-count: 3 # optional # - sub-folder: 'src' # optional # - exclude-keys: > # optional # flag_key_to_exclude_1 # flag_key_to_exclude_2 # - alias-patterns: "(\w+) = :CC_KEY,const (\w+) = feature_flags\.enabled\(:CC_KEY\)" # optional # - usage-patterns: feature_flags\.enabled\(:CC_KEY\) # optional # - verbose: true # optional ``` 4. Commit & push your changes. Scan reports are uploaded for each branch of your repository that triggers the job. ## Available Options[​](#available-options "Direct link to Available Options") | Parameter | Description | Required | Default | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------- | | `configcat_config_id` | The [config ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id) tells the step which feature flags it should search for in your source code. | ☑ | | | `configcat_api_host` | ConfigCat Management API host. | | `api.configcat.com` | | `line_count` | Code snippet line count before and after the reference line. (min: 1, max: 10) | | 4 | | `sub_folder` | Sub-folder to scan, relative to the repository root folder. | | | | `exclude-keys` | List of feature flag keys that must be excluded from the scan report. | | | | `alias-patterns` | Comma delimited list of custom regex patterns used to search for additional aliases. | | | | `usage-patterns` | Comma delimited list of custom regex patterns that describe additional feature flag key usages. | | | | `verbose` | Turns on detailed logging. | | false | --- # Source: https://configcat.com/docs/glossary/blue-green-deployment.md # Blue/Green Deployment - Streamlining Software Releases Copy page ## Introduction[​](#introduction "Direct link to Introduction") In the dynamic realm of software development, deploying updates without disrupting user experience is paramount. Blue/Green Deployment emerges as a strategic method that enables this seamless transition. Let's delve into its mechanics and recognize its significance in software deployment. ## What is Blue/Green Deployment?[​](#what-is-bluegreen-deployment "Direct link to What is Blue/Green Deployment?") Blue/Green Deployment is a strategy used to reduce downtime and risk by running two identical production environments. Simply put, the 'Blue' environment is the active one, while the 'Green' is a clone, ready to be switched over at any moment. This approach allows for testing in the production environment itself without affecting users. ## Objectives of Blue/Green Deployment[​](#objectives-of-bluegreen-deployment "Direct link to Objectives of Blue/Green Deployment") * **Minimal Downtime**: Achieve nearly zero downtime during deployments. * **Risk Reduction**: Mitigate risks associated with the release of new features or updates. * **Rapid Rollback**: Provide the ability to quickly revert to the previous version if issues arise post-deployment. * **Continuous Delivery**: Facilitate a smoother continuous delivery pipeline. ## The Blue/Green Deployment Process[​](#the-bluegreen-deployment-process "Direct link to The Blue/Green Deployment Process") * **Preparation**: Setting up two identical environments — Blue (current) and Green (new). * **Testing**: Validating the Green environment to ensure it's ready for live traffic. * **Routing Traffic**: Shifting user traffic from Blue to Green seamlessly. * **Monitoring**: Keeping a close watch on the Green environment for any issues. * **Finalization or Rollback**: If successful, decommission the Blue environment, or if problems are detected, revert traffic back to Blue. ## Why Blue/Green Deployment is Essential[​](#why-bluegreen-deployment-is-essential "Direct link to Why Blue/Green Deployment is Essential") * **Enhanced Reliability**: Increases the reliability of the deployment process. * **User Experience**: Ensures uninterrupted service to users during updates. * **Simplified Troubleshooting**: Allows easy identification and resolution of issues. * **Flexibility**: Offers flexibility in managing and scheduling deployments. ## Challenges in Blue/Green Deployment and Solutions[​](#challenges-in-bluegreen-deployment-and-solutions "Direct link to Challenges in Blue/Green Deployment and Solutions") * **Resource Intensiveness**: Requires duplicating the production environment. Solution: Efficient resource management and cloud-based solutions. * **Data Synchronization**: Keeping data in sync between Blue and Green environments. Solution: Robust data management strategies and tools. * **Complex Configuration**: Managing complex configurations during the switch. Solution: Automation tools and thorough planning. ## Conclusion[​](#conclusion "Direct link to Conclusion") Blue/Green Deployment serves as a cornerstone for modern software delivery, ensuring that updates and new features are rolled out smoothly, without disturbing the end-user experience. By integrating this strategy into deployment practices, organizations can enhance the reliability and efficiency of their software delivery process, ultimately leading to greater user satisfaction and business success. --- # Source: https://configcat.com/docs/sdk-reference/js/browser.md # Browser (JavaScript) SDK Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/js-unified-sdk.svg?style=social)](https://github.com/configcat/js-unified-sdk/stargazers) [![JS SDK CI](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml/badge.svg?branch=master)](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml) [![SonarCloud Coverage](https://img.shields.io/sonar/coverage/configcat_js-unified-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_js-unified-sdk) [![Known Vulnerabilities](https://snyk.io/test/github/configcat/js-unified-sdk/badge.svg?targetFile=package.json)](https://snyk.io/test/github/configcat/js-unified-sdk?targetFile=package.json) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=configcat_js-sdk\&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=configcat_js-sdk) [![JSDELIVR](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge)](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge) info This SDK supersedes the legacy [JavaScript SDK](https://configcat.com/docs/sdk-reference/js.md) and [JavaScript (SSR) SDK](https://configcat.com/docs/sdk-reference/js-ssr.md). It is suitable for the following types of browser applications: * Static HTML websites * Server-side rendered Multi-Page Applications (MPA), e.g. PHP, ASP.NET Core Razor Pages, Spring MVC, etc. * Client-side rendered Single-Page Applications (SPA), e.g. Angular, React, Vue.js, etc. * Server-side rendered Single-Page Applications (SSR), e.g. Angular SSR, Next.js, Nuxt, etc. * Prerendered Single/Multi-Page Applications (SSG), e.g. Angular SSG, Vue.js SSG, Astro, etc. * Web Workers [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install and import package[​](#1-install-and-import-package "Direct link to 1. Install and import package") * via NPM * via CDN First install the [NPM package](https://npmjs.com/package/@configcat/sdk): ```bash npm i @configcat/sdk ``` Then import it into your application: ```js import * as configcat from "@configcat/sdk/browser"; ``` info **In SSR/SSG applications**, you can either import from `@configcat/sdk/node` or `@configcat/sdk/browser` depending on whether your code executes in a server or client context, or import from the uniform main entry point `@configcat/sdk` if your code needs to run in both contexts. info For subpath imports to work **in TypeScript**, you must set the [moduleResolution](https://www.typescriptlang.org/tsconfig/#moduleResolution) option to `node16`, `nodenext` or `bundler` in your `tsconfig.json`. For TypeScript versions older than 4.7, where these options are not available, you need to fall back to module resolution `node` and importing from the main entry point `@configcat/sdk`. info Please note that subpath imports require your bundler to support the [exports](https://nodejs.org/api/packages.html#exports) package.json field, introduced in Node.js v12.7. **In the unlikely case of bundler compatibility issues**, you can fall back to importing from the main entry point `@configcat/sdk` as long as your bundler recognizes the [browser](https://github.com/defunctzombie/package-browser-field-spec) package.json field. Import the package directly from a CDN server into your application: ```html ``` or ```html ``` ### 2. Create the *ConfigCat* client with your SDK Key[​](#2-create-the-configcat-client-with-your-sdk-key "Direct link to 2-create-the-configcat-client-with-your-sdk-key") ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); ``` ### 3. Get your setting value[​](#3-get-your-setting-value "Direct link to 3. Get your setting value") The async/await way: ```js const value = await configCatClient.getValueAsync( 'isMyAwesomeFeatureEnabled', false, ); if (value) { do_the_new_thing(); } else { do_the_old_thing(); } ``` info Please note that [top-level await in modules](https://exploringjs.com/js/book/ch_modules.html#top-level-await) may not be available [in older browsers](https://caniuse.com/mdn-javascript_operators_await_top_level). If you need to target such browser versions, you will need to use Promises, wrap your code in an async function or configure your build tools to downlevel this language feature. The Promise way: ```js configCatClient .getValueAsync('isMyAwesomeFeatureEnabled', false) .then((value) => { if (value) { do_the_new_thing(); } else { do_the_old_thing(); } }); ``` The *ConfigCat SDK* also offers a synchronous API for feature flag evaluation. Read more [here](#snapshots-and-synchronous-feature-flag-evaluation). ### 4. Dispose the *ConfigCat* client[​](#4-dispose-the-configcat-client "Direct link to 4-dispose-the-configcat-client") You can safely dispose all clients at once or individually and release all associated resources on application exit. ```js configcat.disposeAllClients(); // disposes all clients // -or- configCatClient.dispose(); // disposes a specific client ``` ## Demo on CodePen[​](#demo-on-codepen "Direct link to Demo on CodePen") See the Pen [ConfigCat Feature Flag Demo](https://codepen.io/configcat/pen/myemzYW) on [CodePen](https://codepen.io). ## Creating the *ConfigCat* Client[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `configcat.getClient('')` returns a client with default options. The `getClient` function has optional parameters, which can be used to adjust the behavior of the client. | Parameters | Description | Default | | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | | `sdkKey` | **REQUIRED.** SDK Key to access your feature flags and settings. Get it from *ConfigCat Dashboard*. | - | | `pollingMode` | Optional. The polling mode to use to fetch the config data from the ConfigCat CDN. [More about polling modes](#polling-modes). | `PollingMode.AutoPoll` | | `options` | Optional. The options object. See the table below. | - | The available options depends on the chosen polling mode. However, there are some common options which can be set in the case of every polling mode: | Option Parameter | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `configFetcher` | Custom [`IConfigCatConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigFetcher.ts) instance for downloading a config. | [`XmlHttpRequestConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/browser/XmlHttpRequestConfigFetcher.ts) | | `cache` | Custom [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) implementation for caching the downloaded config. | [`LocalStorageConfigCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/browser/LocalStorageConfigCache.ts) or e [`IndexedDBConfigCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/shared/IndexedDBConfigCache.ts) | | `logger` | Custom [`IConfigCatLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) implementation for tracing. | [`ConfigCatConsoleLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) (with WARN level) | | `logFilter` | Sets a custom log filter. [More about log filtering](#log-filtering). | `undefined` (none) | | `baseUrl` | Sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | | `requestTimeoutMs` | The amount of milliseconds the SDK waits for a response from the ConfigCat servers before returning values from the cache. | 30000 | | `flagOverrides` | Local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | | `dataGovernance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `DataGovernance.Global`, `DataGovernance.EuOnly`. | `DataGovernance.Global` | | `defaultUser` | Sets the default user. [More about default user](#default-user). | `undefined` (none) | | `offline` | Determines whether the client should be initialized to offline mode. [More about offline mode](#online--offline-mode). | `false` | Options also include a property named `setupHook`, which you can use to subscribe to the hooks (events) at the time of initialization. [More about hooks](#hooks). For example: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('clientReady', function() { const keys = this.configCatClient.snapshot().getAllKeys(); console.log(`Client is ready! Number of available feature flags: ${keys.length}`); }), }, ); ``` info You can acquire singleton client instances for your SDK keys using the `configcat.getClient(sdkKey: "")` factory function. (However, please keep in mind that subsequent calls to `getClient()` with the *same SDK Key* return a *shared* client instance, which was set up by the first call.) You can close all open clients at once using the `configcat.disposeAllClients()` function or do it individually using the `configCatClient.dispose()` method. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") Returns a Promise with the value. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((value) => { console.log(value); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | `typeof defaultValue` | | -------------- | --------------------- | | On/Off Toggle | `boolean` | | Text | `string` | | Whole Number | `number` | | Decimal Number | `number` | In addition to the types mentioned above, you also have the option to provide `null` or `undefined` for the `defaultValue` parameter regardless of the setting kind. However, if you do so, the return type of the `getValue` method will be * `boolean | string | number | null` when `defaultValue` is `null` or * `boolean | string | number | undefined` when `defaultValue` is `undefined`. This is because in these cases the exact return type cannot be determined at compile-time as the TypeScript compiler has no information about the setting type. It's important to note that providing any other type for the `defaultValue` parameter will result in a `TypeError`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueDetailsAsync()`[​](#anatomy-of-getvaluedetailsasync "Direct link to anatomy-of-getvaluedetailsasync") `getValueDetailsAsync()` is similar to `getValueAsync()` but instead of returning the evaluated value only, it provides more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const details = await configCatClient.getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((details) => { console.log(details); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `key` | `string` | The key of the evaluated feature flag or setting. | | `value` | `boolean` / `string` / `number` | The evaluated value of the feature flag or setting. | | `user` | `User` | The User Object used for the evaluation. | | `isDefaultValue` | `boolean` | True when the default value passed to `getValueDetailsAsync()` is returned due to an error. | | `errorCode` | `EvaluationErrorCode` | In case of an error, this property contains a code that identifies the reason for the error. | | `errorMessage` | `string` | In case of an error, this property contains the error message. | | `errorException` | `any` | In case of an error, this property contains the related exception object (if any). | | `matchedTargetingRule` | `TargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matchedPercentageOption` | `PercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `fetchTime` | `Date` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. For simple targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; ``` ```js const userObject = { identifier: 'john@example.com' }; ``` | Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any `string` value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | For advanced targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#', email: 'john@example.com', country: 'United Kingdom', custom: { SubscriptionType: 'Pro', UserRole: 'Admin', }, }; ``` The `custom` dictionary also allows attribute values other than `string` values: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; userObject.custom = { Rating: 4.5, RegisteredAt: new Date('2023-11-22T12:34:56.000Z'), Roles: ['Role1', 'Role2'], }; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `string` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `number` values, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `number` values representing a second-based Unix timestamp, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `string`, * accept `string` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") It's possible to set a default User Object that will be used on feature flag and setting evaluation. It can be useful when your application has a single user only or rarely switches users. You can set the default User Object either on SDK initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { defaultUser: { identifier: 'john@example.com' }, }, ); ``` ...or using the `setDefaultUser()` method of the `configCatClient` object: ```js configCatClient.setDefaultUser({ identifier: 'john@example.com' }); ``` Whenever the evaluation methods like `getValueAsync()`, `getValueDetailsAsync()`, etc. are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); // The default user will be used in the evaluation process. const value = await configCatClient.getValueAsync('keyOfMyFeatureFlag', false); ``` When a `user` parameter is passed to the evaluation methods, it takes precedence over the default user. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); const otherUser = { identifier: 'brian@example.com' }; // otherUser will be used in the evaluation process. const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', false, otherUser, ); ``` You can also remove the default user by doing the following: ```js configCatClient.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValueAsync()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. [More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `pollIntervalSeconds` option parameter to change the polling interval. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { pollIntervalSeconds: 95, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `pollIntervalSeconds` | Polling interval in seconds. | 60s | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5s | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValueAsync()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValueAsync()` will return the setting value after the cache is updated. Use `cacheTimeToLiveSeconds` option parameter to set cache lifetime. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.LazyLoad, { cacheTimeToLiveSeconds: 600, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------- | ------- | | `cacheTimeToLiveSeconds` | Cache TTL in seconds. | 60s | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefreshAsync()` is your application's responsibility. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); await configCatClient.forceRefreshAsync(); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` > `getValueAsync()` returns `defaultValue` if the cache is empty. Call `forceRefreshAsync()` to update the cache. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); // console: "my default value" await configCatClient.forceRefreshAsync(); value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `clientReady: [cacheState: ClientCacheState]`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `cacheState` argument. * `configFetched: [result: RefreshResult, isInitiatedByUser: boolean]`: This event is emitted each time the client attempts to refresh the cached config by fetching the latest version from the ConfigCat CDN. It is emitted not only when `ForceRefreshAsync` is called but also when the refresh is initiated by the client automatically. Thus, this event allows you to observe potential network issues that occur under the hood. * `configChanged: [newConfig: IConfig]`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `flagEvaluated: [evaluationDetails: IEvaluationDetails]`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetailsAsync()`](#anatomy-of-getvaluedetailsasync). * `clientError: [message: string, exception?: any]`: This event is emitted when an error occurs within the client. You can subscribe to these events either on initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', function() { /* handle the event */ }), }, ); ``` ...or directly on the `ConfigCatClient` instance: ```js configCatClient.on('flagEvaluated', function() { /* handle the event */ }); ``` caution Some events (e.g. `clientReady`, `configChanged` and `clientError`) may be emitted before `getClient` returns. This means you may miss them unless you subscribe on initialization. However, even if you do, there's another gotcha: it's not safe to use the outer `configCatClient` variable in your event handler because it may not yet be assigned when the handler is called. Instead, you can safely access the client instance via `this.configCatClient` - provided that the event handler is a normal function, not an arrow function. ## Snapshots and synchronous feature flag evaluation[​](#snapshots-and-synchronous-feature-flag-evaluation "Direct link to Snapshots and synchronous feature flag evaluation") On JavaScript platforms, the *ConfigCat* client provides only asynchronous methods for evaluating feature flags and settings because these operations may involve network communication (e.g. downloading config data from the ConfigCat CDN servers), which is necessarily an asynchronous operation in JavaScript. However, there can be circumstances where synchronous evaluation is preferable, thus, since v8.1.0, the JavaScript SDK provides a way to synchronously evaluate feature flags and settings via *snapshots*. Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, ); // Wait for the client to initialize. await configCatClient.waitForReady(); const snapshot = configCatClient.snapshot(); const user = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; for (const key of snapshot.getAllKeys()) { const value = snapshot.getValue(key, null, user); console.log(`${key}: ${value}`); } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefreshAsync`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTimeSeconds` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```js const clientCacheState = await configCatClient.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { // Handle initialization failure (see below). console.warn('ConfigCat client failed to obtain the config data during initialization.'); } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `configChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases where you want to prevent the SDK from making HTTP calls, you can switch it to offline mode: ```js configCatClient.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To switch the SDK back to online mode, do the following: ```js configCatClient.setOnline(); ``` Using the `configCatClient.isOffline` property you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `{ [key: string]: boolean | string | number }` object, from the current query string or from a custom flag override data source. ### Map[​](#map "Direct link to Map") You can specify simple feature flag & setting overrides using a `{ [key: string]: boolean | string | number }` map. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: configcat.createFlagOverridesFromMap( { enabledFeature: true, disabledFeature: false, intSetting: 5, doubleSetting: 3.14, stringSetting: 'test', }, configcat.OverrideBehaviour.LocalOnly, ), }, ); ``` ### Query string[​](#query-string "Direct link to Query string") It is also possible to override feature flags & settings using query string parameters. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: createFlagOverridesFromQueryParams(configcat.OverrideBehaviour.LocalOverRemote), }, ); ``` With that setup, you can override feature flags and settings by appending query string parameters to the URL of your application in the following form: `https://app.example.com/?cc-myBooleanFlag=true&cc-myStringSetting=abc&...` The setting type is automatically inferred from the value. Please pay attention to this behavior. The inferred type of the value must match the type of the feature flag or setting you override (see also [this table](#setting-type-mapping)). In case you want to force a boolean or number value to be interpreted as a string value, use the `;str` suffix: `&cc-myStringSetting;str=true`. If the default prefix used to differentiate between normal and flag override query string parameters (`cc-`) is not suitable for you, you can set a custom prefix using the corresponding optional parameter of `createFlagOverridesFromQueryParams`. ### Custom data source implementation[​](#custom-data-source-implementation "Direct link to Custom data source implementation") You can create a custom flag override data source by implementing `IOverrideDataSource`. The SDK provides the `createSettingFromValue` function to create `Setting` objects from simple `boolean`, `string` and `number` values. In case you need complex (full-featured) flag overrides, you can use the `deserializeConfig` function to obtain `Setting` objects from a config JSON conforming to the [config JSON v6 format](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ```ts class MyCustomOverrideDataSource implements IOverrideDataSource { private settings: Record; constructor(configJson: string) { this.settings = deserializeConfig(configJson).f ?? {}; } getOverrides(): Record { return this.settings; } } ``` or ```js function MyCustomOverrideDataSource(configJson) { this.settings = deserializeConfig(configJson).f ?? {}; } MyCustomOverrideDataSource.prototype.getOverrides = function () { return this.settings; }; ``` then ```js // Set the `MyCustomOverrideDataSource` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: { dataSource: new MyCustomOverrideDataSource('{ "f": { ... } }'), behaviour: configcat.OverrideBehaviour.LocalOnly, } }, ); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: configcat.createConsoleLogger(configcat.LogLevel.Info), // Setting log level to Info }, ); ``` Available log levels: | Level | Description | | ----- | ------------------------------------------------------- | | Off | Nothing gets logged. | | Error | Only error level events are logged. | | Warn | Default. Errors and Warnings are logged. | | Info | Errors, Warnings and feature flag evaluation is logged. | | Debug | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash ConfigCat - INFO - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"#SOME-USER-ID#","Email":"configcat@example.com"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") The SDK provides a simple logger implementation that logs to [the debugging console](https://developer.mozilla.org/en-US/docs/Web/API/console) (`configcat.createConsoleLogger(...)`) but it also allows you to inject any custom implementation of `IConfigCatLogger`. ```ts class MyCustomLogger implements IConfigCatLogger { /** * Writes an event into the log. * @param level Event severity level. * @param eventId Event identifier. * @param message Message. * @param exception The exception object related to the message (if any). */ log( level: LogLevel, eventId: LogEventId, message: LogMessage, exception?: any, ): void { // insert your custom log logic } } ``` or ```js function MyCustomLogger() {} MyCustomLogger.prototype.log = function (level, eventId, message, exception) { // insert your custom log logic }; ``` then ```js // Set the `MyCustomLogger` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: new MyCustomLogger(), }, ); ``` ### Log Filtering[​](#log-filtering "Direct link to Log Filtering") You can define a custom log filter by providing a callback function via the `logFilter` option. The callback will be called by the *ConfigCat SDK* each time a log event occurs (and the event passes the minimum log level specified by the `IConfigCatLogger.level` property). That is, the callback allows you to filter log events by `level`, `eventId`, `message` or `exception`. The formatted message string can be obtained via `message.toString()`. If the callback function returns `true`, the event will be logged, otherwise it will be skipped. ```js // Filter out events with id 1001 from the log. const logFilter = (level, eventId, message, exception) => eventId != 1001; const configCatClient = configcat.getClient( "#YOUR-SDK-KEY#", configcat.PollingMode.AutoPoll, { logFilter: logFilter } ); ``` caution Please make sure that your log filter logic doesn't perform heavy computation. A complex or incorrectly implemented log filter can degrade the performance of the SDK. ## `getAllKeysAsync()`[​](#getallkeysasync "Direct link to getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeysAsync()` method. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); const keys = await configCatClient.getAllKeysAsync(); console.log(keys); ``` ## `getAllValuesAsync()`[​](#getallvaluesasync "Direct link to getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValuesAsync(); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValuesAsync(userObject); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); ``` ## `getAllValueDetailsAsync()`[​](#getallvaluedetailsasync "Direct link to getallvaluedetailsasync") Evaluates and returns the values along with evaluation details of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValueDetailsAsync(); settingValues.forEach((details) => console.log(details)); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValueDetailsAsync(userObject); settingValues.forEach((details) => console.log(details)); ``` ## Using custom cache implementation[​](#using-custom-cache-implementation "Direct link to Using custom cache implementation") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) interface and set the `cache` property in the options passed to `getClient`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```ts class MyCustomCache implements IConfigCatCache { set(key: string, value: string): Promise | void { // insert your cache write logic here } get( key: string, ): Promise | string | null | undefined { // insert your cache read logic here } } ``` or ```js function MyCustomCache() {} MyCustomCache.prototype.set = function (key, value) { // insert your cache write logic here }; MyCustomCache.prototype.get = function (key) { // insert your cache read logic here }; ``` then ```js // Set the `MyCustomCache` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { cache: new MyCustomCache(), }, ); ``` info The JavaScript SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the *ConfigCat SDK* that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Platform compatibility[​](#platform-compatibility "Direct link to Platform compatibility") The SDK should be compatible with all modern, widely used browsers and bundlers. The SDK is [tested](https://github.com/configcat/js-unified-sdk/blob/master/.github/workflows/js-sdk-ci.yml) against the following browsers: * Chrome (stable, latest, beta) * Chromium (71.0.3556.0, 72.0.3626.0, 80.0.3987.0) * Firefox (84.0, latest, latest-beta) * Safari (latest) The SDK is compatible with TypeScript v4.0.2 or newer. Earlier versions may work but those are not tested, thus, not supported officially. These tests are running on each pull request, before each deploy, and on a daily basis. You can view a sample run [here](https://github.com/configcat/js-unified-sdk/actions/runs/11745259578). ## Best practices[​](#best-practices "Direct link to Best practices") ### Choosing polling mode for serverless functions[​](#choosing-polling-mode-for-serverless-functions "Direct link to Choosing polling mode for serverless functions") In most cases, Auto polling is a good choice, but it's not ideal for short-lived serverless functions like AWS Lambdas, Azure Functions, Cloudflare Workers, etc. For example, if the SDK is running in a Next.js application that is hosted on Vercel (AWS Lambda), or your application is hosted directly in AWS Lambdas, it is recommended to use the SDK in Lazy loading or Manual polling mode instead of the default Auto polling mode. As AWS Lambdas try to minimize their uptime, the applications are terminated as soon as the sytem detects inactivity in the application. Auto polling mode is implemented using an asynchronous background loop to periodically get the config data from the ConfigCat servers, however the AWS Lambda doesn't detect it as a running application and terminates it. So it can easily happen that there is an ongoing HTTP GET request towards our servers and this termination can cause errors. The most likely error message in this case is `Request timed out while trying to fetch config JSON.` ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [Plain HTML + JS](https://github.com/configcat/js-unified-sdk/tree/master/samples/html) * [Plain HTML + JS using ECMAScript module system](https://github.com/configcat/js-unified-sdk/tree/master/samples/html-esm) * [Plain HTML + TS running the SDK in a Web Worker](https://github.com/configcat/js-unified-sdk/tree/master/samples/web-worker) * [Sample Angular web application](https://github.com/configcat/js-unified-sdk/tree/master/samples/angular-sample) * [Sample React web application](https://github.com/configcat/js-unified-sdk/tree/master/samples/react-sample) * [Sample React Native application](https://github.com/configcat/js-unified-sdk/tree/master/samples/react-native-sample) * [Sample Vue SSR web application](https://github.com/configcat/js-unified-sdk/tree/master/samples/vue-ssr-sample) ## Guides[​](#guides "Direct link to Guides") See the guides on how to use ConfigCat's JavaScript SDK with the following libraries and frameworks: info Some of these guides may use legacy SDKs. However, the parts beyond NPM package installation and import should still work with modern SDKs. Client-side frontend frameworks: * [Angular](https://configcat.com/blog/2022/08/09/using-feature-flags-in-angular/) * [React](https://configcat.com/blog/2021/12/13/feature-flags-in-react/) * [Vue.js](https://configcat.com/blog/2022/01/28/how-to-use-feature-flag-in-vuejs/) * [Ionic](https://configcat.com/blog/2022/07/29/how-to-use-feature-flags-in-ionic-js/) * [Phaser](https://configcat.com/blog/2022/02/04/feature-flags-in-phaser/) * [Solid.js](https://configcat.com/blog/2022/11/11/how-to-use-feature-flags-in-solidjs/) * [melonJS](https://configcat.com/blog/2022/02/19/feature-flags-in-melonjs/) SSR frontend frameworks: * [Nuxt](https://configcat.com/blog/2022/07/01/how-to-use-feature-flags-in-nuxtjs/) * [Next.js](https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/) * [Remix](https://configcat.com/blog/2022/04/01/feature-flags-in-remix/) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) * [ConfigCat SDK for JavaScript in NPM](https://www.npmjs.com/package/@configcat/sdk) --- # Source: https://configcat.com/docs/sdk-reference/js/bun.md # Bun SDK Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/js-unified-sdk.svg?style=social)](https://github.com/configcat/js-unified-sdk/stargazers) [![JS SDK CI](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml/badge.svg?branch=master)](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml) [![SonarCloud Coverage](https://img.shields.io/sonar/coverage/configcat_js-unified-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_js-unified-sdk) [![Known Vulnerabilities](https://snyk.io/test/github/configcat/js-unified-sdk/badge.svg?targetFile=package.json)](https://snyk.io/test/github/configcat/js-unified-sdk?targetFile=package.json) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=configcat_js-sdk\&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=configcat_js-sdk) [![JSDELIVR](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge)](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge) [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install and import package[​](#1-install-and-import-package "Direct link to 1. Install and import package") First install the [NPM package](https://npmjs.com/package/@configcat/sdk): ```bash npm i @configcat/sdk ``` Then import it into your application: ```js import * as configcat from "@configcat/sdk/bun"; ``` ### 2. Create the *ConfigCat* client with your SDK Key[​](#2-create-the-configcat-client-with-your-sdk-key "Direct link to 2-create-the-configcat-client-with-your-sdk-key") ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); ``` ### 3. Get your setting value[​](#3-get-your-setting-value "Direct link to 3. Get your setting value") The async/await way: ```js const value = await configCatClient.getValueAsync( 'isMyAwesomeFeatureEnabled', false, ); if (value) { do_the_new_thing(); } else { do_the_old_thing(); } ``` The Promise way: ```js configCatClient .getValueAsync('isMyAwesomeFeatureEnabled', false) .then((value) => { if (value) { do_the_new_thing(); } else { do_the_old_thing(); } }); ``` The *ConfigCat SDK* also offers a synchronous API for feature flag evaluation. Read more [here](#snapshots-and-synchronous-feature-flag-evaluation). ### 4. Dispose the *ConfigCat* client[​](#4-dispose-the-configcat-client "Direct link to 4-dispose-the-configcat-client") You can safely dispose all clients at once or individually and release all associated resources on application exit. ```js configcat.disposeAllClients(); // disposes all clients // -or- configCatClient.dispose(); // disposes a specific client ``` ## Creating the *ConfigCat* Client[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `configcat.getClient('')` returns a client with default options. The `getClient` function has optional parameters, which can be used to adjust the behavior of the client. | Parameters | Description | Default | | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | | `sdkKey` | **REQUIRED.** SDK Key to access your feature flags and settings. Get it from *ConfigCat Dashboard*. | - | | `pollingMode` | Optional. The polling mode to use to fetch the config data from the ConfigCat CDN. [More about polling modes](#polling-modes). | `PollingMode.AutoPoll` | | `options` | Optional. The options object. See the table below. | - | The available options depends on the chosen polling mode. However, there are some common options which can be set in the case of every polling mode: | Option Parameter | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `configFetcher` | Custom [`IConfigCatConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigFetcher.ts) instance for downloading a config. | [`NodeHttpConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/node/NodeHttpConfigFetcher.ts) | | `cache` | Custom [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) implementation for caching the downloaded config. | [`InMemoryConfigCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) | | `logger` | Custom [`IConfigCatLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) implementation for tracing. | [`ConfigCatConsoleLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) (with WARN level) | | `logFilter` | Sets a custom log filter. [More about log filtering](#log-filtering). | `undefined` (none) | | `baseUrl` | Sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | | `httpAgent` | The [`http.Agent`](https://nodejs.org/api/http.html#class-httpagent) instance to use for non-secure HTTP communication. Can be used to route `http://...` requests made by the SDK through an HTTP, HTTPS or SOCKS proxy (see also [this section](#using-configcat-behind-a-proxy)). | | | `httpsAgent` | The [`https.Agent`](https://nodejs.org/api/https.html#class-httpsagent) instance to use for secure HTTP communication. Can be used to route `https://...` requests made by the SDK through an HTTP, HTTPS or SOCKS proxy (see also [this section](#using-configcat-behind-a-proxy)). | | | `requestTimeoutMs` | The amount of milliseconds the SDK waits for a response from the ConfigCat servers before returning values from the cache. | 30000 | | `flagOverrides` | Local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | | `dataGovernance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `DataGovernance.Global`, `DataGovernance.EuOnly`. | `DataGovernance.Global` | | `defaultUser` | Sets the default user. [More about default user](#default-user). | `undefined` (none) | | `offline` | Determines whether the client should be initialized to offline mode. [More about offline mode](#online--offline-mode). | `false` | Options also include a property named `setupHook`, which you can use to subscribe to the hooks (events) at the time of initialization. [More about hooks](#hooks). For example: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('clientReady', function() { const keys = this.configCatClient.snapshot().getAllKeys(); console.log(`Client is ready! Number of available feature flags: ${keys.length}`); }), }, ); ``` info You can acquire singleton client instances for your SDK keys using the `configcat.getClient(sdkKey: "")` factory function. (However, please keep in mind that subsequent calls to `getClient()` with the *same SDK Key* return a *shared* client instance, which was set up by the first call.) You can close all open clients at once using the `configcat.disposeAllClients()` function or do it individually using the `configCatClient.dispose()` method. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") Returns a Promise with the value. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((value) => { console.log(value); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | `typeof defaultValue` | | -------------- | --------------------- | | On/Off Toggle | `boolean` | | Text | `string` | | Whole Number | `number` | | Decimal Number | `number` | In addition to the types mentioned above, you also have the option to provide `null` or `undefined` for the `defaultValue` parameter regardless of the setting kind. However, if you do so, the return type of the `getValue` method will be * `boolean | string | number | null` when `defaultValue` is `null` or * `boolean | string | number | undefined` when `defaultValue` is `undefined`. This is because in these cases the exact return type cannot be determined at compile-time as the TypeScript compiler has no information about the setting type. It's important to note that providing any other type for the `defaultValue` parameter will result in a `TypeError`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueDetailsAsync()`[​](#anatomy-of-getvaluedetailsasync "Direct link to anatomy-of-getvaluedetailsasync") `getValueDetailsAsync()` is similar to `getValueAsync()` but instead of returning the evaluated value only, it provides more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const details = await configCatClient.getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((details) => { console.log(details); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `key` | `string` | The key of the evaluated feature flag or setting. | | `value` | `boolean` / `string` / `number` | The evaluated value of the feature flag or setting. | | `user` | `User` | The User Object used for the evaluation. | | `isDefaultValue` | `boolean` | True when the default value passed to `getValueDetailsAsync()` is returned due to an error. | | `errorCode` | `EvaluationErrorCode` | In case of an error, this property contains a code that identifies the reason for the error. | | `errorMessage` | `string` | In case of an error, this property contains the error message. | | `errorException` | `any` | In case of an error, this property contains the related exception object (if any). | | `matchedTargetingRule` | `TargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matchedPercentageOption` | `PercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `fetchTime` | `Date` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. For simple targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; ``` ```js const userObject = { identifier: 'john@example.com' }; ``` | Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any `string` value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | For advanced targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#', email: 'john@example.com', country: 'United Kingdom', custom: { SubscriptionType: 'Pro', UserRole: 'Admin', }, }; ``` The `custom` dictionary also allows attribute values other than `string` values: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; userObject.custom = { Rating: 4.5, RegisteredAt: new Date('2023-11-22T12:34:56.000Z'), Roles: ['Role1', 'Role2'], }; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `string` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `number` values, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `number` values representing a second-based Unix timestamp, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `string`, * accept `string` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") It's possible to set a default User Object that will be used on feature flag and setting evaluation. It can be useful when your application has a single user only or rarely switches users. You can set the default User Object either on SDK initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { defaultUser: { identifier: 'john@example.com' }, }, ); ``` ...or using the `setDefaultUser()` method of the `configCatClient` object: ```js configCatClient.setDefaultUser({ identifier: 'john@example.com' }); ``` Whenever the evaluation methods like `getValueAsync()`, `getValueDetailsAsync()`, etc. are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); // The default user will be used in the evaluation process. const value = await configCatClient.getValueAsync('keyOfMyFeatureFlag', false); ``` When a `user` parameter is passed to the evaluation methods, it takes precedence over the default user. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); const otherUser = { identifier: 'brian@example.com' }; // otherUser will be used in the evaluation process. const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', false, otherUser, ); ``` You can also remove the default user by doing the following: ```js configCatClient.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValueAsync()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. [More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `pollIntervalSeconds` option parameter to change the polling interval. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { pollIntervalSeconds: 95, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `pollIntervalSeconds` | Polling interval in seconds. | 60s | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5s | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValueAsync()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValueAsync()` will return the setting value after the cache is updated. Use `cacheTimeToLiveSeconds` option parameter to set cache lifetime. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.LazyLoad, { cacheTimeToLiveSeconds: 600, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------- | ------- | | `cacheTimeToLiveSeconds` | Cache TTL in seconds. | 60s | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefreshAsync()` is your application's responsibility. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); await configCatClient.forceRefreshAsync(); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` > `getValueAsync()` returns `defaultValue` if the cache is empty. Call `forceRefreshAsync()` to update the cache. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); // console: "my default value" await configCatClient.forceRefreshAsync(); value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `clientReady: [cacheState: ClientCacheState]`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `cacheState` argument. * `configFetched: [result: RefreshResult, isInitiatedByUser: boolean]`: This event is emitted each time the client attempts to refresh the cached config by fetching the latest version from the ConfigCat CDN. It is emitted not only when `ForceRefreshAsync` is called but also when the refresh is initiated by the client automatically. Thus, this event allows you to observe potential network issues that occur under the hood. * `configChanged: [newConfig: IConfig]`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `flagEvaluated: [evaluationDetails: IEvaluationDetails]`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetailsAsync()`](#anatomy-of-getvaluedetailsasync). * `clientError: [message: string, exception?: any]`: This event is emitted when an error occurs within the client. You can subscribe to these events either on initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', function() { /* handle the event */ }), }, ); ``` ...or directly on the `ConfigCatClient` instance: ```js configCatClient.on('flagEvaluated', function() { /* handle the event */ }); ``` caution Some events (e.g. `clientReady`, `configChanged` and `clientError`) may be emitted before `getClient` returns. This means you may miss them unless you subscribe on initialization. However, even if you do, there's another gotcha: it's not safe to use the outer `configCatClient` variable in your event handler because it may not yet be assigned when the handler is called. Instead, you can safely access the client instance via `this.configCatClient` - provided that the event handler is a normal function, not an arrow function. ## Snapshots and synchronous feature flag evaluation[​](#snapshots-and-synchronous-feature-flag-evaluation "Direct link to Snapshots and synchronous feature flag evaluation") On JavaScript platforms, the *ConfigCat* client provides only asynchronous methods for evaluating feature flags and settings because these operations may involve network communication (e.g. downloading config data from the ConfigCat CDN servers), which is necessarily an asynchronous operation in JavaScript. However, there can be circumstances where synchronous evaluation is preferable, thus, since v8.1.0, the JavaScript SDK provides a way to synchronously evaluate feature flags and settings via *snapshots*. Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, ); // Wait for the client to initialize. await configCatClient.waitForReady(); const snapshot = configCatClient.snapshot(); const user = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; for (const key of snapshot.getAllKeys()) { const value = snapshot.getValue(key, null, user); console.log(`${key}: ${value}`); } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefreshAsync`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTimeSeconds` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```js const clientCacheState = await configCatClient.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { // Handle initialization failure (see below). console.warn('ConfigCat client failed to obtain the config data during initialization.'); } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `configChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases where you want to prevent the SDK from making HTTP calls, you can switch it to offline mode: ```js configCatClient.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To switch the SDK back to online mode, do the following: ```js configCatClient.setOnline(); ``` Using the `configCatClient.isOffline` property you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `{ [key: string]: boolean | string | number }` object or from a custom flag override data source. ### Map[​](#map "Direct link to Map") You can specify simple feature flag & setting overrides using a `{ [key: string]: boolean | string | number }` map. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: configcat.createFlagOverridesFromMap( { enabledFeature: true, disabledFeature: false, intSetting: 5, doubleSetting: 3.14, stringSetting: 'test', }, configcat.OverrideBehaviour.LocalOnly, ), }, ); ``` ### Custom data source implementation[​](#custom-data-source-implementation "Direct link to Custom data source implementation") You can create a custom flag override data source by implementing `IOverrideDataSource`. The SDK provides the `createSettingFromValue` function to create `Setting` objects from simple `boolean`, `string` and `number` values. In case you need complex (full-featured) flag overrides, you can use the `deserializeConfig` function to obtain `Setting` objects from a config JSON conforming to the [config JSON v6 format](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ```ts class MyCustomOverrideDataSource implements IOverrideDataSource { private settings: Record; constructor(configJson: string) { this.settings = deserializeConfig(configJson).f ?? {}; } getOverrides(): Record { return this.settings; } } ``` or ```js function MyCustomOverrideDataSource(configJson) { this.settings = deserializeConfig(configJson).f ?? {}; } MyCustomOverrideDataSource.prototype.getOverrides = function () { return this.settings; }; ``` then ```js // Set the `MyCustomOverrideDataSource` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: { dataSource: new MyCustomOverrideDataSource('{ "f": { ... } }'), behaviour: configcat.OverrideBehaviour.LocalOnly, } }, ); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: configcat.createConsoleLogger(configcat.LogLevel.Info), // Setting log level to Info }, ); ``` Available log levels: | Level | Description | | ----- | ------------------------------------------------------- | | Off | Nothing gets logged. | | Error | Only error level events are logged. | | Warn | Default. Errors and Warnings are logged. | | Info | Errors, Warnings and feature flag evaluation is logged. | | Debug | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash ConfigCat - INFO - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"#SOME-USER-ID#","Email":"configcat@example.com"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") The SDK provides a simple logger implementation that logs to [the debugging console](https://developer.mozilla.org/en-US/docs/Web/API/console) (`configcat.createConsoleLogger(...)`) but it also allows you to inject any custom implementation of `IConfigCatLogger`. ```ts class MyCustomLogger implements IConfigCatLogger { /** * Writes an event into the log. * @param level Event severity level. * @param eventId Event identifier. * @param message Message. * @param exception The exception object related to the message (if any). */ log( level: LogLevel, eventId: LogEventId, message: LogMessage, exception?: any, ): void { // insert your custom log logic } } ``` or ```js function MyCustomLogger() {} MyCustomLogger.prototype.log = function (level, eventId, message, exception) { // insert your custom log logic }; ``` then ```js // Set the `MyCustomLogger` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: new MyCustomLogger(), }, ); ``` ### Log Filtering[​](#log-filtering "Direct link to Log Filtering") You can define a custom log filter by providing a callback function via the `logFilter` option. The callback will be called by the *ConfigCat SDK* each time a log event occurs (and the event passes the minimum log level specified by the `IConfigCatLogger.level` property). That is, the callback allows you to filter log events by `level`, `eventId`, `message` or `exception`. The formatted message string can be obtained via `message.toString()`. If the callback function returns `true`, the event will be logged, otherwise it will be skipped. ```js // Filter out events with id 1001 from the log. const logFilter = (level, eventId, message, exception) => eventId != 1001; const configCatClient = configcat.getClient( "#YOUR-SDK-KEY#", configcat.PollingMode.AutoPoll, { logFilter: logFilter } ); ``` caution Please make sure that your log filter logic doesn't perform heavy computation. A complex or incorrectly implemented log filter can degrade the performance of the SDK. ## `getAllKeysAsync()`[​](#getallkeysasync "Direct link to getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeysAsync()` method. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); const keys = await configCatClient.getAllKeysAsync(); console.log(keys); ``` ## `getAllValuesAsync()`[​](#getallvaluesasync "Direct link to getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValuesAsync(); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValuesAsync(userObject); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); ``` ## `getAllValueDetailsAsync()`[​](#getallvaluedetailsasync "Direct link to getallvaluedetailsasync") Evaluates and returns the values along with evaluation details of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValueDetailsAsync(); settingValues.forEach((details) => console.log(details)); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValueDetailsAsync(userObject); settingValues.forEach((details) => console.log(details)); ``` ## Using custom cache implementation[​](#using-custom-cache-implementation "Direct link to Using custom cache implementation") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) interface and set the `cache` property in the options passed to `getClient`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```ts class MyCustomCache implements IConfigCatCache { set(key: string, value: string): Promise | void { // insert your cache write logic here } get( key: string, ): Promise | string | null | undefined { // insert your cache read logic here } } ``` or ```js function MyCustomCache() {} MyCustomCache.prototype.set = function (key, value) { // insert your cache write logic here }; MyCustomCache.prototype.get = function (key) { // insert your cache read logic here }; ``` then ```js // Set the `MyCustomCache` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { cache: new MyCustomCache(), }, ); ``` info The JavaScript SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Using ConfigCat behind a proxy[​](#using-configcat-behind-a-proxy "Direct link to Using ConfigCat behind a proxy") It is possible to set up the SDK to route HTTP requests through a HTTP, HTTPS or SOCKS proxy. ```bash npm i https-proxy-agent ``` ```js import { HttpsProxyAgent } from 'https-proxy-agent'; const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { httpsAgent: new HttpsProxyAgent("http://192.168.1.1:8080"), }, ); ``` info By default, you need to specify the `httpsAgent` option because the SDK always uses HTTPS to access the ConfigCat CDN. However, if you set the `baseUrl` to a `http://...` URL, you will need to install `http-proxy-agent` and set the `httpAgent` option instead. ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the *ConfigCat SDK* that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Platform compatibility[​](#platform-compatibility "Direct link to Platform compatibility") The SDK should be compatible with newer versions of Bun. The SDK is [tested](https://github.com/configcat/js-unified-sdk/blob/master/.github/workflows/js-sdk-ci.yml) against the following runtimes: * Bun (v1.1.0, latest stable) on Windows / Ubuntu / macOS The SDK is compatible with TypeScript v4.0.2 or newer. Earlier versions may work but those are not tested, thus, not supported officially. These tests are running on each pull request, before each deploy, and on a daily basis. You can view a sample run [here](https://github.com/configcat/js-unified-sdk/actions/runs/11745259578). ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [Sample Bun console application](https://github.com/configcat/js-unified-sdk/tree/master/samples/bun-console) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) * [ConfigCat SDK for JavaScript in NPM](https://www.npmjs.com/package/@configcat/sdk) --- # Source: https://configcat.com/docs/advanced/caching.md # Polling modes & Caching Copy page There are 3 different ways (polling modes) to control caching. ## Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") In auto polling mode, the ConfigCat SDK downloads the latest feature flags and settings from the ConfigCat CDN automatically and stores them in the cache. By default, this happens every 60 seconds. You can set the polling interval to any value between 1 and 2,147,483 seconds. ## Lazy loading[​](#lazy-loading "Direct link to Lazy loading") In lazy loading mode, the ConfigCat SDK downloads the latest feature flags and settings from the ConfigCat CDN only if they are not already present in the cache, or if the cache has expired. By default, the cache Time To Live (TTL) value is 60 seconds. You can set it to any value between 1 and 2,147,483,647 seconds. ## Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the feature flags and settings are downloaded from the ConfigCat CDN. The ConfigCat SDK will not download them automatically. You can (and should) update the cache manually, by calling a `forceRefresh()` - this will download the latest feature flags and settings and update the cache. This animation explains the different polling modes: ## Caching[​](#caching "Direct link to Caching") ConfigCat SDKs in their default setup store all the information they need for feature flag evaluation in memory. This behavior is extendable with custom cache implementations that you can use for pointing the SDK to your own data storage. The main reason for caching is to accelerate serving feature flag evaluation requests when your application is in a stateless environment or frequently restarts. When the SDK notices that it has a valid cache entry to work with, it will use the data from the cache rather than initiating a new HTTP request towards ConfigCat. The cache's validity is based on the polling interval in case of [auto polling](#auto-polling-default) or on the TTL in case of [lazy loading](#lazy-loading). info See the [SDK specific docs](https://configcat.com/docs/sdk-reference/overview.md) for your desired platform to learn how to use custom cache implementations. ### Offline mode[​](#offline-mode "Direct link to Offline mode") ConfigCat SDKs have the capability to go offline. In offline mode, they work only from the configured cache and never communicate with ConfigCat over HTTP. This allows you to set up a centralized cache that only one online ConfigCat SDK writes, but serves many offline ones. info See the [SDK specific docs](https://configcat.com/docs/sdk-reference/overview.md) for your desired platform to learn how to enable offline mode. ### Shared cache[​](#shared-cache "Direct link to Shared cache") As of certain versions, ConfigCat SDKs support using a shared cache. To achieve that, each SDK constructs the key for identifying a specific cache entry based on the SDK key passed at initialization. This means each platform specific SDK that uses the same SDK key will use the same cache entry. Mixing this behavior with [offline mode](#offline-mode), you can have a centralized shared cache that serves many SDKs regardless of what platform they run on. Support for shared caching was introduced in these SDK versions: | SDK | Version | | ------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | .NET | >= [v8.1.0](https://github.com/configcat/.net-sdk/releases) | | Android (Java) | >= [v9.0.0](https://github.com/configcat/android-sdk/releases) | | C++ | >= [v3.0.0](https://github.com/configcat/cpp-sdk/releases) | | Dart (Flutter) | >= [v3.0.0](https://github.com/configcat/dart-sdk/releases) | | Elixir | >= [v3.0.0](https://github.com/configcat/elixir-sdk/releases) | | Go | >= [v8.0.0](https://github.com/configcat/go-sdk/releases) | | Java | >= [v8.2.0](https://github.com/configcat/java-sdk/releases) | | JavaScript (Browser, Bun, Chromium Extension, Cloudflare Worker, Deno, Node.js) | >= [v1.0.0](https://github.com/configcat/js-unified-sdk/releases) | | JS - Legacy | >= [v8.0.0](https://github.com/configcat/js-sdk/releases) | | JS SSR - Legacy | >= [v7.0.0](https://github.com/configcat/js-ssr-sdk/releases) | | Kotlin | >= [v2.0.0](https://github.com/configcat/kotlin-sdk/releases) | | Node.js - Legacy | >= [v10.0.0](https://github.com/configcat/node-sdk/releases) | | PHP | >= [v8.0.0](https://github.com/configcat/php-sdk/releases) | | Python | >= [v8.0.0](https://github.com/configcat/python-sdk/releases) | | React | >= [v3.0.0](https://github.com/configcat/react-sdk/releases) | | Ruby | >= [v7.0.0](https://github.com/configcat/ruby-sdk/releases) | | Rust | >= [v0.1.0](https://github.com/configcat/rust-sdk/releases) | | Swift (iOS) | >= [v10.0.0](https://github.com/configcat/swift-sdk/releases) | --- # Source: https://configcat.com/docs/sdk-reference/js/chromium-extension.md # Chromium Extension SDK Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/js-unified-sdk.svg?style=social)](https://github.com/configcat/js-unified-sdk/stargazers) [![JS SDK CI](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml/badge.svg?branch=master)](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml) [![SonarCloud Coverage](https://img.shields.io/sonar/coverage/configcat_js-unified-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_js-unified-sdk) [![Known Vulnerabilities](https://snyk.io/test/github/configcat/js-unified-sdk/badge.svg?targetFile=package.json)](https://snyk.io/test/github/configcat/js-unified-sdk?targetFile=package.json) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=configcat_js-sdk\&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=configcat_js-sdk) [![JSDELIVR](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge)](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge) [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install and import package[​](#1-install-and-import-package "Direct link to 1. Install and import package") * via NPM * via CDN First install the [NPM package](https://npmjs.com/package/@configcat/sdk): ```bash npm i @configcat/sdk ``` Then import it into your application: ```js import * as configcat from "@configcat/sdk/chromium-extension"; ``` info For subpath imports to work **in TypeScript**, you must set the [moduleResolution](https://www.typescriptlang.org/tsconfig/#moduleResolution) option to `node16`, `nodenext` or `bundler` in your `tsconfig.json`. For TypeScript versions older than 4.7, where these options are not available, you need to fall back to module resolution `node` and importing from the main entry point `@configcat/sdk`. info Please note that subpath imports require your bundler to support the [exports](https://nodejs.org/api/packages.html#exports) package.json field, introduced in Node.js v12.7. **In the unlikely case of bundler compatibility issues**, you can fall back to importing from the main entry point `@configcat/sdk` as long as your bundler recognizes the [browser](https://github.com/defunctzombie/package-browser-field-spec) package.json field. Import the package directly from a CDN server into your application: ```html ``` ### 2. Create the *ConfigCat* client with your SDK Key[​](#2-create-the-configcat-client-with-your-sdk-key "Direct link to 2-create-the-configcat-client-with-your-sdk-key") ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); ``` ### 3. Get your setting value[​](#3-get-your-setting-value "Direct link to 3. Get your setting value") The async/await way: ```js const value = await configCatClient.getValueAsync( 'isMyAwesomeFeatureEnabled', false, ); if (value) { do_the_new_thing(); } else { do_the_old_thing(); } ``` The Promise way: ```js configCatClient .getValueAsync('isMyAwesomeFeatureEnabled', false) .then((value) => { if (value) { do_the_new_thing(); } else { do_the_old_thing(); } }); ``` The *ConfigCat SDK* also offers a synchronous API for feature flag evaluation. Read more [here](#snapshots-and-synchronous-feature-flag-evaluation). ### 4. Dispose the *ConfigCat* client[​](#4-dispose-the-configcat-client "Direct link to 4-dispose-the-configcat-client") You can safely dispose all clients at once or individually and release all associated resources on application exit. ```js configcat.disposeAllClients(); // disposes all clients // -or- configCatClient.dispose(); // disposes a specific client ``` ## Creating the *ConfigCat* Client[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `configcat.getClient('')` returns a client with default options. The `getClient` function has optional parameters, which can be used to adjust the behavior of the client. | Parameters | Description | Default | | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | | `sdkKey` | **REQUIRED.** SDK Key to access your feature flags and settings. Get it from *ConfigCat Dashboard*. | - | | `pollingMode` | Optional. The polling mode to use to fetch the config data from the ConfigCat CDN. [More about polling modes](#polling-modes). | `PollingMode.AutoPoll` | | `options` | Optional. The options object. See the table below. | - | The available options depends on the chosen polling mode. However, there are some common options which can be set in the case of every polling mode: | Option Parameter | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `configFetcher` | Custom [`IConfigCatConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigFetcher.ts) instance for downloading a config. | [`FetchApiConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/shared/FetchApiConfigFetcher.ts) | | `cache` | Custom [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) implementation for caching the downloaded config. | [`ChromeLocalStorageConfigCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/chromium-extension/ChromeLocalStorageConfigCache.ts) or [`IndexedDBConfigCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/shared/IndexedDBConfigCache.ts) | | `logger` | Custom [`IConfigCatLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) implementation for tracing. | [`ConfigCatConsoleLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) (with WARN level) | | `logFilter` | Sets a custom log filter. [More about log filtering](#log-filtering). | `undefined` (none) | | `baseUrl` | Sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | | `requestTimeoutMs` | The amount of milliseconds the SDK waits for a response from the ConfigCat servers before returning values from the cache. | 30000 | | `flagOverrides` | Local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | | `dataGovernance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `DataGovernance.Global`, `DataGovernance.EuOnly`. | `DataGovernance.Global` | | `defaultUser` | Sets the default user. [More about default user](#default-user). | `undefined` (none) | | `offline` | Determines whether the client should be initialized to offline mode. [More about offline mode](#online--offline-mode). | `false` | Options also include a property named `setupHook`, which you can use to subscribe to the hooks (events) at the time of initialization. [More about hooks](#hooks). For example: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('clientReady', function() { const keys = this.configCatClient.snapshot().getAllKeys(); console.log(`Client is ready! Number of available feature flags: ${keys.length}`); }), }, ); ``` info You can acquire singleton client instances for your SDK keys using the `configcat.getClient(sdkKey: "")` factory function. (However, please keep in mind that subsequent calls to `getClient()` with the *same SDK Key* return a *shared* client instance, which was set up by the first call.) You can close all open clients at once using the `configcat.disposeAllClients()` function or do it individually using the `configCatClient.dispose()` method. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") Returns a Promise with the value. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((value) => { console.log(value); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | `typeof defaultValue` | | -------------- | --------------------- | | On/Off Toggle | `boolean` | | Text | `string` | | Whole Number | `number` | | Decimal Number | `number` | In addition to the types mentioned above, you also have the option to provide `null` or `undefined` for the `defaultValue` parameter regardless of the setting kind. However, if you do so, the return type of the `getValue` method will be * `boolean | string | number | null` when `defaultValue` is `null` or * `boolean | string | number | undefined` when `defaultValue` is `undefined`. This is because in these cases the exact return type cannot be determined at compile-time as the TypeScript compiler has no information about the setting type. It's important to note that providing any other type for the `defaultValue` parameter will result in a `TypeError`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueDetailsAsync()`[​](#anatomy-of-getvaluedetailsasync "Direct link to anatomy-of-getvaluedetailsasync") `getValueDetailsAsync()` is similar to `getValueAsync()` but instead of returning the evaluated value only, it provides more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const details = await configCatClient.getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((details) => { console.log(details); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `key` | `string` | The key of the evaluated feature flag or setting. | | `value` | `boolean` / `string` / `number` | The evaluated value of the feature flag or setting. | | `user` | `User` | The User Object used for the evaluation. | | `isDefaultValue` | `boolean` | True when the default value passed to `getValueDetailsAsync()` is returned due to an error. | | `errorCode` | `EvaluationErrorCode` | In case of an error, this property contains a code that identifies the reason for the error. | | `errorMessage` | `string` | In case of an error, this property contains the error message. | | `errorException` | `any` | In case of an error, this property contains the related exception object (if any). | | `matchedTargetingRule` | `TargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matchedPercentageOption` | `PercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `fetchTime` | `Date` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. For simple targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; ``` ```js const userObject = { identifier: 'john@example.com' }; ``` | Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any `string` value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | For advanced targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#', email: 'john@example.com', country: 'United Kingdom', custom: { SubscriptionType: 'Pro', UserRole: 'Admin', }, }; ``` The `custom` dictionary also allows attribute values other than `string` values: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; userObject.custom = { Rating: 4.5, RegisteredAt: new Date('2023-11-22T12:34:56.000Z'), Roles: ['Role1', 'Role2'], }; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `string` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `number` values, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `number` values representing a second-based Unix timestamp, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `string`, * accept `string` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") It's possible to set a default User Object that will be used on feature flag and setting evaluation. It can be useful when your application has a single user only or rarely switches users. You can set the default User Object either on SDK initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { defaultUser: { identifier: 'john@example.com' }, }, ); ``` ...or using the `setDefaultUser()` method of the `configCatClient` object: ```js configCatClient.setDefaultUser({ identifier: 'john@example.com' }); ``` Whenever the evaluation methods like `getValueAsync()`, `getValueDetailsAsync()`, etc. are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); // The default user will be used in the evaluation process. const value = await configCatClient.getValueAsync('keyOfMyFeatureFlag', false); ``` When a `user` parameter is passed to the evaluation methods, it takes precedence over the default user. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); const otherUser = { identifier: 'brian@example.com' }; // otherUser will be used in the evaluation process. const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', false, otherUser, ); ``` You can also remove the default user by doing the following: ```js configCatClient.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValueAsync()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. [More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `pollIntervalSeconds` option parameter to change the polling interval. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { pollIntervalSeconds: 95, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `pollIntervalSeconds` | Polling interval in seconds. | 60s | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5s | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValueAsync()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValueAsync()` will return the setting value after the cache is updated. Use `cacheTimeToLiveSeconds` option parameter to set cache lifetime. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.LazyLoad, { cacheTimeToLiveSeconds: 600, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------- | ------- | | `cacheTimeToLiveSeconds` | Cache TTL in seconds. | 60s | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefreshAsync()` is your application's responsibility. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); await configCatClient.forceRefreshAsync(); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` > `getValueAsync()` returns `defaultValue` if the cache is empty. Call `forceRefreshAsync()` to update the cache. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); // console: "my default value" await configCatClient.forceRefreshAsync(); value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `clientReady: [cacheState: ClientCacheState]`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `cacheState` argument. * `configFetched: [result: RefreshResult, isInitiatedByUser: boolean]`: This event is emitted each time the client attempts to refresh the cached config by fetching the latest version from the ConfigCat CDN. It is emitted not only when `ForceRefreshAsync` is called but also when the refresh is initiated by the client automatically. Thus, this event allows you to observe potential network issues that occur under the hood. * `configChanged: [newConfig: IConfig]`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `flagEvaluated: [evaluationDetails: IEvaluationDetails]`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetailsAsync()`](#anatomy-of-getvaluedetailsasync). * `clientError: [message: string, exception?: any]`: This event is emitted when an error occurs within the client. You can subscribe to these events either on initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', function() { /* handle the event */ }), }, ); ``` ...or directly on the `ConfigCatClient` instance: ```js configCatClient.on('flagEvaluated', function() { /* handle the event */ }); ``` caution Some events (e.g. `clientReady`, `configChanged` and `clientError`) may be emitted before `getClient` returns. This means you may miss them unless you subscribe on initialization. However, even if you do, there's another gotcha: it's not safe to use the outer `configCatClient` variable in your event handler because it may not yet be assigned when the handler is called. Instead, you can safely access the client instance via `this.configCatClient` - provided that the event handler is a normal function, not an arrow function. ## Snapshots and synchronous feature flag evaluation[​](#snapshots-and-synchronous-feature-flag-evaluation "Direct link to Snapshots and synchronous feature flag evaluation") On JavaScript platforms, the *ConfigCat* client provides only asynchronous methods for evaluating feature flags and settings because these operations may involve network communication (e.g. downloading config data from the ConfigCat CDN servers), which is necessarily an asynchronous operation in JavaScript. However, there can be circumstances where synchronous evaluation is preferable, thus, since v8.1.0, the JavaScript SDK provides a way to synchronously evaluate feature flags and settings via *snapshots*. Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, ); // Wait for the client to initialize. await configCatClient.waitForReady(); const snapshot = configCatClient.snapshot(); const user = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; for (const key of snapshot.getAllKeys()) { const value = snapshot.getValue(key, null, user); console.log(`${key}: ${value}`); } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefreshAsync`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTimeSeconds` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```js const clientCacheState = await configCatClient.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { // Handle initialization failure (see below). console.warn('ConfigCat client failed to obtain the config data during initialization.'); } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `configChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases where you want to prevent the SDK from making HTTP calls, you can switch it to offline mode: ```js configCatClient.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To switch the SDK back to online mode, do the following: ```js configCatClient.setOnline(); ``` Using the `configCatClient.isOffline` property you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `{ [key: string]: boolean | string | number }` object, from the current query string or from a custom flag override data source. ### Map[​](#map "Direct link to Map") You can specify simple feature flag & setting overrides using a `{ [key: string]: boolean | string | number }` map. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: configcat.createFlagOverridesFromMap( { enabledFeature: true, disabledFeature: false, intSetting: 5, doubleSetting: 3.14, stringSetting: 'test', }, configcat.OverrideBehaviour.LocalOnly, ), }, ); ``` ### Query string[​](#query-string "Direct link to Query string") It is also possible to override feature flags & settings using query string parameters. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: createFlagOverridesFromQueryParams(configcat.OverrideBehaviour.LocalOverRemote), }, ); ``` With that setup, you can override feature flags and settings by appending query string parameters to the URL of your application in the following form: `https://app.example.com/?cc-myBooleanFlag=true&cc-myStringSetting=abc&...` The setting type is automatically inferred from the value. Please pay attention to this behavior. The inferred type of the value must match the type of the feature flag or setting you override (see also [this table](#setting-type-mapping)). In case you want to force a boolean or number value to be interpreted as a string value, use the `;str` suffix: `&cc-myStringSetting;str=true`. If the default prefix used to differentiate between normal and flag override query string parameters (`cc-`) is not suitable for you, you can set a custom prefix using the corresponding optional parameter of `createFlagOverridesFromQueryParams`. ### Custom data source implementation[​](#custom-data-source-implementation "Direct link to Custom data source implementation") You can create a custom flag override data source by implementing `IOverrideDataSource`. The SDK provides the `createSettingFromValue` function to create `Setting` objects from simple `boolean`, `string` and `number` values. In case you need complex (full-featured) flag overrides, you can use the `deserializeConfig` function to obtain `Setting` objects from a config JSON conforming to the [config JSON v6 format](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ```ts class MyCustomOverrideDataSource implements IOverrideDataSource { private settings: Record; constructor(configJson: string) { this.settings = deserializeConfig(configJson).f ?? {}; } getOverrides(): Record { return this.settings; } } ``` or ```js function MyCustomOverrideDataSource(configJson) { this.settings = deserializeConfig(configJson).f ?? {}; } MyCustomOverrideDataSource.prototype.getOverrides = function () { return this.settings; }; ``` then ```js // Set the `MyCustomOverrideDataSource` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: { dataSource: new MyCustomOverrideDataSource('{ "f": { ... } }'), behaviour: configcat.OverrideBehaviour.LocalOnly, } }, ); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: configcat.createConsoleLogger(configcat.LogLevel.Info), // Setting log level to Info }, ); ``` Available log levels: | Level | Description | | ----- | ------------------------------------------------------- | | Off | Nothing gets logged. | | Error | Only error level events are logged. | | Warn | Default. Errors and Warnings are logged. | | Info | Errors, Warnings and feature flag evaluation is logged. | | Debug | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash ConfigCat - INFO - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"#SOME-USER-ID#","Email":"configcat@example.com"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") The SDK provides a simple logger implementation that logs to [the debugging console](https://developer.mozilla.org/en-US/docs/Web/API/console) (`configcat.createConsoleLogger(...)`) but it also allows you to inject any custom implementation of `IConfigCatLogger`. ```ts class MyCustomLogger implements IConfigCatLogger { /** * Writes an event into the log. * @param level Event severity level. * @param eventId Event identifier. * @param message Message. * @param exception The exception object related to the message (if any). */ log( level: LogLevel, eventId: LogEventId, message: LogMessage, exception?: any, ): void { // insert your custom log logic } } ``` or ```js function MyCustomLogger() {} MyCustomLogger.prototype.log = function (level, eventId, message, exception) { // insert your custom log logic }; ``` then ```js // Set the `MyCustomLogger` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: new MyCustomLogger(), }, ); ``` ### Log Filtering[​](#log-filtering "Direct link to Log Filtering") You can define a custom log filter by providing a callback function via the `logFilter` option. The callback will be called by the *ConfigCat SDK* each time a log event occurs (and the event passes the minimum log level specified by the `IConfigCatLogger.level` property). That is, the callback allows you to filter log events by `level`, `eventId`, `message` or `exception`. The formatted message string can be obtained via `message.toString()`. If the callback function returns `true`, the event will be logged, otherwise it will be skipped. ```js // Filter out events with id 1001 from the log. const logFilter = (level, eventId, message, exception) => eventId != 1001; const configCatClient = configcat.getClient( "#YOUR-SDK-KEY#", configcat.PollingMode.AutoPoll, { logFilter: logFilter } ); ``` caution Please make sure that your log filter logic doesn't perform heavy computation. A complex or incorrectly implemented log filter can degrade the performance of the SDK. ## `getAllKeysAsync()`[​](#getallkeysasync "Direct link to getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeysAsync()` method. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); const keys = await configCatClient.getAllKeysAsync(); console.log(keys); ``` ## `getAllValuesAsync()`[​](#getallvaluesasync "Direct link to getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValuesAsync(); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValuesAsync(userObject); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); ``` ## `getAllValueDetailsAsync()`[​](#getallvaluedetailsasync "Direct link to getallvaluedetailsasync") Evaluates and returns the values along with evaluation details of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValueDetailsAsync(); settingValues.forEach((details) => console.log(details)); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValueDetailsAsync(userObject); settingValues.forEach((details) => console.log(details)); ``` ## Using custom cache implementation[​](#using-custom-cache-implementation "Direct link to Using custom cache implementation") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) interface and set the `cache` property in the options passed to `getClient`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```ts class MyCustomCache implements IConfigCatCache { set(key: string, value: string): Promise | void { // insert your cache write logic here } get( key: string, ): Promise | string | null | undefined { // insert your cache read logic here } } ``` or ```js function MyCustomCache() {} MyCustomCache.prototype.set = function (key, value) { // insert your cache write logic here }; MyCustomCache.prototype.get = function (key) { // insert your cache read logic here }; ``` then ```js // Set the `MyCustomCache` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { cache: new MyCustomCache(), }, ); ``` info The JavaScript SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the *ConfigCat SDK* that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Platform compatibility[​](#platform-compatibility "Direct link to Platform compatibility") The SDK should be compatible with modern Chromium-based browsers and bundlers. The SDK is [tested](https://github.com/configcat/js-unified-sdk/blob/master/.github/workflows/js-sdk-ci.yml) against the following browsers: * Chrome (stable, latest, beta) * Chromium (72.0.3626.0, 80.0.3987.0) The SDK is compatible with TypeScript v4.0.2 or newer. Earlier versions may work but those are not tested, thus, not supported officially. These tests are running on each pull request, before each deploy, and on a daily basis. You can view a sample run [here](https://github.com/configcat/js-unified-sdk/actions/runs/11745259578). ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [Sample Chrome extension](https://github.com/configcat/js-unified-sdk/tree/master/samples/chrome-extension) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) * [ConfigCat SDK for JavaScript in NPM](https://www.npmjs.com/package/@configcat/sdk) --- # Source: https://configcat.com/docs/glossary/ci-cd-pipeline.md # CI/CD Pipeline - Streamlining Software Delivery Copy page ## Introduction[​](#introduction "Direct link to Introduction") In the ever-evolving realm of software development, efficiency and speed are paramount. The CI/CD pipeline emerges as a cornerstone in achieving these goals, merging coding, testing, and deployment into a streamlined and automated process. Let’s unpack the components of CI/CD pipelines and their impact on software delivery. ## What is a CI/CD Pipeline?[​](#what-is-a-cicd-pipeline "Direct link to What is a CI/CD Pipeline?") CI/CD stands for Continuous Integration and Continuous Deployment/Delivery. This method introduces automation into the development process to enable frequent application delivery to customers. The primary concepts central to CI/CD include continuous integration, continuous delivery, and continuous deployment. ## The Objectives of a CI/CD Pipeline[​](#the-objectives-of-a-cicd-pipeline "Direct link to The Objectives of a CI/CD Pipeline") * **Rapid Deployment**: Facilitating frequent and reliable software updates. * **Quality Assurance**: Ensuring consistent quality and performance through automated testing. * **Risk Reduction**: Minimizing errors and issues in production through early detection. * **Efficient Development**: Streamlining the development process for faster turnaround times. ## The CI/CD Pipeline Process[​](#the-cicd-pipeline-process "Direct link to The CI/CD Pipeline Process") * **Code Integration**: Developers merge their changes into a shared repository, triggering automated builds and tests. * **Automated Testing**: The integrated code is automatically tested for bugs, performance issues, and other potential problems. * **Deployment**: Upon successful testing, the code is deployed to a staging or production environment. * **Monitoring and Feedback**: Continuous monitoring of the application's performance and gathering feedback for future improvements. ## Why CI/CD Pipelines are Essential[​](#why-cicd-pipelines-are-essential "Direct link to Why CI/CD Pipelines are Essential") * **Speedy Deliveries**: Accelerates the process of getting software improvements to end-users. * **Enhanced Collaboration**: Fosters a collaborative environment where code integration and problem-solving happen in real-time. * **Adaptability**: Allows for quick adaptation to market changes and user feedback. * **Cost-Effectiveness**: Reduces costs associated with manual processes and delayed releases. ## Challenges in CI/CD Pipeline and Solutions[​](#challenges-in-cicd-pipeline-and-solutions "Direct link to Challenges in CI/CD Pipeline and Solutions") * **Complex Integration**: Integrating various tools and platforms can be challenging. Solution: Utilize versatile CI/CD tools that offer broad integration capabilities. * **Security Concerns**: Continuous deployment could introduce security vulnerabilities. Solution: Implement robust security checks within the pipeline. * **Managing Dependencies**: Handling dependencies in a constantly changing environment. Solution: Effective dependency management strategies and tools. ## Conclusion[​](#conclusion "Direct link to Conclusion") The CI/CD pipeline is more than just a development strategy; it’s a catalyst for agility, quality, and innovation in software development. By embracing the utility of CI/CD pipelines, organizations can ensure that they not only keep pace with market demands but also drive forward with efficiency and precision. As the backbone of modern DevOps practices, the CI/CD pipeline stands as an essential element in the journey towards streamlined, resilient, and customer-centric software delivery. --- # Source: https://configcat.com/docs/advanced/code-references/circleci-orb.md # CircleCI Orb - Scan your source code for feature flags Copy page This section describes how to use ConfigCat's [CircleCI Orb](https://circleci.com/developer/orbs/orb/configcat/scan-repository) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. You can find more information about CircleCI Orbs [here](https://circleci.com/orbs/). ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in [CircleCI Environment Variables](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project) with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![CircleCI Orb secrets](/docs/assets/cli/scan/cco_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Create a new CircleCI YAML config in your repository under the `.circleci` folder, and put the following snippet into it. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml version: 2.1 orbs: configcat: configcat/scan-repository@1.11.1 workflows: main: jobs: - configcat/scan: config-id: PASTE-YOUR-CONFIG-ID-HERE # required file-url-template: 'https://github.com/your/repo/blob/{commitHash}/{filePath}#L{lineNumber}' # optional commit-url-template: 'https://github.com/your/repo/commit/{commitHash}' # optional # line-count: 3 # optional # timeout: 1800 # optional # sub-folder: 'src' # optional # exclude-keys: > # optional # flag_key_to_exclude_1 # flag_key_to_exclude_2 # alias-patterns: (\w+) = :CC_KEY,const (\w+) = feature_flags\.enabled\(:CC_KEY\) # optional # usage-patterns: feature_flags\.enabled\(:CC_KEY\) # optional # verbose: true # optional ``` 4. Commit & push your changes. The above example configures a workflow that executes the scan and code reference upload on every git `push` event. Scan reports are uploaded for each branch of your repository that triggers the workflow. ## Available Options[​](#available-options "Direct link to Available Options") | Parameter | Description | Required | Default | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------- | | `config-id` | ID of the ConfigCat config to scan against. | ☑ | | | `api-host` | ConfigCat Management API host. | | `api.configcat.com` | | `api-user` | Name of the environment variable where the [ConfigCat Management API basic authentication username](https://app.configcat.com/my-account/public-api-credentials) is stored. | | CONFIGCAT\_API\_USER | | `api-pass` | Name of the environment variable where the [ConfigCat Management API basic authentication password](https://app.configcat.com/my-account/public-api-credentials) is stored. | | CONFIGCAT\_API\_PASS | | `file-url-template` | Template url used to generate VCS file links. Available template parameters: `commitHash`, `filePath`, `lineNumber`. Example: `https://github.com/my/repo/blob/{commitHash}/{filePath}#L{lineNumber}` | | | | `commit-url-template` | Template url used to generate VCS commit links. Available template parameters: `commitHash`. Example: `https://github.com/my/repo/commit/{commitHash}` | | | | `line-count` | Context line count before and after the reference line. (min: 1, max: 10) | | 4 | | `timeout` | Scan timeout in seconds (default: 1800, min: 60). If the scan does not finish within this time, it is aborted. No partial results are returned. The command exits with a timeout error. | | 1800 | | `sub-folder` | Sub-folder to scan, relative to the repository root folder. | | | | `exclude-keys` | List of feature flag keys that must be excluded from the scan report. | | | | `alias-patterns` | Comma delimited list of custom regex patterns used to search for additional aliases. | | | | `usage-patterns` | Comma delimited list of custom regex patterns that describe additional feature flag key usages. | | | | `verbose` | Turns on detailed logging. | | false | --- # Source: https://configcat.com/docs/integrations/circleci.md # CircleCI - Scan your code for feature flag usages Copy page ConfigCat's [CircleCI Orb](https://circleci.com/developer/orbs/orb/configcat/scan-repository) has the ability to scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. This feature makes the elimination of the technical debt easier, as it can show which repositories reference your feature flags and settings in one centralized place on your [Dashboard](https://app.configcat.com). [Here](https://configcat.com/docs/advanced/code-references/overview.md) you can find more details about how this feature works. This section describes how to use ConfigCat's [CircleCI Orb](https://circleci.com/developer/orbs/orb/configcat/scan-repository) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. You can find more information about CircleCI Orbs [here](https://circleci.com/orbs/). ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in [CircleCI Environment Variables](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project) with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![CircleCI Orb secrets](/docs/assets/cli/scan/cco_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Create a new CircleCI YAML config in your repository under the `.circleci` folder, and put the following snippet into it. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml version: 2.1 orbs: configcat: configcat/scan-repository@1.11.1 workflows: main: jobs: - configcat/scan: config-id: PASTE-YOUR-CONFIG-ID-HERE # required file-url-template: 'https://github.com/your/repo/blob/{commitHash}/{filePath}#L{lineNumber}' # optional commit-url-template: 'https://github.com/your/repo/commit/{commitHash}' # optional # line-count: 3 # optional # timeout: 1800 # optional # sub-folder: 'src' # optional # exclude-keys: > # optional # flag_key_to_exclude_1 # flag_key_to_exclude_2 # alias-patterns: (\w+) = :CC_KEY,const (\w+) = feature_flags\.enabled\(:CC_KEY\) # optional # usage-patterns: feature_flags\.enabled\(:CC_KEY\) # optional # verbose: true # optional ``` 4. Commit & push your changes. The above example configures a workflow that executes the scan and code reference upload on every git `push` event. Scan reports are uploaded for each branch of your repository that triggers the workflow. ## Available Options[​](#available-options "Direct link to Available Options") | Parameter | Description | Required | Default | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------- | | `config-id` | ID of the ConfigCat config to scan against. | ☑ | | | `api-host` | ConfigCat Management API host. | | `api.configcat.com` | | `api-user` | Name of the environment variable where the [ConfigCat Management API basic authentication username](https://app.configcat.com/my-account/public-api-credentials) is stored. | | CONFIGCAT\_API\_USER | | `api-pass` | Name of the environment variable where the [ConfigCat Management API basic authentication password](https://app.configcat.com/my-account/public-api-credentials) is stored. | | CONFIGCAT\_API\_PASS | | `file-url-template` | Template url used to generate VCS file links. Available template parameters: `commitHash`, `filePath`, `lineNumber`. Example: `https://github.com/my/repo/blob/{commitHash}/{filePath}#L{lineNumber}` | | | | `commit-url-template` | Template url used to generate VCS commit links. Available template parameters: `commitHash`. Example: `https://github.com/my/repo/commit/{commitHash}` | | | | `line-count` | Context line count before and after the reference line. (min: 1, max: 10) | | 4 | | `timeout` | Scan timeout in seconds (default: 1800, min: 60). If the scan does not finish within this time, it is aborted. No partial results are returned. The command exits with a timeout error. | | 1800 | | `sub-folder` | Sub-folder to scan, relative to the repository root folder. | | | | `exclude-keys` | List of feature flag keys that must be excluded from the scan report. | | | | `alias-patterns` | Comma delimited list of custom regex patterns used to search for additional aliases. | | | | `usage-patterns` | Comma delimited list of custom regex patterns that describe additional feature flag key usages. | | | | `verbose` | Turns on detailed logging. | | false | --- # Source: https://configcat.com/docs/advanced/cli.md # Command Line Interface (CLI) Copy page The [ConfigCat Command Line Interface (CLI)](https://github.com/configcat/cli) allows you to interact with the [Public Management API](https://configcat.com/docs/api/reference/configcat-public-management-api.md) via the command line. It supports most functionality found on the ConfigCat Dashboard. You can manage ConfigCat resources like Feature Flags, Targeting / Percentage rules, Products, Configs, Environments, and more. The CLI also has the ability to [scan your source code](https://configcat.com/docs/advanced/code-references/overview.md) for feature flag and setting usage and upload the found code references to ConfigCat. Finally, the CLI provides a few useful utilities, such as validating a config JSON file, downloading one from the ConfigCat CDN by SDK Key, etc. These can come in handy when you use [flag overrides](https://configcat.com/docs/sdk-reference/js/overview.md#flag-overrides) in your application. ```text configcat This is the Command Line Tool of ConfigCat. ConfigCat is a hosted feature flag service: https://configcat.com For more information, see the documentation here: https://configcat.com/docs/advanced/cli Usage: configcat [command] [options] Options: -v, --verbose Print detailed execution information -ni, --non-interactive Turn off progress rendering and interactive features --version Show version information -?, -h, --help Show help and usage information Commands: setup Setup the CLI with Public Management API host and credentials ls List all Product, Config, and Environment IDs p, product Manage Products c, config Manage Configs webhook, wh Manage Webhooks e, environment Manage Environments f, flag, s, setting Manage Feature Flags & Settings f2, flag-v2, s2, setting-v2 Manage V2 Feature Flags & Settings seg, segment Manage Segments permission-group, pg Manage Permission Groups m, member Manage Members t, tag Manage Tags k, sdk-key List SDK Keys scan Scan files for Feature Flag & Setting usages eval Evaluate feature flags. In case of a single feature flag, by default, the command writes only the evaluated value to the output. In case of multiple feature flags, the command writes a table if no other format is specified config-json Config JSON-related utilities w, workspace Manage the CLI workspace. When set, the CLI's interactive mode filters Product and Config selectors by the values set in the workspace Use "configcat [command] -?" for more information about a command. ``` ## Reference[​](#reference "Direct link to Reference") See the [command reference documentation](https://configcat.github.io/cli/) for more information about each available command. ## Getting started[​](#getting-started "Direct link to Getting started") The following instructions will guide you through the first steps to start using this tool. ### Installation[​](#installation "Direct link to Installation") You can install the CLI on multiple operating systems using the following sources. **Homebrew (macOS / Linux)** Install the CLI with [Homebrew](https://brew.sh) from [ConfigCat's tap](https://github.com/configcat/homebrew-tap) by executing the following command: ```bash brew tap configcat/tap brew install configcat ``` **Snap (Linux)** Install the CLI with [Snapcraft](https://snapcraft.io) by executing the following command: ```bash sudo snap install configcat ``` **Scoop (Windows)** Install the CLI with [Scoop](https://scoop.sh) from [ConfigCat's bucket](https://github.com/configcat/scoop-configcat) by executing the following command: ```bash scoop bucket add configcat https://github.com/configcat/scoop-configcat scoop install configcat ``` **Chocolatey (Windows)** Install the CLI with [Chocolatey](https://chocolatey.org/) by executing the following command: ```powershell choco install configcat ``` **.NET tool / NuGet.org** The CLI can be installed as a [.NET tool](https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools) via the .NET SDK. ```bash dotnet tool install -g configcat-cli ``` After installing, you can execute the CLI using the `configcat` command: ```bash configcat scan "/repository" --print --config-id ``` **Docker** The CLI can be executed from a [Docker](https://www.docker.com/) image. ```bash docker pull configcat/cli ``` An example of how to scan a repository for feature flag & setting references with the docker image. ```bash docker run --rm \ --env CONFIGCAT_API_HOST= \ --env CONFIGCAT_API_USER= \ --env CONFIGCAT_API_PASS= \ -v /path/to/repository:/repository \ configcat/cli scan "/repository" --print --config-id ``` **Install Script** On Unix platforms, you can install the CLI by executing an install script. ```bash curl -fsSL "https://raw.githubusercontent.com/configcat/cli/main/scripts/install.sh" | bash ``` By default, the script downloads the OS specific artifact from the latest [GitHub Release](https://github.com/configcat/cli/releases) with `curl` and moves it into the `/usr/local/bin` directory. It might happen that you don't have permissions to write into `/usr/local/bin`, then you should execute the install script with `sudo`. ```bash curl -fsSL "https://raw.githubusercontent.com/configcat/cli/main/scripts/install.sh" | sudo bash ``` The script accepts the following input parameters: | Parameter | Description | Default value | | ----------------- | ------------------------------------------------ | ---------------- | | `-d`, `--dir` | The directory where the CLI should be installed. | `/usr/local/bin` | | `-v`, `--version` | The desired version to install. | `latest` | | `-a`, `--arch` | The desired architecture to install. | `x64` | Available **architecture** values for Linux: `x64`, `musl-x64`, `arm`, `arm64`. Available **architecture** values for macOS: `x64`, `arm64`. **Script usage examples**: *Custom installation directory*: ```bash curl -fsSL "https://raw.githubusercontent.com/configcat/cli/main/scripts/install.sh" | bash -s -- -d=/path/to/install ``` *Install a different version*: ```bash curl -fsSL "https://raw.githubusercontent.com/configcat/cli/main/scripts/install.sh" | bash -s -- -v=1.4.2 ``` *Install with custom architecture*: ```bash curl -fsSL "https://raw.githubusercontent.com/configcat/cli/main/scripts/install.sh" | bash -s -- -a=arm ``` **Standalone executables** You can download the executables directly from [GitHub Releases](https://github.com/configcat/cli/releases) for your desired platform. ### Setup[​](#setup "Direct link to Setup") After a successful installation, the CLI must be set up with your [ConfigCat Public Management API credentials](https://app.configcat.com/my-account/public-api-credentials). You can do this by using the `configcat setup` command. ![interactive](/docs/assets/cli/cli-setup.gif) #### Environment variables[​](#environment-variables "Direct link to Environment variables") Besides the `setup` command above, the CLI can read your credentials from the following environment variables. | Name | Description | | -------------------- | ---------------------------------------- | | `CONFIGCAT_API_HOST` | API host (default: `api.configcat.com`). | | `CONFIGCAT_API_USER` | API basic auth user name. | | `CONFIGCAT_API_PASS` | API basic auth password. | caution When any of these environment variables are set, the CLI will use them over the local values set by the `configcat setup` command. ## Modes[​](#modes "Direct link to Modes") The CLI supports both interactive and argument driven execution. When no arguments provided for a command and user input is enabled (stdout is not redirected), the CLI automatically activates interactive mode. ### Interactive[​](#interactive "Direct link to Interactive") ![interactive](/docs/assets/cli/cli-flag-create.gif) ### With arguments[​](#with-arguments "Direct link to With arguments") The same operation with command arguments would look like this: ```bash configcat flag-v2 create \ --config-id \ --name "My awesome feature" \ --hint "This is my awesome feature" \ --key my_awesome_feature --type boolean \ --tag-ids \ --init-values-per-environment : \ ``` info Each `create` command writes the newly created resource's ID to the standard output so you can save that for further operations. Example: ```bash #!/bin/bash ORGANIZATION_ID="" PRODUCT_ID=$(configcat product create -o $ORGANIZATION_ID -n "") CONFIG_ID=$(configcat config create -p $PRODUCT_ID -n "") ``` info You can change the output format of several commands' result to JSON with the `--json` option, like: `configcat flag ls --json`. See more about these commands in the [command reference documentation](https://configcat.github.io/cli/). ## Scan & upload code references[​](#scan--upload-code-references "Direct link to Scan & upload code references") The CLI has the ability to scan your source code for feature flag and setting usage and upload the found code references to ConfigCat. You can read more about this feature [here](https://configcat.com/docs/advanced/code-references/overview.md). ## Examples[​](#examples "Direct link to Examples") Here are a few examples showing the true power of the CLI. ### Create a feature flag[​](#create-a-feature-flag "Direct link to Create a feature flag") The following example shows how you can create a feature flag in a specific config. ![create flag](/docs/assets/cli/cli-flag-create.gif) ### Evaluate feature flags[​](#evaluate-feature-flags "Direct link to Evaluate feature flags") The following example shows how you can evaluate one or more feature flags. ![evaluate flags](/docs/assets/cli/cli-eval.gif) ### Feature flag value update[​](#feature-flag-value-update "Direct link to Feature flag value update") The following example shows how you can update the value of a feature flag in a specific environment. ![flag value update](/docs/assets/cli/cli-flag-update.gif) ### Add targeting rules[​](#add-targeting-rules "Direct link to Add targeting rules") The following example shows how you can add targeting rules to a feature flag. ![flag targeting add](/docs/assets/cli/cli-flag-targeting-add.gif) ### Add percentage options[​](#add-percentage-options "Direct link to Add percentage options") The following example shows how you can set percentage options in a feature flag. ![flag percentage add](/docs/assets/cli/cli-flag-targeting-percentage.gif) --- # Source: https://configcat.com/docs/sdk-reference/js/cloudflare-worker.md # Cloudflare Worker SDK Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/js-unified-sdk.svg?style=social)](https://github.com/configcat/js-unified-sdk/stargazers) [![JS SDK CI](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml/badge.svg?branch=master)](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml) [![SonarCloud Coverage](https://img.shields.io/sonar/coverage/configcat_js-unified-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_js-unified-sdk) [![Known Vulnerabilities](https://snyk.io/test/github/configcat/js-unified-sdk/badge.svg?targetFile=package.json)](https://snyk.io/test/github/configcat/js-unified-sdk?targetFile=package.json) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=configcat_js-sdk\&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=configcat_js-sdk) [![JSDELIVR](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge)](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge) [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install and import package[​](#1-install-and-import-package "Direct link to 1. Install and import package") First install the [NPM package](https://npmjs.com/package/@configcat/sdk): ```bash npm i @configcat/sdk ``` Then import it into your application: ```js import * as configcat from "@configcat/sdk/cloudflare-worker"; ``` ### 2. Create the *ConfigCat* client with your SDK Key[​](#2-create-the-configcat-client-with-your-sdk-key "Direct link to 2-create-the-configcat-client-with-your-sdk-key") ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#', configcat.PollingMode.LazyLoad); ``` ### 3. Get your setting value[​](#3-get-your-setting-value "Direct link to 3. Get your setting value") The async/await way: ```js const value = await configCatClient.getValueAsync( 'isMyAwesomeFeatureEnabled', false, ); if (value) { do_the_new_thing(); } else { do_the_old_thing(); } ``` The Promise way: ```js configCatClient .getValueAsync('isMyAwesomeFeatureEnabled', false) .then((value) => { if (value) { do_the_new_thing(); } else { do_the_old_thing(); } }); ``` The *ConfigCat SDK* also offers a synchronous API for feature flag evaluation. Read more [here](#snapshots-and-synchronous-feature-flag-evaluation). ### 4. Dispose the *ConfigCat* client[​](#4-dispose-the-configcat-client "Direct link to 4-dispose-the-configcat-client") You can safely dispose all clients at once or individually and release all associated resources on application exit. ```js configcat.disposeAllClients(); // disposes all clients // -or- configCatClient.dispose(); // disposes a specific client ``` ## Creating the *ConfigCat* Client[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `configcat.getClient('')` returns a client with default options. The `getClient` function has optional parameters, which can be used to adjust the behavior of the client. | Parameters | Description | Default | | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | | `sdkKey` | **REQUIRED.** SDK Key to access your feature flags and settings. Get it from *ConfigCat Dashboard*. | - | | `pollingMode` | Optional. The polling mode to use to fetch the config data from the ConfigCat CDN. [More about polling modes](#polling-modes). | `PollingMode.AutoPoll` | | `options` | Optional. The options object. See the table below. | - | The available options depends on the chosen polling mode. However, there are some common options which can be set in the case of every polling mode: | Option Parameter | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `configFetcher` | Custom [`IConfigCatConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigFetcher.ts) instance for downloading a config. | [`FetchApiConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/shared/FetchApiConfigFetcher.ts) | | `cache` | Custom [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) implementation for caching the downloaded config. | [`CloudflareConfigCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/cloudflare-worker/CloudflareConfigCache.ts) | | `logger` | Custom [`IConfigCatLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) implementation for tracing. | [`ConfigCatConsoleLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) (with WARN level) | | `logFilter` | Sets a custom log filter. [More about log filtering](#log-filtering). | `undefined` (none) | | `baseUrl` | Sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | | `requestTimeoutMs` | The amount of milliseconds the SDK waits for a response from the ConfigCat servers before returning values from the cache. | 30000 | | `flagOverrides` | Local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | | `dataGovernance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `DataGovernance.Global`, `DataGovernance.EuOnly`. | `DataGovernance.Global` | | `defaultUser` | Sets the default user. [More about default user](#default-user). | `undefined` (none) | | `offline` | Determines whether the client should be initialized to offline mode. [More about offline mode](#online--offline-mode). | `false` | Options also include a property named `setupHook`, which you can use to subscribe to the hooks (events) at the time of initialization. [More about hooks](#hooks). For example: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('clientReady', function() { const keys = this.configCatClient.snapshot().getAllKeys(); console.log(`Client is ready! Number of available feature flags: ${keys.length}`); }), }, ); ``` info You can acquire singleton client instances for your SDK keys using the `configcat.getClient(sdkKey: "")` factory function. (However, please keep in mind that subsequent calls to `getClient()` with the *same SDK Key* return a *shared* client instance, which was set up by the first call.) You can close all open clients at once using the `configcat.disposeAllClients()` function or do it individually using the `configCatClient.dispose()` method. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") Returns a Promise with the value. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((value) => { console.log(value); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | `typeof defaultValue` | | -------------- | --------------------- | | On/Off Toggle | `boolean` | | Text | `string` | | Whole Number | `number` | | Decimal Number | `number` | In addition to the types mentioned above, you also have the option to provide `null` or `undefined` for the `defaultValue` parameter regardless of the setting kind. However, if you do so, the return type of the `getValue` method will be * `boolean | string | number | null` when `defaultValue` is `null` or * `boolean | string | number | undefined` when `defaultValue` is `undefined`. This is because in these cases the exact return type cannot be determined at compile-time as the TypeScript compiler has no information about the setting type. It's important to note that providing any other type for the `defaultValue` parameter will result in a `TypeError`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueDetailsAsync()`[​](#anatomy-of-getvaluedetailsasync "Direct link to anatomy-of-getvaluedetailsasync") `getValueDetailsAsync()` is similar to `getValueAsync()` but instead of returning the evaluated value only, it provides more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const details = await configCatClient.getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((details) => { console.log(details); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `key` | `string` | The key of the evaluated feature flag or setting. | | `value` | `boolean` / `string` / `number` | The evaluated value of the feature flag or setting. | | `user` | `User` | The User Object used for the evaluation. | | `isDefaultValue` | `boolean` | True when the default value passed to `getValueDetailsAsync()` is returned due to an error. | | `errorCode` | `EvaluationErrorCode` | In case of an error, this property contains a code that identifies the reason for the error. | | `errorMessage` | `string` | In case of an error, this property contains the error message. | | `errorException` | `any` | In case of an error, this property contains the related exception object (if any). | | `matchedTargetingRule` | `TargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matchedPercentageOption` | `PercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `fetchTime` | `Date` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. For simple targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; ``` ```js const userObject = { identifier: 'john@example.com' }; ``` | Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any `string` value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | For advanced targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#', email: 'john@example.com', country: 'United Kingdom', custom: { SubscriptionType: 'Pro', UserRole: 'Admin', }, }; ``` The `custom` dictionary also allows attribute values other than `string` values: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; userObject.custom = { Rating: 4.5, RegisteredAt: new Date('2023-11-22T12:34:56.000Z'), Roles: ['Role1', 'Role2'], }; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `string` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `number` values, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `number` values representing a second-based Unix timestamp, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `string`, * accept `string` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") It's possible to set a default User Object that will be used on feature flag and setting evaluation. It can be useful when your application has a single user only or rarely switches users. You can set the default User Object either on SDK initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { defaultUser: { identifier: 'john@example.com' }, }, ); ``` ...or using the `setDefaultUser()` method of the `configCatClient` object: ```js configCatClient.setDefaultUser({ identifier: 'john@example.com' }); ``` Whenever the evaluation methods like `getValueAsync()`, `getValueDetailsAsync()`, etc. are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); // The default user will be used in the evaluation process. const value = await configCatClient.getValueAsync('keyOfMyFeatureFlag', false); ``` When a `user` parameter is passed to the evaluation methods, it takes precedence over the default user. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); const otherUser = { identifier: 'brian@example.com' }; // otherUser will be used in the evaluation process. const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', false, otherUser, ); ``` You can also remove the default user by doing the following: ```js configCatClient.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValueAsync()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. [More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `pollIntervalSeconds` option parameter to change the polling interval. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { pollIntervalSeconds: 95, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `pollIntervalSeconds` | Polling interval in seconds. | 60s | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5s | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValueAsync()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValueAsync()` will return the setting value after the cache is updated. Use `cacheTimeToLiveSeconds` option parameter to set cache lifetime. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.LazyLoad, { cacheTimeToLiveSeconds: 600, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------- | ------- | | `cacheTimeToLiveSeconds` | Cache TTL in seconds. | 60s | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefreshAsync()` is your application's responsibility. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); await configCatClient.forceRefreshAsync(); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` > `getValueAsync()` returns `defaultValue` if the cache is empty. Call `forceRefreshAsync()` to update the cache. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); // console: "my default value" await configCatClient.forceRefreshAsync(); value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `clientReady: [cacheState: ClientCacheState]`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `cacheState` argument. * `configFetched: [result: RefreshResult, isInitiatedByUser: boolean]`: This event is emitted each time the client attempts to refresh the cached config by fetching the latest version from the ConfigCat CDN. It is emitted not only when `ForceRefreshAsync` is called but also when the refresh is initiated by the client automatically. Thus, this event allows you to observe potential network issues that occur under the hood. * `configChanged: [newConfig: IConfig]`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `flagEvaluated: [evaluationDetails: IEvaluationDetails]`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetailsAsync()`](#anatomy-of-getvaluedetailsasync). * `clientError: [message: string, exception?: any]`: This event is emitted when an error occurs within the client. You can subscribe to these events either on initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', function() { /* handle the event */ }), }, ); ``` ...or directly on the `ConfigCatClient` instance: ```js configCatClient.on('flagEvaluated', function() { /* handle the event */ }); ``` caution Some events (e.g. `clientReady`, `configChanged` and `clientError`) may be emitted before `getClient` returns. This means you may miss them unless you subscribe on initialization. However, even if you do, there's another gotcha: it's not safe to use the outer `configCatClient` variable in your event handler because it may not yet be assigned when the handler is called. Instead, you can safely access the client instance via `this.configCatClient` - provided that the event handler is a normal function, not an arrow function. ## Snapshots and synchronous feature flag evaluation[​](#snapshots-and-synchronous-feature-flag-evaluation "Direct link to Snapshots and synchronous feature flag evaluation") On JavaScript platforms, the *ConfigCat* client provides only asynchronous methods for evaluating feature flags and settings because these operations may involve network communication (e.g. downloading config data from the ConfigCat CDN servers), which is necessarily an asynchronous operation in JavaScript. However, there can be circumstances where synchronous evaluation is preferable, thus, since v8.1.0, the JavaScript SDK provides a way to synchronously evaluate feature flags and settings via *snapshots*. Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, ); // Wait for the client to initialize. await configCatClient.waitForReady(); const snapshot = configCatClient.snapshot(); const user = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; for (const key of snapshot.getAllKeys()) { const value = snapshot.getValue(key, null, user); console.log(`${key}: ${value}`); } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefreshAsync`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTimeSeconds` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```js const clientCacheState = await configCatClient.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { // Handle initialization failure (see below). console.warn('ConfigCat client failed to obtain the config data during initialization.'); } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `configChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases where you want to prevent the SDK from making HTTP calls, you can switch it to offline mode: ```js configCatClient.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To switch the SDK back to online mode, do the following: ```js configCatClient.setOnline(); ``` Using the `configCatClient.isOffline` property you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `{ [key: string]: boolean | string | number }` object, from the current query string or from a custom flag override data source. ### Map[​](#map "Direct link to Map") You can specify simple feature flag & setting overrides using a `{ [key: string]: boolean | string | number }` map. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: configcat.createFlagOverridesFromMap( { enabledFeature: true, disabledFeature: false, intSetting: 5, doubleSetting: 3.14, stringSetting: 'test', }, configcat.OverrideBehaviour.LocalOnly, ), }, ); ``` ### Query string[​](#query-string "Direct link to Query string") It is also possible to override feature flags & settings using query string parameters. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: createFlagOverridesFromQueryParams(configcat.OverrideBehaviour.LocalOverRemote, request), }, ); ``` With that setup, you can override feature flags and settings by appending query string parameters to the URL of your application in the following form: `https://app.example.com/?cc-myBooleanFlag=true&cc-myStringSetting=abc&...` The setting type is automatically inferred from the value. Please pay attention to this behavior. The inferred type of the value must match the type of the feature flag or setting you override (see also [this table](#setting-type-mapping)). In case you want to force a boolean or number value to be interpreted as a string value, use the `;str` suffix: `&cc-myStringSetting;str=true`. If the default prefix used to differentiate between normal and flag override query string parameters (`cc-`) is not suitable for you, you can set a custom prefix using the corresponding optional parameter of `createFlagOverridesFromQueryParams`. ### Custom data source implementation[​](#custom-data-source-implementation "Direct link to Custom data source implementation") You can create a custom flag override data source by implementing `IOverrideDataSource`. The SDK provides the `createSettingFromValue` function to create `Setting` objects from simple `boolean`, `string` and `number` values. In case you need complex (full-featured) flag overrides, you can use the `deserializeConfig` function to obtain `Setting` objects from a config JSON conforming to the [config JSON v6 format](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ```ts class MyCustomOverrideDataSource implements IOverrideDataSource { private settings: Record; constructor(configJson: string) { this.settings = deserializeConfig(configJson).f ?? {}; } getOverrides(): Record { return this.settings; } } ``` or ```js function MyCustomOverrideDataSource(configJson) { this.settings = deserializeConfig(configJson).f ?? {}; } MyCustomOverrideDataSource.prototype.getOverrides = function () { return this.settings; }; ``` then ```js // Set the `MyCustomOverrideDataSource` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: { dataSource: new MyCustomOverrideDataSource('{ "f": { ... } }'), behaviour: configcat.OverrideBehaviour.LocalOnly, } }, ); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: configcat.createConsoleLogger(configcat.LogLevel.Info), // Setting log level to Info }, ); ``` Available log levels: | Level | Description | | ----- | ------------------------------------------------------- | | Off | Nothing gets logged. | | Error | Only error level events are logged. | | Warn | Default. Errors and Warnings are logged. | | Info | Errors, Warnings and feature flag evaluation is logged. | | Debug | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash ConfigCat - INFO - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"#SOME-USER-ID#","Email":"configcat@example.com"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") The SDK provides a simple logger implementation that logs to [the debugging console](https://developer.mozilla.org/en-US/docs/Web/API/console) (`configcat.createConsoleLogger(...)`) but it also allows you to inject any custom implementation of `IConfigCatLogger`. ```ts class MyCustomLogger implements IConfigCatLogger { /** * Writes an event into the log. * @param level Event severity level. * @param eventId Event identifier. * @param message Message. * @param exception The exception object related to the message (if any). */ log( level: LogLevel, eventId: LogEventId, message: LogMessage, exception?: any, ): void { // insert your custom log logic } } ``` or ```js function MyCustomLogger() {} MyCustomLogger.prototype.log = function (level, eventId, message, exception) { // insert your custom log logic }; ``` then ```js // Set the `MyCustomLogger` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: new MyCustomLogger(), }, ); ``` ### Log Filtering[​](#log-filtering "Direct link to Log Filtering") You can define a custom log filter by providing a callback function via the `logFilter` option. The callback will be called by the *ConfigCat SDK* each time a log event occurs (and the event passes the minimum log level specified by the `IConfigCatLogger.level` property). That is, the callback allows you to filter log events by `level`, `eventId`, `message` or `exception`. The formatted message string can be obtained via `message.toString()`. If the callback function returns `true`, the event will be logged, otherwise it will be skipped. ```js // Filter out events with id 1001 from the log. const logFilter = (level, eventId, message, exception) => eventId != 1001; const configCatClient = configcat.getClient( "#YOUR-SDK-KEY#", configcat.PollingMode.AutoPoll, { logFilter: logFilter } ); ``` caution Please make sure that your log filter logic doesn't perform heavy computation. A complex or incorrectly implemented log filter can degrade the performance of the SDK. ## `getAllKeysAsync()`[​](#getallkeysasync "Direct link to getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeysAsync()` method. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); const keys = await configCatClient.getAllKeysAsync(); console.log(keys); ``` ## `getAllValuesAsync()`[​](#getallvaluesasync "Direct link to getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValuesAsync(); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValuesAsync(userObject); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); ``` ## `getAllValueDetailsAsync()`[​](#getallvaluedetailsasync "Direct link to getallvaluedetailsasync") Evaluates and returns the values along with evaluation details of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValueDetailsAsync(); settingValues.forEach((details) => console.log(details)); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValueDetailsAsync(userObject); settingValues.forEach((details) => console.log(details)); ``` ## Using custom cache implementation[​](#using-custom-cache-implementation "Direct link to Using custom cache implementation") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) interface and set the `cache` property in the options passed to `getClient`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```ts class MyCustomCache implements IConfigCatCache { set(key: string, value: string): Promise | void { // insert your cache write logic here } get( key: string, ): Promise | string | null | undefined { // insert your cache read logic here } } ``` or ```js function MyCustomCache() {} MyCustomCache.prototype.set = function (key, value) { // insert your cache write logic here }; MyCustomCache.prototype.get = function (key) { // insert your cache read logic here }; ``` then ```js // Set the `MyCustomCache` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { cache: new MyCustomCache(), }, ); ``` info The JavaScript SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the *ConfigCat SDK* that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Platform compatibility[​](#platform-compatibility "Direct link to Platform compatibility") The SDK should be compatible with latest versions of [workerd](https://github.com/cloudflare/workerd). The SDK is [tested](https://github.com/configcat/js-unified-sdk/blob/master/.github/workflows/js-sdk-ci.yml) against the following runtimes: * Workerd (2023-02-28) The SDK is compatible with TypeScript v4.0.2 or newer. Earlier versions may work but those are not tested, thus, not supported officially. These tests are running on each pull request, before each deploy, and on a daily basis. You can view a sample run [here](https://github.com/configcat/js-unified-sdk/actions/runs/11745259578). ## Best practices[​](#best-practices "Direct link to Best practices") ### Choosing polling mode for serverless functions[​](#choosing-polling-mode-for-serverless-functions "Direct link to Choosing polling mode for serverless functions") Auto polling is not ideal for short-lived serverless functions like Cloudflare Workers. It is recommended to use the SDK in Lazy loading or Manual polling mode instead of the default Auto polling mode. ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [Sample Cloudflare Worker](https://github.com/configcat/js-unified-sdk/tree/master/samples/cloudflare-worker) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) * [ConfigCat SDK for JavaScript in NPM](https://www.npmjs.com/package/@configcat/sdk) --- # Source: https://configcat.com/docs/advanced/team-management/saml/identity-providers/cloudflare.md # Cloudflare Zero Trust Copy page Connect ConfigCat with Cloudflare Zero Trust via SAML. ## Introduction[​](#introduction "Direct link to Introduction") Each SSO Identity Provider requires specific information to configure a SAML integration. The following guide will walk you through how you can connect ConfigCat with Cloudflare Zero Trust as a SAML Identity Provider. ## 1. Create an Application in Cloudflare[​](#1-create-an-application-in-cloudflare "Direct link to 1. Create an Application in Cloudflare") * Log in to [CloudFlare](https://dash.cloudflare.com/), go to the Zero Trust Dashboard, and select `Applications` under the `Access` menu.
Then click on `Add an application`. ![Create Cloudflare application](/docs/assets/saml/cloudflare/add_app.png) * Select `SaaS`. ![Select SaaS](/docs/assets/saml/cloudflare/add_saas.png) * Enter a descriptive name in the `Application` field. ![Cloudflare app name](/docs/assets/saml/cloudflare/app_name.png) The next step will guide you on how to collect the information required for the appearing configuration section. ## 2. Configure SAML for the Cloudflare Application[​](#2-configure-saml-for-the-cloudflare-application "Direct link to 2. Configure SAML for the Cloudflare Application") * Open your organization's authentication settings on the [ConfigCat Dashboard](https://app.configcat.com/organization/authentication). ![ConfigCat authentication settings](/docs/assets/saml/dashboard/authentication.png) * Click `ADD SAML IDENTITY PROVIDER`. ![ConfigCat Add Identity Provider](/docs/assets/saml/dashboard/add_idp.png) * Give a name for your Identity Provider, and click `Create`. ![ConfigCat Name Identity Provider](/docs/assets/saml/dashboard/cf_name.png) * From the next section of the dialog, copy the following values and paste them into the Cloudflare application. * `Entity ID` -> `Entity ID` * `Assertion Consumer Service` -> `Assertion Consumer Service URL` ![ConfigCat SAML configuration](/docs/assets/saml/dashboard/acs_entity_id_1.png) ![Cloudflare SAML url EID](/docs/assets/saml/cloudflare/meta.png) * Set the `Name ID Format` to `Email`. ![Cloudflare SAML name id](/docs/assets/saml/cloudflare/name_id.png) * Click `Next` at the bottom of the page. ## 3. Configure policies for the Cloudflare Application[​](#3-configure-policies-for-the-cloudflare-application "Direct link to 3. Configure policies for the Cloudflare Application") To let users authenticate via SAML, you need to assign groups to the Cloudflare application. * Give a name for the Cloudflare Application's policy and check those groups that you want to assign. ![Cloudflare SAML name id](/docs/assets/saml/cloudflare/policy.png) * Click `Next` at the bottom of the page. ## 4. Configure ConfigCat with SAML Details from Cloudflare[​](#4-configure-configcat-with-saml-details-from-cloudflare "Direct link to 4. Configure ConfigCat with SAML Details from Cloudflare") * Copy the value of `SSO endpoint` and `Public key` fields. ![Cloudflare SSO url cert](/docs/assets/saml/cloudflare/cert_sign_on_url.png) * On the ConfigCat Dashboard, select the `3. Set up ConfigCat` step, click `Manual Configuration`, then paste the copied values into the appearing fields. * `SSO endpoint` -> `Sign-on URL` * `Public key` -> `X.509 Certificate` ![ConfigCat manual configuration](/docs/assets/saml/dashboard/cf_manual.png) ## 5. Select Trusted Domains on the SAML Configuration Dialog[​](#5-select-trusted-domains-on-the-saml-configuration-dialog "Direct link to 5. Select Trusted Domains on the SAML Configuration Dialog") * Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) * Click `Save`. ## 5. Sign In[​](#5-sign-in "Direct link to 5. Sign In") * Go to the [ConfigCat Log In](https://app.configcat.com) page, and click `COMPANY ACCOUNT - SAML`. ![ConfigCat SAML login](/docs/assets/saml/dashboard/saml_login.png) * Sign in with your company email address assigned to the Cloudflare application. ![ConfigCat SAML company login](/docs/assets/saml/dashboard/company_email.png) * ConfigCat will redirect you to Cloudflare's sign in page. ![Cloudflare sign in](/docs/assets/saml/cloudflare/login_page.png) ## 6. Next Steps[​](#6-next-steps "Direct link to 6. Next Steps") * Configure the [auto-assignment of users](https://configcat.com/docs/advanced/team-management/auto-assign-users.md). --- # Source: https://configcat.com/docs/api/reference/code-references.md # Code References Copy page With this endpoint you can upload Feature Flag and Setting usage references that will be shown on the ConfigCat Dashboard. [Here](https://configcat.com/docs/advanced/code-references/overview.md) you can read more about the concept of Code References. ## [📄️ Get References for Feature Flag or Setting](https://configcat.com/docs/api/reference/get-references-for-feature-flag-or-setting.md) ## [📄️ Delete Reference reports](https://configcat.com/docs/api/reference/delete-reference-reports.md) ## [📄️ Upload References](https://configcat.com/docs/api/reference/upload-references.md) --- # Source: https://configcat.com/docs/advanced/config-v2-migration-guide.md # Config V2 Migration Guide Copy page This guide will help you migrate from Config V1 to Config V2. ## What is Config V2?[​](#what-is-config-v2 "Direct link to What is Config V2?") **Config V2 is the next generation of ConfigCat.** It comes with a new Dashboard, Public Management API and SDKs. **Config V2 supports all the features of V1**, so you can continue using those, but **it offers interesting new features as well**. However, you won't be able to use the new features with the V1 versions of the Dashboard, Public Management API and SDKs. Read more about the new features in the [Config V2 Overview](https://configcat.com/docs/advanced/config-v2.md). ## A few things to consider before migration[​](#a-few-things-to-consider-before-migration "Direct link to A few things to consider before migration") * **Migration from Config V1 means that a V2 config will be copied from the V1 config. The V1 config will remain unchanged and accessible.** The V2 version will have a new SDK key for each environment. * **Config V2 and V1 are completely separate.** They don't affect each other in any way. You can use them side by side. * **There is no automatic sync between the V1 and V2 configs.** If you want to keep them in sync, you have to manually update the V2 config when you make changes to the V1 config and vice versa. * There is no pressure to migrate. Although we have plans to phase out V1 eventually, you can stay on it for a long time. * Once the migration process is started, it's recommended to migrate your V1 configs to V2 as quickly as possible to avoid confusion. * Keep in mind that the [integrations](https://app.configcat.com/integrations) and [webhooks](https://app.configcat.com/product/webhooks) connected to V1 configs are not migrated automatically and you have to set them up manually for the migrated V2 configs. * Every newly created config will be a V2 config by default. ## Migrating from Config V1 to Config V2[​](#migrating-from-config-v1-to-config-v2 "Direct link to Migrating from Config V1 to Config V2") The migration process starts with copying your V1 config to a new V2 one and updating your applications to use the new config. The complete process is the following: ### Step 1: Create the V2 config[​](#step-1-create-the-v2-config "Direct link to Step 1: Create the V2 config") 1. Open the ConfigCat Dashboard and click on the `Start migration` button on top of a V1 config. 2. Click `Create V2 config` to create a new config with the same settings as the V1 config. It's important to note that the V2 config will be created with the same settings as the V1 config and the V1 config will still be accessible and unchanged. ### Step 2: Upgrade the ConfigCat SDK version[​](#step-2-upgrade-the-configcat-sdk-version "Direct link to Step 2: Upgrade the ConfigCat SDK version") In your application, upgrade the ConfigCat SDK to the latest version. Old versions of the SDK will not be able to access the new config. Make sure you upgrade every application that uses the migrated V2 config. Here is a list of the SDKs that support Config V2: [See the supported SDK versions.](https://configcat.com/docs/advanced/config-v2-sdk-compatibility.md) ### Step 3: Update the ConfigCat SDK Key[​](#step-3-update-the-configcat-sdk-key "Direct link to Step 3: Update the ConfigCat SDK Key") In your application, replace the old ConfigCat SDK Key with the new one (i.e. with the one that belongs to the V2 version of the config) in every environment. The new key can be found on the ConfigCat Dashboard on the V2 config's page. ### Step 4: Deploy your application[​](#step-4-deploy-your-application "Direct link to Step 4: Deploy your application") Deploy your application to production and wait until all your users upgrade to the new version. You can check the migration status on the ConfigCat Dashboard under the migration status page that is available from a config's context menu in the sidebar. ### Step 5: Clean up[​](#step-5-clean-up "Direct link to Step 5: Clean up") After confirming that all your users have transitioned to the latest version of your application, you can finalize the migration by removing the V1 config. To verify that the V1 configs haven't been accessed for a significant period, check the migration status page accessible via a config's context menu in the sidebar. This step helps eliminate any mix-ups and prevents the unintended use of outdated configurations. caution Once you delete the V1 config, you won't be able to restore it. --- # Source: https://configcat.com/docs/advanced/config-v2-sdk-compatibility.md # Config V2 SDK Compatibility Copy page This table shows which SDK versions support Config V2. Read more about [Config V2](https://configcat.com/docs/advanced/config-v2.md) | SDK | Version | Release Notes | | ------------------------------------------------------------------------------- | ---------- | ----------------------------------------------------------------- | | .NET | >= v9.1.0 | | | Android (Java) | >= v10.1.0 | | | C++ | >= v4.0.0 | | | Dart (Flutter) | >= v4.1.0 | | | Elixir | >= v4.0.0 | | | Go | >= v9.0.3 | | | Java | >= v9.1.0 | | | JavaScript (Browser, Bun, Chromium Extension, Cloudflare Worker, Deno, Node.js) | >= v1.0.0 | | | JavaScript - Legacy | >= v9.5.0 | | | JavaScript (Chromium Extension) - Legacy | >= v2.4.0 | | | JavaScript (SSR) - Legacy | >= v8.4.0 | | | Kotlin Multiplatform | >= v3.0.0 | | | Node.js - Legacy | >= v11.3.0 | | | PHP 8.1+ | >= v9.1.0 | | | PHP 7.1+ | >= v3.0.0 | | | Python | >= v9.0.3 | | | React | >= v4.6.0 | | | Ruby | >= v8.0.0 | | | Rust | >= v0.1.0 | | | Swift (iOS) | >= v11.0.0 | | | Unreal Engine | >= v2.0.0 | | --- # Source: https://configcat.com/docs/advanced/config-v2.md # Config V2 Overview Copy page Config V2 is a new version of ConfigCat. It comes with a new Dashboard, Public Management API, SDKs, and features. ## What's new?[​](#whats-new "Direct link to What's new?") * A bunch of new features and improvements listed below. * New config editor UI on the Dashboard. * [New and improved config JSON schema.](https://github.com/configcat/config-json) * New API: [See the API Docs.](https://configcat.com/docs/api/reference/configcat-public-management-api.md) * New SDKs: [See the supported SDK versions.](https://configcat.com/docs/advanced/config-v2-sdk-compatibility.md) ## How to migrate from Config V1 to Config V2?[​](#how-to-migrate-from-config-v1-to-config-v2 "Direct link to How to migrate from Config V1 to Config V2?") See the [Config V2 Migration Guide](https://configcat.com/docs/advanced/config-v2-migration-guide.md). If you get stuck or have any questions about the migration, feel free to [contact us](https://configcat.com/support/). ## New features[​](#new-features "Direct link to New features") ### AND conditions[​](#and-conditions "Direct link to AND conditions") With AND conditions, you can define more complex Targeting Rules, such as "serve this value for the users who use my Android app AND whose email domain is '@example.com'". You can add multiple conditions to a Targeting Rule and they will be evaluated with an AND connection between them. ![AND conditions](/docs/assets/images/and-conditions-1885d725ca07feb98918be74caf847ac.png) ### New comparators[​](#new-comparators "Direct link to New comparators") With the new comparators, you can create Targeting Rules based on date comparisons, array comparisons, and more. * New text and confidential text comparators: `EQUALS`, `NOT EQUALS`, `STARTS WITH ANY OF`, `ENDS WITH ANY OF`, `NOT STARTS WITH ANY OF`, `NOT ENDS WITH ANY OF`. * New array comparators: `ARRAY CONTAINS ANY OF`, `ARRAY NOT CONTAINS ANY OF`. * New date comparators: `BEFORE`, `AFTER`. ![New comparators](/docs/assets/images/new-comparators-20f2a035bd85c2416e9bb89599234608.png) ### Prerequisite flags[​](#prerequisite-flags "Direct link to Prerequisite flags") With prerequisite flags, you can create feature flags that depend on other feature flags. Prerequisite feature flags (aka. master feature flag, inter-dependent feature flag, global toggle) are particularly useful for managing complex feature dependencies and ensuring a smooth user experience during feature rollouts. ![Prerequisite flags](/docs/assets/images/prerequisite-flags-8d735217aefdcab04a16517a782f13b1.png) ### Comparison value hints[​](#comparison-value-hints "Direct link to Comparison value hints") With comparison value hints, you can associate arbitrary text with your comparison values. This way you can add a description to your comparison value list items that helps you remember what they are for. ### Percentage Options within Targeting Rules[​](#percentage-options-within-targeting-rules "Direct link to Percentage Options within Targeting Rules") You can add Percentage Options to your Targeting Rules. This is useful if you want to create more complex Targeting Rules, such as "turn on the feature for 20% of the users who are on iOS, and off for 80%". ![Percentage Options within Targeting Rules](/docs/assets/images/percentage-options-within-targeting-rules-19525180c556b212b688a76daa59f754.png) ### Custom Percentage Attributes[​](#custom-percentage-attributes "Direct link to Custom Percentage Attributes") With custom Percentage Attributes, you can create Percentage Options based on custom attributes. This way you can create Percentage Options based on any of your user attributes. For example, you can create a Percentage Option that is based on the user's company or organization. So you can serve a value for 20% of the users from company A and serve another value for 80% of the users from company B. ![Custom Percentage Attributes](/docs/assets/images/custom-percentage-attributes-8b44f64042ed7947f08ccfa0b6f17c84.png) --- # Source: https://configcat.com/docs/api/reference/configcat-public-management-api.md Version: v1 # ConfigCat Public Management API Copy page The purpose of this API is to access the ConfigCat platform programmatically. You can **Create**, **Read**, **Update** and **Delete** any entities like **Feature Flags, Configs, Environments** or **Products** within ConfigCat. **Base API URL**: If you prefer the swagger documentation, you can find it here: [Swagger UI](https://api.configcat.com/swagger). The API is based on HTTP REST, uses resource-oriented URLs, status codes and supports JSON format. **Important:** Do not use this API for accessing and evaluating feature flag values. Use the [SDKs](https://configcat.com/docs/sdk-reference/overview.md) or the [ConfigCat Proxy](https://configcat.com/docs/advanced/proxy/proxy-overview.md) instead. ## OpenAPI Specification[​](#openapi-specification "Direct link to OpenAPI Specification") The complete specification is publicly available in the following formats: * [OpenAPI v3](https://api.configcat.com/docs/v1/swagger.json) * [Swagger v2](https://api.configcat.com/docs/v1/swagger.v2.json) You can use it to generate client libraries in various languages with [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator) or [Swagger Codegen](https://swagger.io/tools/swagger-codegen/) to interact with this API. ## Throttling and rate limits[​](#throttling-and-rate-limits "Direct link to Throttling and rate limits") All the rate limited API calls are returning information about the current rate limit period in the following HTTP headers: | Header | Description | | ---------------------- | -------------------------------------------------------------------------- | | X-Rate-Limit-Remaining | The maximum number of requests remaining in the current rate limit period. | | X-Rate-Limit-Reset | The time when the current rate limit period resets. | When the rate limit is exceeded by a request, the API returns with a `HTTP 429 - Too many requests` status along with a `Retry-After` HTTP header. ## Authentication[​](#authentication "Direct link to Authentication") * HTTP: Basic Auth To authenticate with the API you have to fill the `Authorization` HTTP request header with your Public API credentials. You can create your credentials on the [Public API credentials management page](https://app.configcat.com/my-account/public-api-credentials). | Security Scheme Type: | http | | -------------------------- | ----- | | HTTP Authorization Scheme: | basic | ### Contact ConfigCat: URL: ### Terms of Service --- # Source: https://configcat.com/docs/api/scim/configcat-user-provisioning-scim-api.md Version: v1 # ConfigCat User Provisioning (SCIM) API Copy page The purpose of this API is to allow user and group synchronization from your Identity Provider into a ConfigCat Organization via the SCIM protocol. [Here](https://configcat.com/docs/advanced/team-management/scim/scim-overview/) you can read more about the user provisioning process. **Base API URL**: `https://scim-api.configcat.com` ## OpenAPI Specification[​](#openapi-specification "Direct link to OpenAPI Specification") The complete specification is publicly available in the following formats: * [OpenAPI v3](https://scim-api.configcat.com/openapi/v1/openapi.json) ## Throttling and rate limits[​](#throttling-and-rate-limits "Direct link to Throttling and rate limits") All the rate limited API calls are returning information about the current rate limit period in the following HTTP headers: | Header | Description | | ---------------------- | -------------------------------------------------------------------------- | | X-Rate-Limit-Remaining | The maximum number of requests remaining in the current rate limit period. | | X-Rate-Limit-Reset | The time when the current rate limit period resets. | When the rate limit is exceeded by a request, the API returns with a `HTTP 429 - Too many requests` status along with a `Retry-After` HTTP header. ## Authentication[​](#authentication "Direct link to Authentication") * HTTP: Bearer Auth To authenticate with the API you have to fill the `Authorization` HTTP request header with your SCIM token. You can retrieve your credentials on the [Authentication & Provisioning page](https://app.configcat.com/organization/authentication). Example: `Bearer 12345abcdef` | Security Scheme Type: | http | | -------------------------- | ------ | | HTTP Authorization Scheme: | bearer | ### Contact ConfigCat: URL: ### Terms of Service --- # Source: https://configcat.com/docs/api/reference/configs.md # Configs Copy page With these endpoints you can manage your Configs. This also can be used to manage [Feature Flags and Settings](https://configcat.com/docs/api/reference/feature-flags-settings.md) and their [served values](https://configcat.com/docs/api/reference/feature-flag-setting-values.md) through this API. [Here](https://configcat.com/docs/main-concepts.md#config) you can read more about the concept of Configs. ## [📄️ List Configs](https://configcat.com/docs/api/reference/get-configs.md) [This endpoint returns the list of the Configs that belongs to the given Product identified by the](https://configcat.com/docs/api/reference/get-configs.md) ## [📄️ Create Config](https://configcat.com/docs/api/reference/create-config.md) [This endpoint creates a new Config in a specified Product](https://configcat.com/docs/api/reference/create-config.md) ## [📄️ Get Config](https://configcat.com/docs/api/reference/get-config.md) [This endpoint returns the metadata of a Config](https://configcat.com/docs/api/reference/get-config.md) ## [📄️ Update Config](https://configcat.com/docs/api/reference/update-config.md) [This endpoint updates a Config identified by the \`configId\` parameter.](https://configcat.com/docs/api/reference/update-config.md) ## [📄️ Delete Config](https://configcat.com/docs/api/reference/delete-config.md) [This endpoint removes a Config identified by the \`configId\` parameter.](https://configcat.com/docs/api/reference/delete-config.md) --- # Source: https://configcat.com/docs/glossary/continuous-integration.md # Continuous Integration - The Backbone of Modern Software Development Copy page ## Introduction[​](#introduction "Direct link to Introduction") In the rapidly evolving landscape of software development, Continuous Integration (CI) has emerged as an essential practice. It represents a fundamental shift in the approach to software building and testing, emphasizing speed, efficiency, and early error detection. Here, we explore the ins and outs of Continuous Integration and its pivotal role in modern software development. ## What is Continuous Integration?[​](#what-is-continuous-integration "Direct link to What is Continuous Integration?") Continuous Integration is a development practice where developers frequently merge their code changes into a central repository, usually several times a day. After each merge, automated builds and tests are run, ensuring that the new code integrates seamlessly with the existing codebase. ## The Objectives of Continuous Integration[​](#the-objectives-of-continuous-integration "Direct link to The Objectives of Continuous Integration") * **Early Problem Detection**: Identifying and resolving issues promptly, reducing the risk of compounded problems. * **Streamlined Development**: Facilitating smoother collaboration and integration among team members. * **Quality Assurance**: Maintaining a high standard of code quality through automated testing. * **Reduced Integration Costs**: Lowering the time and resources spent on fixing integration issues. ## The Continuous Integration Process[​](#the-continuous-integration-process "Direct link to The Continuous Integration Process") * **Commit Code Regularly**: Developers regularly commit small code changes to the central repository. * **Automated Builds**: Automated systems build the software with each new code commit. * **Automated Testing**: Running a suite of tests to ensure code quality and functionality. * **Immediate Feedback**: Providing developers with immediate feedback on the integration process. * **Rapid Issue Resolution**: Quickly addressing any integration or test failures. ## Why Continuous Integration is Essential[​](#why-continuous-integration-is-essential "Direct link to Why Continuous Integration is Essential") * **Improved Collaboration**: Encourages more frequent code integration, leading to better team collaboration. * **Increased Efficiency**: Reduces manual integration efforts, making the development process more efficient. * **Enhanced Code Quality**: Consistent testing ensures high code quality and reduces bugs in production. * **Faster Release Cycles**: Accelerates the process from development to deployment, enabling faster release cycles. ## Challenges in Continuous Integration and Solutions[​](#challenges-in-continuous-integration-and-solutions "Direct link to Challenges in Continuous Integration and Solutions") * **Maintaining Quality with Speed**: Balancing rapid integration with maintaining code quality. Solution: Implement robust automated testing frameworks. * **Managing Build Failures**: Addressing and preventing frequent build failures. Solution: Enforce coding standards and regular code reviews. * **Infrastructure Overheads**: Managing the infrastructure required for CI. Solution: Use cloud-based CI tools and services. ## Conclusion[​](#conclusion "Direct link to Conclusion") Continuous Integration stands as a transformative approach in software development. By automating the integration and testing process, it not only enhances efficiency and quality but also fosters a more collaborative and agile development environment. Embracing Continuous Integration is not just a choice but a necessity for teams aiming to excel in the competitive world of software development. --- # Source: https://configcat.com/docs/sdk-reference/cpp.md # C++ SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/cpp-sdk.svg?style=social)](https://github.com/configcat/cpp-sdk/stargazers) [![Build Status](https://img.shields.io/github/actions/workflow/status/configcat/cpp-sdk/cpp-ci.yml?logo=GitHub\&label=windows%20%2F%20macos%20%2F%20linux\&branch=main)](https://github.com/configcat/cpp-sdk/actions/workflows/cpp-ci.yml) [![Coverage Status](https://codecov.io/gh/configcat/cpp-sdk/branch/main/graph/badge.svg?token=cvUgfof8k7)](https://codecov.io/gh/configcat/cpp-sdk) [ConfigCat C++ SDK on GitHub](https://github.com/configcat/cpp-sdk) ## Getting Started[​](#getting-started "Direct link to Getting Started") ### 1. Add the ConfigCat SDK to your project[​](#1-add-the-configcat-sdk-to-your-project "Direct link to 1. Add the ConfigCat SDK to your project") With **[Vcpkg](https://github.com/microsoft/vcpkg)** * On Windows: ```cmd git clone https://github.com/microsoft/vcpkg .\vcpkg\bootstrap-vcpkg.bat .\vcpkg\vcpkg install configcat ``` In order to use vcpkg with Visual Studio, run the following command (may require administrator elevation): ```cmd .\vcpkg\vcpkg integrate install ``` After this, you can create a New non-CMake Project (or open an existing one). All installed libraries are immediately ready to be `#include`d and used in your project without additional setup. * On Linux/Mac: ```bash git clone https://github.com/microsoft/vcpkg ./vcpkg/bootstrap-vcpkg.sh ./vcpkg/vcpkg install configcat ``` ### 2. Include *configcat.h* header in your application code[​](#2-include-configcath-header-in-your-application-code "Direct link to 2-include-configcath-header-in-your-application-code") ```cpp #include using namespace configcat; ``` ### 3. Create the *ConfigCat* client with your *SDK Key*[​](#3-create-the-configcat-client-with-your-sdk-key "Direct link to 3-create-the-configcat-client-with-your-sdk-key") ```cpp auto client = ConfigCatClient::get("#YOUR-SDK-KEY#"); ``` ### 4. Get your setting value[​](#4-get-your-setting-value "Direct link to 4. Get your setting value") ```cpp bool isMyAwesomeFeatureEnabled = client->getValue("isMyAwesomeFeatureEnabled", false); if (isMyAwesomeFeatureEnabled) { doTheNewThing(); } else { doTheOldThing(); } ``` ### 5. Close *ConfigCat* client​[​](#5-close-configcat-client "Direct link to 5-close-configcat-client") You can safely shut down all clients at once or individually and release all associated resources on application exit. ```cpp ConfigCatClient::closeAll(); // closes all clients ConfigCatClient::close(client); // closes a specific client ``` ## Setting up the *ConfigCat Client*[​](#setting-up-the-configcat-client "Direct link to setting-up-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `ConfigCatClient::get("#YOUR-SDK-KEY#")` returns a client with default options. | Properties | Description | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `baseUrl` | Optional, sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | `dataGovernance` | Optional, defaults to `Global`. Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `Global`, `EuOnly`. | | `connectTimeoutMs` | Optional, defaults to `8000ms`. Sets the amount of milliseconds to wait for the server to make the initial connection (i.e. completing the TCP connection handshake). `0` means it never times out during transfer | | `readTimeoutMs` | Optional, defaults to `5000ms`. Sets the amount of milliseconds to wait for the server to respond before giving up. `0` means it never times out during transfer. | | `pollingMode` | Optional, sets the polling mode for the client. [More about polling modes](#polling-modes). | | `configCache` | Optional, sets a custom cache implementation for the client. [More about cache](#custom-cache). | | `logger` | Optional, sets the internal logger and log level. [More about logging](#logging). | | `flagOverrides` | Optional, sets the local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | `defaultUser` | Optional, sets the default user. [More about default user](#default-user). | | `offline` | Optional, defaults to `false`. Indicates whether the SDK should be initialized in offline mode. [More about offline mode](#online--offline-mode). | | `hooks` | Optional, used to subscribe events that the SDK sends in specific scenarios. [More about hooks](#hooks). | ```cpp ConfigCatOptions options; options.pollingMode = PollingMode::manualPoll(); auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` caution We strongly recommend you to use the `ConfigCatClient` as a Singleton object in your application. The `ConfigCatClient` constructs singleton client instances for your SDK keys with its `ConfigCatClient::get()` static factory method. These clients can be closed all at once with `ConfigCatClient::closeAll()` method or individually with the `ConfigCatClient::close(client)`. ## Anatomy of `getValue()`[​](#anatomy-of-getvalue "Direct link to anatomy-of-getvalue") | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```cpp auto user = ConfigCatUser::create("#USER-IDENTIFIER#"); auto value = client->getValue( "keyOfMySetting", // key false, // defaultValue user, // Optional User Object ); ``` caution It is important to choose the correct `getValue` overload, where the type of the `defaultValue` parameter matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | Type of `defaultValue` | | -------------- | ----------------------------- | | On/Off Toggle | `bool` | | Text | `std::string` / `const char*` | | Whole Number | `int32_t` | | Decimal Number | `double` | In addition to the overloads mentioned above, you also have the option to choose an overload that doesn't expect a default value. In that case any setting kind is allowed, and in case of error, the return value will be `std::nullopt`. If you specify a default value whose type mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueDetails()`[​](#anatomy-of-getvaluedetails "Direct link to anatomy-of-getvaluedetails") `getValueDetails()` is similar to `getValue()` but instead of returning the evaluated value only, it gives more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```cpp auto user = ConfigCatUser::create("#USER-IDENTIFIER#"); auto details = client->getValueDetails( "keyOfMySetting", // key false, // defaultValue user, // Optional User Object ); ``` caution It is important to choose the correct `getValueDetails` overload, where the type of the `defaultValue` parameter matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ----------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `value` | `std::optional` | The evaluated value of the feature flag or setting. | | `key` | `std::string` | The key of the evaluated feature flag or setting. | | `isDefaultValue` | `bool` | True when the default value passed to `getValueDetails()` is returned due to an error. | | `errorMessage` | `std::optional` | In case of an error, this field contains the error message. | | `errorException` | `std::exception_ptr` | In case of an error, this property contains the related exception object (if any). | | `user` | `std::shared_ptr` | The User Object that was used for evaluation. | | `matchedTargetingRule` | `std::optional` | The targeting rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matchedPercentageRule` | `std::optional` | The percentage option (if any) that was used to select the evaluated value. | | `fetchTime` | `std::chrono::time_point` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. ```cpp auto user = ConfigCatUser::create("#UNIQUE-USER-IDENTIFIER#"); ``` ```cpp auto user = ConfigCatUser::create("john@example.com"); ``` ### Customized User Object creation[​](#customized-user-object-creation "Direct link to Customized User Object creation") | Argument | Description | | --------- | ------------------------------------------------------------------------------------------------------------------------------- | | `id` | **REQUIRED.** Unique identifier of a user in your application. Can be any value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. e.g. User role, Subscription type. | ```cpp auto user = ConfigCatUser::create( "#UNIQUE-USER-IDENTIFIER#", // userID "john@example.com", // email "United Kingdom", // country { { "SubscriptionType", "Pro" }, { "UserRole", "Admin" } } // custom ); ``` The `custom` dictionary also allows attribute values other than `std::string` values: ```cpp auto user = ConfigCatUser::create( "#UNIQUE-USER-IDENTIFIER#", // userID "john@example.com", // email "United Kingdom", // country { { "Rating", 4.5 }, { "RegisteredAt", make_datetime(2023, 11, 22, 12, 34, 56) }, { "Roles", std::vector{"Role1", "Role2"} } } // custom ) ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `std::string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS\_ONE\_OF, etc.) * accept `std::string` values, * all other values are automatically converted to `std::string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS\_ONE\_OF\_SEMVER, LESS\_THAN\_SEMVER, GREATER\_THAN\_SEMVER, etc.) * accept `std::string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (EQUALS\_NUMBER, LESS\_THAN\_NUMBER, GREATER\_THAN\_OR\_EQUAL\_NUMBER, etc.) * accept `double` values and all other numeric values which can safely be converted to `double`, * accept `std::string` values containing a properly formatted, valid `double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE\_DATETIME / AFTER\_DATETIME) * accept `configcat::date_time_t` (`std::chrono::system_clock::time_point`) values, which are automatically converted to a second-based Unix timestamp, * accept `double` values representing a second-based Unix timestamp and all other numeric values which can safely be converted to `double`, * accept `std::string` values containing a properly formatted, valid `double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY\_CONTAINS\_ANY\_OF / ARRAY\_NOT\_CONTAINS\_ANY\_OF) * accept lists of `std::string` (i.e. `std::vector`), * accept `std::string` values containing a valid JSON string which can be deserialized to an array of `std::string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") There's an option to set a default User Object that will be used at feature flag and setting evaluation. It can be useful when your application has a single user only, or rarely switches users. You can set the default User Object either on SDK initialization: ```cpp ConfigCatOptions options; options.defaultUser = ConfigCatUser::create("john@example.com"); auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` or with the `setDefaultUser()` method of the ConfigCat client. ```cpp client->setDefaultUser(ConfigCatUser::create("john@example.com")); ``` Whenever the `getValue()`, `getValueDetails()`, `getAllValues()`, or `getAllValueDetails()` methods are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```cpp auto user = ConfigCatUser::create("john@example.com"); client->setDefaultUser(user); // The default user will be used at the evaluation process. auto value = client->getValue("keyOfMySetting", false); ``` When the `user` parameter is specified on the requesting method, it takes precedence over the default user. ```cpp auto user = ConfigCatUser::create("john@example.com"); client->setDefaultUser(user); auto otherUser = ConfigCatUser::create("brian@example.com"); // otherUser will be used at the evaluation process. auto value = client->getValue("keyOfMySetting", false, otherUser.get()); ``` For deleting the default user, you can do the following: ```cpp client->clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValue()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle.
[More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `autoPollIntervalInSeconds` option parameter of the `PollingMode::autoPoll()` to change the polling interval. ```cpp auto autoPollIntervalInSeconds = 100; ConfigCatOptions options; options.pollingMode = PollingMode::autoPoll(autoPollIntervalInSeconds); auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` Available options: | Option Parameter | Description | Default | | --------------------------- | --------------------------------------------------------------------------------------------------- | ------- | | `autoPollIntervalInSeconds` | Polling interval. | 60 | | `maxInitWaitTimeInSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5 | ### Lazy Loading[​](#lazy-loading "Direct link to Lazy Loading") When calling `getValue()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValue()` will return the setting value after the cache is updated. Use the `cacheRefreshIntervalInSeconds` option parameter of the `PollingMode::lazyLoad()` to set cache lifetime. ```cpp auto cacheRefreshIntervalInSeconds = 100; ConfigCatOptions options; options.pollingMode = PollingMode::lazyLoad(cacheRefreshIntervalInSeconds); auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` Available options: | Parameter | Description | Default | | ------------------------------- | ----------- | ------- | | `cacheRefreshIntervalInSeconds` | Cache TTL. | 60 | ### Manual Polling[​](#manual-polling "Direct link to Manual Polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefresh()` is your application's responsibility. ```cpp ConfigCatOptions options; options.pollingMode = PollingMode::manualPoll(); auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); client->forceRefresh(); ``` > `getValue()` returns `defaultValue` if the cache is empty. Call `forceRefresh()` to update the cache. ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `onClientReady()`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after instantiation. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeInSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. Alternatively, in Auto Polling mode, you can wait for the first `onConfigChanged` event to be notified when the internal cache is actually populated with config data. * `onConfigChanged(std::shared_ptr)`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `onFlagEvaluated(const EvaluationDetailsBase&)`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetails()`](#anatomy-of-getvaluedetails). * `onError(const std::string&, const std::exception_ptr&)`: This event is emitted when an error occurs within the client. You can subscribe to these events either on SDK initialization: ```cpp ConfigCatOptions options; options.pollingMode = PollingMode::manualPoll(); options.hooks = std::make_shared( []() { /* onClientReady callback */ }, [](std::shared_ptr config) { /* onConfigChanged callback */ }, [](const EvaluationDetailsBase& details) { /* onFlagEvaluated callback */ }, [](const std::string& error, const std::exception_ptr& exception) { /* onError callback */ } ); auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` or with the `getHooks()` method of the ConfigCat client: ```cpp client->getHooks->addOnFlagEvaluated([](const EvaluationDetailsBase& details) { /* onFlagEvaluated callback */ }); ``` ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases when you'd want to prevent the SDK from making HTTP calls, you can put it in offline mode: ```cpp client->setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To put the SDK back in online mode, you can do the following: ```cpp client->setOnline(); ``` > With `client->isOffline()` you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour::LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour::LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour::RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a file or a map. ### JSON File[​](#json-file "Direct link to JSON File") The SDK can be set up to load your feature flag & setting overrides from a file. #### File[​](#file "Direct link to File") ```cpp ConfigCatOptions options; options.flagOverrides = std::make_shared("path/to/the/local_flags.json", LocalOnly); auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` #### JSON File Structure[​](#json-file-structure "Direct link to JSON File Structure") The SDK supports 2 types of JSON structures to describe feature flags & settings. ##### 1. Simple (key-value) structure[​](#1-simple-key-value-structure "Direct link to 1. Simple (key-value) structure") ```json { "flags": { "enabledFeature": true, "disabledFeature": false, "intSetting": 5, "doubleSetting": 3.14, "stringSetting": "test" } } ``` ##### 2. Complex (full-featured) structure[​](#2-complex-full-featured-structure "Direct link to 2. Complex (full-featured) structure") This is the same format that the SDK downloads from the ConfigCat CDN. It allows the usage of all features that are available on the ConfigCat Dashboard. You can download your current config JSON from ConfigCat's CDN and use it as a baseline. A convenient way to get the config JSON for a specific SDK Key is to install the [ConfigCat CLI](https://github.com/configcat/cli) tool and execute the following command: ```bash configcat config-json get -f v6 -p {YOUR-SDK-KEY} > config.json ``` (Depending on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings, you may need to add the `--eu` switch.) Alternatively, you can download the config JSON manually, based on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings: * GLOBAL: `https://cdn-global.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` * EU: `https://cdn-eu.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` ```json { "p": { // hash salt, required only when confidential text comparator(s) are used "s": "80xCU/SlDz1lCiWFaxIBjyJeJecWjq46T4eu6GtozkM=" }, "s": [ // array of segments { "n": "Beta Users", // segment name "r": [ // array of User Conditions (there is a logical AND relation between the elements) { "a": "Email", // comparison attribute "c": 0, // comparator (see below) "l": [ // comparison value (see below) "john@example.com", "jane@example.com" ] } ] } ], "f": { // key-value map of feature flags & settings "isFeatureEnabled": { // key of a particular flag / setting "t": 0, // setting type, possible values: // 0 -> on/off setting (feature flag) // 1 -> text setting // 2 -> whole number setting // 3 -> decimal number setting "r": [ // array of Targeting Rules (there is a logical OR relation between the elements) { "c": [ // array of conditions (there is a logical AND relation between the elements) { "u": { // User Condition "a": "Email", // comparison attribute "c": 2, // comparator, possible values and required comparison value types: // 0 -> IS ONE OF (cleartext) + string array comparison value ("l") // 1 -> IS NOT ONE OF (cleartext) + string array comparison value ("l") // 2 -> CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 3 -> NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 4 -> IS ONE OF (semver) + semver string array comparison value ("l") // 5 -> IS NOT ONE OF (semver) + semver string array comparison value ("l") // 6 -> < (semver) + semver string comparison value ("s") // 7 -> <= (semver + semver string comparison value ("s") // 8 -> > (semver) + semver string comparison value ("s") // 9 -> >= (semver + semver string comparison value ("s") // 10 -> = (number) + number comparison value ("d") // 11 -> <> (number + number comparison value ("d") // 12 -> < (number) + number comparison value ("d") // 13 -> <= (number + number comparison value ("d") // 14 -> > (number) + number comparison value ("d") // 15 -> >= (number) + number comparison value ("d") // 16 -> IS ONE OF (hashed) + string array comparison value ("l") // 17 -> IS NOT ONE OF (hashed) + string array comparison value ("l") // 18 -> BEFORE (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 19 -> AFTER (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 20 -> EQUALS (hashed) + string comparison value ("s") // 21 -> NOT EQUALS (hashed) + string comparison value ("s") // 22 -> STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 23 -> NOT STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 24 -> ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 25 -> NOT ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 26 -> ARRAY CONTAINS ANY OF (hashed) + string array comparison value ("l") // 27 -> ARRAY NOT CONTAINS ANY OF (hashed) + string array comparison value ("l") // 28 -> EQUALS (cleartext) + string comparison value ("s") // 29 -> NOT EQUALS (cleartext) + string comparison value ("s") // 30 -> STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 31 -> NOT STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 32 -> ENDS WITH ANY OF (cleartext) + string array comparison value ("l") // 33 -> NOT ENDS WITH ANY OF (cleartext + string array comparison value ("l") // 34 -> ARRAY CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 35 -> ARRAY NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") "l": [ // comparison value - depending on the comparator, another type of value may need // to be specified (see above): // "s": string // "d": number "@example.com" ] } }, { "p": { // Flag Condition (Prerequisite) "f": "mainIntFlag", // key of prerequisite flag "c": 0, // comparator, possible values: 0 -> EQUALS, 1 -> NOT EQUALS "v": { // comparison value (value's type must match the prerequisite flag's type) "i": 42 } } }, { "s": { // Segment Condition "s": 0, // segment index, a valid index into the top-level segment array ("s") "c": 1 // comparator, possible values: 0 -> IS IN SEGMENT, 1 -> IS NOT IN SEGMENT } } ], "s": { // alternatively, an array of Percentage Options ("p", see below) can also be specified "v": { // the value served when the rule is selected during evaluation "b": true }, "i": "bcfb84a7" } } ], "p": [ // array of Percentage Options { "p": 10, // % value "v": { // the value served when the Percentage Option is selected during evaluation "b": true }, "i": "bcfb84a7" }, { "p": 90, "v": { "b": false }, "i": "bddac6ae" } ], "v": { // fallback value, served when none of the Targeting Rules match, // no Percentage Options are defined or evaluation of these is not possible "b": false // depending on the setting type, another type of value may need to be specified: // text setting -> "s": string // whole number setting -> "i": number // decimal number setting -> "d": number }, "i": "430bded3" // variation id (for analytical purposes) } } } ``` For a more comprehensive specification of the config JSON v6 format, you may refer to [this JSON schema document](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ### Map[​](#map "Direct link to Map") You can set up the SDK to load your feature flag & setting overrides from a map. ```cpp const std::unordered_map& map = { { "enabledFeature", true }, { "disabledFeature", false }, { "intSetting", 5 }, { "doubleSetting", 3.14 }, { "stringSetting", "test" } }; ConfigCatOptions options; options.flagOverrides = std::make_shared(map, LocalOnly); auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` ## `getAllKeys()`[​](#getallkeys "Direct link to getallkeys") You can get the keys for all available feature flags and settings by calling the `getAllKeys()` method. ```cpp auto client = ConfigCatClient::get("#YOUR-SDK-KEY#"); auto keys = client->getAllKeys(); ``` ## `getAllValues()`[​](#getallvalues "Direct link to getallvalues") Evaluates and returns the values of all feature flags and settings. Passing a User Object is optional. ```cpp auto client = ConfigCatClient::get("#YOUR-SDK-KEY#"); auto settingValues = client->getAllValues(); // invoke with User Object auto user = ConfigCatUser::create("#UNIQUE-USER-IDENTIFIER#"); auto settingValuesTargeting = client->getAllValues(user); ``` ## `getAllValueDetails`[​](#getallvaluedetails "Direct link to getallvaluedetails") Evaluates and returns the detailed values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```cpp auto client = ConfigCatClient::get("#YOUR-SDK-KEY#"); // invoke with User Object auto user = ConfigCatUser::create("#UNIQUE-USER-IDENTIFIER#"); auto allValueDetails = client->getAllValueDetails(user) ``` ## Custom Cache[​](#custom-cache "Direct link to Custom Cache") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`ConfigCache`](https://github.com/configcat/cpp-sdk/blob/main/include/configcat/configcache.h#L8) interface and set the `configCache` parameter in the options passed to `ConfigCatClient::get`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. You have the option to inject your custom cache implementation into the client. All you have to do is to inherit from the `ConfigCatCache` abstract class: ```cpp class MyCustomCache : public ConfigCatCache { public: const std::string& read(const std::string& key) override { // here you have to return with the cached value } void write(const std::string& key, const std::string& value) override { // here you have to store the new value in the cache } }; ``` Then use your custom cache implementation: ```cpp ConfigCatOptions options; options.configCache = std::make_shared(); auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` info The C++ SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Force refresh[​](#force-refresh "Direct link to Force refresh") Call the `forceRefresh()` method on the client to download the latest config JSON and update the cache. ## Using ConfigCat behind a proxy[​](#using-configcat-behind-a-proxy "Direct link to Using ConfigCat behind a proxy") Provide your own network credentials (username/password), and proxy server settings (proxy server/port) in the `ConfigCatOptions`. ```cpp ConfigCatOptions options; options.proxies = {{"https", "proxyhost:port"}}; // Protocol, Proxy options.proxyAuthentications = { {"https", ProxyAuthentication{"user", "password"}} // Protocol, ProxyAuthentication }; auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` ## Changing the default HTTP timeout[​](#changing-the-default-http-timeout "Direct link to Changing the default HTTP timeout") Set the maximum wait time for a ConfigCat HTTP response by changing the *connectTimeoutMs* or *readTimeoutMs* in the `ConfigCatOptions`. The default *connectTimeoutMs* is 8 seconds. The default *readTimeoutMs* is 5 seconds. ```cpp ConfigCatOptions options; options.connectTimeoutMs = 10000; // Timeout in milliseconds for establishing a HTTP connection with the server options.readTimeoutMs = 8000; // Timeout in milliseconds for reading the server's HTTP response auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```cpp #include #include auto logger = std::make_shared(LOG_LEVEL_WARNING); ConfigCatOptions options; options.logger = logger; auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` You can change the verbosity of the logs by setting the `LogLevel`. ```cpp logger->setLogLevel(LOG_LEVEL_INFO); ``` Available log levels: | Level | Description | | ------------------- | --------------------------------------------------------------------------------------- | | `LOG_LEVEL_ERROR` | Only error level events are logged. | | `LOG_LEVEL_WARNING` | Default. Errors and Warnings are logged. | | `LOG_LEVEL_INFO` | Errors, Warnings and feature flag evaluation is logged. | | `LOG_LEVEL_DEBUG` | All of the above plus debug info is logged. Debug logs can be different for other SDKs. | Info level logging helps to inspect how a feature flag was evaluated: ```bash [INFO]:[5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"","Email":"configcat@example.com","Country":"US","SubscriptionType":"Pro","Role":"Admin","version":"1.0.0"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") In the ConfigCat SDK, the default logger (`ConsoleLogger`) writes logs to the standard output, but you can override it with your implementation via the `logger` client option. The custom logger must implement the `ILogger` abstract class. ```cpp #include "log.h" class CustomLogger : public ILogger { public: void log(LogLevel level, const std::string& message, const std::exception_ptr& exception) override { // Write the logs std::cout << logLevelAsString(level) << ": " << message << std::endl; if (exception) { std::cout << "Exception details: " << unwrap_exception_message(exception) << std::endl; } } }; ``` ```cpp auto logger = std::make_shared(); logger->setLogLevel(LOG_LEVEL_INFO); ConfigCatOptions options; options.logger = logger; auto client = ConfigCatClient::get("#YOUR-SDK-KEY#", &options); ``` ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the ConfigCat SDK that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") Check out our Sample Application how they use the ConfigCat SDK * [ConfigCat C++ Console Sample App](https://github.com/configcat/cpp-sdk/tree/main/samples/) ## Guides[​](#guides "Direct link to Guides") See [this](https://configcat.com/blog/2022/10/21/configcat-cpp-sdk-announcement/) guide on how to use ConfigCat's C++ SDK. ## Look Under the Hood[​](#look-under-the-hood "Direct link to Look Under the Hood") * [ConfigCat C++ SDK's repository on GitHub](https://github.com/configcat/cpp-sdk) --- # Source: https://configcat.com/docs/api/reference/create-config.md # Create Config Copy page This endpoint creates a new Config in a specified Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/create-environment.md # Create Environment Copy page This endpoint creates a new Environment in a specified Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/create-group.md # Create Group Copy page This endpoint creates a new group with the given attributes. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 409 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/create-integration.md # Create Integration Copy page This endpoint creates a new Integration in a specified Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. The Parameters dictionary differs for each IntegrationType: * Datadog * `apikey`: Required. Datadog API key. * `site`: Datadog site. Available values: `Us`, `Eu`, `Us1Fed`, `Us3`, `Us5`. Default: `Us`. * Slack
Connecting the Slack integration through the Public Management API will not post messages with the ConfigCat Feature Flags Slack app but with an incoming webhook. * `incoming_webhook.url`: Required. The [incoming webhook URL](https://api.slack.com/messaging/webhooks) where the integration should post messages. * `includeSensitiveData`: Set to "true" to include [sensitive (hashed) comparison values](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators). By default, the integration will mask these values in the posted messages. We recommend hiding sensitive comparison values for shared or public Slack channels. * Amplitude * `apiKey`: Required. Amplitude API Key. * `secretKey`: Required. Amplitude Secret Key. * Mixpanel * `serviceAccountUserName`: Required. Mixpanel Service Account Username. * `serviceAccountSecret`: Required. Mixpanel Service Account Secret. * `projectId`: Required. Mixpanel Project ID. * `server`: Mixpanel Server. Available values: `StandardServer`, `EUResidencyServer`. Default: `StandardServer`. * Twilio Segment * `writeKey`: Required. Twilio Segment Write Key. * `server`: Twilio Segment Server. Available values: `Us`, `Eu`. Default: `Us`. * PubNub (work in progress) ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/create-permission-group.md # Create Permission Group Copy page This endpoint creates a new Permission Group in a specified Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/create-product.md # Create Product Copy page This endpoint creates a new Product in a specified Organization identified by the `organizationId` parameter, which can be obtained from the [List Organizations](https://configcat.com/docs/api/reference/get-organizations.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/create-proxy-profile.md # Create Proxy Profile Copy page This endpoint creates a new Proxy Profile in the given Organization identified by the `organizationId` parameter, which can be obtained from the [List Organizations](https://configcat.com/docs/api/reference/get-organizations.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/create-segment.md # Create Segment Copy page This endpoint creates a new Segment in a specified Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/create-setting.md # Create Flag Copy page This endpoint creates a new Feature Flag or Setting in a specified Config identified by the `configId` parameter. **Important:** The `key` attribute must be unique within the given Config. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/create-tag.md # Create Tag Copy page This endpoint creates a new Tag in a specified Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/create-user.md # Create User Copy page This endpoint creates a new user with the given attributes. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 401 * 409 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/create-webhook.md # Create Webhook Copy page This endpoint creates a new Webhook in a specified Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 201 * 400 * 404 * 429 When the creation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/sdk-reference/dart.md # Dart (Flutter) SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/dart-sdk.svg?style=social)](https://github.com/configcat/dart-sdk/stargazers) [![pub package](https://img.shields.io/pub/v/configcat_client.svg)](https://pub.dev/packages/configcat_client) [![Dart CI](https://github.com/configcat/dart-sdk/actions/workflows/dart-ci.yml/badge.svg?branch=main)](https://github.com/configcat/dart-sdk/actions/workflows/dart-ci.yml) [ConfigCat Dart (Flutter) SDK on GitHub](https://github.com/configcat/dart-sdk) ## Getting Started[​](#getting-started "Direct link to Getting Started") ### 1. Add the ConfigCat SDK to your project[​](#1-add-the-configcat-sdk-to-your-project "Direct link to 1. Add the ConfigCat SDK to your project") * Dart * Flutter ```bash dart pub add configcat_client ``` ```bash flutter pub add configcat_client ``` Or put the following directly to your `pubspec.yml` and run `dart pub get` or `flutter pub get`. pubspec.yml ```yaml dependencies: configcat_client: ^4.0.0 ``` ### 2. Import the ConfigCat SDK[​](#2-import-the-configcat-sdk "Direct link to 2. Import the ConfigCat SDK") ```dart import 'package:configcat_client/configcat_client.dart'; ``` ### 3. Create the *ConfigCat* client with your *SDK Key*[​](#3-create-the-configcat-client-with-your-sdk-key "Direct link to 3-create-the-configcat-client-with-your-sdk-key") ```dart final client = ConfigCatClient.get(sdkKey: '#YOUR-SDK-KEY#'); ``` ### 4. (Optional) Set up Flutter caching[​](#4-optional-set-up-flutter-caching "Direct link to 4. (Optional) Set up Flutter caching") If you're using the SDK in a Flutter application, it's recommended to use the [Flutter Preferences Cache](https://github.com/configcat/flutter-preferences-cache) implementation for caching. It stores the downloaded `config JSON` using the [shared\_preferences](https://pub.dev/packages/shared_preferences) package. ```dart import 'package:configcat_preferences_cache/configcat_preferences_cache.dart'; ``` ```dart final client = ConfigCatClient.get( sdkKey: '#YOUR-SDK-KEY#', options: ConfigCatOptions(cache: ConfigCatPreferencesCache())); ``` ### 5. Get your setting value[​](#5-get-your-setting-value "Direct link to 5. Get your setting value") ```dart final isMyAwesomeFeatureEnabled = await client.getValue(key: 'isMyAwesomeFeatureEnabled', defaultValue: false); if (isMyAwesomeFeatureEnabled) { doTheNewThing(); } else { doTheOldThing(); } ``` ### 6. Close *ConfigCat* client​[​](#6-close-configcat-client "Direct link to 6-close-configcat-client") You can safely shut down all clients at once or individually and release all associated resources on application exit. ```dart ConfigCatClient.closeAll(); // closes all clients client.close(); // closes the specific client ``` ## Setting up the *ConfigCat Client*[​](#setting-up-the-configcat-client "Direct link to setting-up-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `ConfigCatClient.get(sdkKey: )` returns a client with default options. ### Customizing the *ConfigCat Client*[​](#customizing-the-configcat-client "Direct link to customizing-the-configcat-client") To customize the SDK's behavior, you can pass an additional `ConfigCatOptions` parameter to the `get()` static factory method where the `ConfigCatOptions` class is used to set up the *ConfigCat Client*. ```dart final client = ConfigCatClient.get( sdkKey: '#YOUR-SDK-KEY#', options: ConfigCatOptions( pollingMode: PollingMode.manualPoll(), logger: ConfigCatLogger(level: LogLevel.info) ) ); ``` These are the available options on the `ConfigCatOptions` class: | Properties | Description | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataGovernance` | Optional, defaults to `global`. Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `global`, `euOnly`. | | `baseUrl` | Optional, sets the CDN base url (forward proxy, dedicated subscription) from where the sdk will download the config JSON. | | `connectTimeout` | Optional, sets the underlying [Dio](https://github.com/flutterchina/dio) HTTP client's connect timeout. [More about the HTTP Client](#httpclient). | | `receiveTimeout` | Optional, sets the underlying [Dio](https://github.com/flutterchina/dio) HTTP client's receive timeout. [More about the HTTP Client](#httpclient). | | `sendTimeout` | Optional, sets the underlying [Dio](https://github.com/flutterchina/dio) HTTP client's send timeout. [More about the HTTP Client](#httpclient). | | `cache` | Optional, sets a custom cache implementation for the client. [More about cache](#custom-cache). | | `pollingMode` | Optional, sets the polling mode for the client. [More about polling modes](#polling-modes). | | `logger` | Optional, sets the internal logger and log level. [More about logging](#logging). | | `override` | Optional, sets local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | `defaultUser` | Optional, sets the default user. [More about default user](#default-user). | | `offline` | Optional, defaults to `false`. Indicates whether the SDK should be initialized in offline mode. [More about offline mode](#online--offline-mode). | | `hooks` | Optional, used to subscribe events that the SDK sends in specific scenarios. [More about hooks](#hooks). | caution We strongly recommend you to use the `ConfigCatClient` as a Singleton object in your application. The `ConfigCatClient.get(sdkKey: )` static factory method constructs singleton client instances for your SDK keys. These clients can be closed all at once with the `ConfigCatClient.closeAll()` method or individually with `client.close()`. ## Anatomy of `getValue()`[​](#anatomy-of-getvalue "Direct link to anatomy-of-getvalue") | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```dart final value = await client.getValue( key: 'keyOfMySetting', defaultValue: false, user: ConfigCatUser(identifier: '#USER-IDENTIFIER#'), // Optional User Object ); ``` caution It is important to provide an argument for the `defaultValue` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | Type parameter `T` | | -------------- | ------------------ | | On/Off Toggle | `bool`/`bool?` | | Text | `String`/`String?` | | Whole Number | `int`/`int?` | | Decimal Number | `double`/`double?` | In addition to the types mentioned above, you also have the option to provide `object`, `object?` or `dynamic` for the type parameter regardless of the setting kind. It's important to note that providing any other type for the type parameter will result in an `ArgumentError`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. When relying on type inference and not explicitly specifying the type parameter, be mindful of potential type mismatch issues, especially with number types. For example, `client.getValue(key: "keyOfMyDecimalSetting", defaultValue: 0)` will return `defaultValue` (`0`) instead of the actual value of the decimal setting because the compiler infers the type as `int` instead of `double`, that is, the call is equivalent to `client.getValue("keyOfMyDecimalSetting", 0)`, which is a type mismatch. To correctly evaluate a decimal setting, you should use: ```dart var value = client.getValue("keyOfMyDecimalSetting", 0.0); // -or- var value = client.getValue("keyOfMyDecimalSetting", 0); ``` ## Anatomy of `getValueDetails()`[​](#anatomy-of-getvaluedetails "Direct link to anatomy-of-getvaluedetails") `getValueDetails()` is similar to `getValue()` but instead of returning the evaluated value only, it gives more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```dart final details = await client.getValueDetails( key: 'keyOfMySetting', defaultValue: false, user: ConfigCatUser(identifier: '#USER-IDENTIFIER#'), // Optional User Object ); ``` caution It is important to provide an argument for the `defaultValue` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------- | | `value` | `bool` / `String` / `int` / `double` | The evaluated value of the feature flag or setting. | | `key` | `String` | The key of the evaluated feature flag or setting. | | `isDefaultValue` | `bool` | True when the default value passed to `getValueDetails()` is returned due to an error. | | `error` | `String?` | In case of an error, this property contains the error message. | | `user` | `ConfigCatUser?` | The User Object that was used for evaluation. | | `matchedPercentageOption` | `PercentageOption?` | The Percentage Option (if any) that was used to select the evaluated value. | | `matchedTargetingRule` | `TargetingRule?` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `fetchTime` | `DateTime` | The last download time of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. ```dart final user = ConfigCatUser(identifier: '#UNIQUE-USER-IDENTIFIER#'); ``` ```dart final user = ConfigCatUser(identifier: 'john@example.com'); ``` ### Customized User Object creation[​](#customized-user-object-creation "Direct link to Customized User Object creation") | Argument | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. e.g. User role, Subscription type. | ```dart final user = ConfigCatUser( identifier: '#UNIQUE-USER-IDENTIFIER#', email: 'john@example.com', country: 'United Kingdom', custom: { 'SubscriptionType': 'Pro', 'UserRole': 'Admin' } ); ``` The `custom` map also allows attribute values other than `String` values: ```dart final user = ConfigCatUser( identifier: '#UNIQUE-USER-IDENTIFIER#', email: 'john@example.com', country: 'United Kingdom', custom: { 'Rating': 4.5, 'RegisteredAt': DateTime.parse('2023-11-22 12:34:56 +00:00'), 'Roles': {"Role1", "Role2"} } ); ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `String` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `String` values, * all other values are automatically converted to `String` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `String` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `double` values and all other numeric values which can safely be converted to `double`, * accept `String` values containing a properly formatted, valid `double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `DateTime` values, which are automatically converted to a second-based Unix timestamp, * accept `double` values representing a second-based Unix timestamp and all other numeric values which can safely be converted to `Double`, * accept `String` values containing a properly formatted, valid `double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept lists or sets of `String`, * accept `String` values containing a valid JSON string which can be deserialized to an array of `String`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") There's an option to set a default User Object that will be used at feature flag and setting evaluation. It can be useful when your application has a single user only, or rarely switches users. You can set the default User Object either on SDK initialization: ```dart final client = ConfigCatClient.get( sdkKey: '#YOUR-SDK-KEY#', options: ConfigCatOptions( defaultUser: ConfigCatUser(identifier: 'john@example.com') ) ); ``` or with the `setDefaultUser()` method of the ConfigCat client. ```dart client.setDefaultUser(ConfigCatUser(identifier: 'john@example.com')); ``` Whenever the `getValue()`, `getValueDetails()`, `getAllValues()`, or `getAllVariationIds()` methods are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```dart final user = ConfigCatUser(identifier: 'john@example.com'); client.setDefaultUser(user); // The default user will be used at the evaluation process. final value = await client.getValue(key: 'keyOfMySetting', defaultValue: false); ``` When the `user` parameter is specified on the requesting method, it takes precedence over the default user. ```dart final user = ConfigCatUser(identifier: 'john@example.com'); client.setDefaultUser(user); final otherUser = ConfigCatUser(identifier: 'brian@example.com'); // otherUser will be used at the evaluation process. final value = await client.getValue(key: 'keyOfMySetting', defaultValue: false, user: otherUser); ``` For deleting the default user, you can do the following: ```dart client.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValue()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle.
[More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the the `autoPollInterval` option parameter of the `PollingMode.autoPoll()` to change the polling interval. ```dart final client = ConfigCatClient.get( sdkKey: '', options: ConfigCatOptions( pollingMode: PollingMode.autoPoll( autoPollInterval: Duration(seconds: 100), ), ) ); ``` Available options: | Option Parameter | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `autoPollInterval` | Polling interval. | 60 | | `maxInitWaitTime` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5 | ### Lazy Loading[​](#lazy-loading "Direct link to Lazy Loading") When calling `getValue()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValue()` will return the setting value after the cache is updated. Use the `cacheRefreshInterval` option parameter of the `PollingMode.lazyLoad()` to set cache lifetime. ```dart final client = ConfigCatClient.get( sdkKey: '', options: ConfigCatOptions( pollingMode: PollingMode.lazyLoad( // the cache will expire in 100 seconds cacheRefreshInterval: Duration(seconds: 100), ), ) ); ``` Available options: | Parameter | Description | Default | | ---------------------- | ----------- | ------- | | `cacheRefreshInterval` | Cache TTL. | 60 | ### Manual Polling[​](#manual-polling "Direct link to Manual Polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefresh()` is your application's responsibility. ```dart final client = ConfigCatClient.get( sdkKey: '', options: ConfigCatOptions( pollingMode: PollingMode.manualPoll(), ) ); client.forceRefresh(); ``` > `getValue()` returns `defaultValue` if the cache is empty. Call `forceRefresh()` to update the cache. ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `onClientReady()`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after instantiation. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTime` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. Alternatively, in Auto Polling mode, you can wait for the first `onConfigChanged` event to be notified when the internal cache is actually populated with config data. * `onConfigChanged(Map)`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `onFlagEvaluated(EvaluationDetails)`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetails()`](#anatomy-of-getvaluedetails). * `onError(String)`: This event is emitted when an error occurs within the client. You can subscribe to these events either on SDK initialization: ```dart final client = ConfigCatClient.get( sdkKey: '#YOUR-SDK-KEY#', options: ConfigCatOptions( pollingMode: PollingMode.manualPoll(), hooks: Hooks( onFlagEvaluated: (details) => /* handle the event */ ) ) ); ``` or with the `hooks` property of the ConfigCat client: ```dart client.hooks.addOnFlagEvaluated((details) => /* handle the event */); ``` ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases when you'd want to prevent the SDK from making HTTP calls, you can put it in offline mode: ```dart client.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To put the SDK back in online mode, you can do the following: ```dart client.setOnline(); ``` > With `client.isOffline()` you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.localOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.localOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.remoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `Map`. ```dart final client = ConfigCatClient.get( sdkKey: 'localhost', options: ConfigCatOptions( override: FlagOverrides( dataSource: OverrideDataSource.map({ 'enabledFeature': true, 'disabledFeature': false, 'intSetting': 5, 'doubleSetting': 3.14, 'stringSetting': 'test', }), behaviour: OverrideBehaviour.localOnly ) ) ); ``` ## `getAllKeys()`[​](#getallkeys "Direct link to getallkeys") You can get the keys for all available feature flags and settings by calling the `getAllKeys()` method. ```dart final client = ConfigCatClient.get(sdkKey: '#YOUR-SDK-KEY#'); final keys = await client.getAllKeys(); ``` ## `getAllValues()`[​](#getallvalues "Direct link to getallvalues") Evaluates and returns the values of all feature flags and settings. Passing a User Object is optional. ```dart final client = ConfigCatClient.get(sdkKey: '#YOUR-SDK-KEY#'); final settingValues = await client.getAllValues(); // invoke with User Object final user = ConfigCatUser(identifier: '#UNIQUE-USER-IDENTIFIER#'); final settingValuesTargeting = await client.getAllValues(user); ``` ## Cache[​](#cache "Direct link to Cache") The SDK caches the downloaded `config JSON` only in memory by default. In case you have a Flutter application, you can use the [Flutter Preferences Cache](https://github.com/configcat/flutter-preferences-cache) for caching.
It's based on the [shared\_preferences](https://pub.dev/packages/shared_preferences) package that uses the following storage locations by platform: * **Web**: Browser `LocalStorage`. * **iOS / macOS**: `NSUserDefaults`. * **Android**: `SharedPreferences`. * **Linux**: File in `XDG_DATA_HOME` directory. * **Windows**: File in roaming `AppData` directory. ```dart final client = ConfigCatClient.get( sdkKey: '#YOUR-SDK-KEY#', options: ConfigCatOptions(cache: ConfigCatPreferencesCache())); ``` ### Custom Cache[​](#custom-cache "Direct link to Custom Cache") You have the option to inject your custom cache implementation into the client. All you have to do is to inherit from the `ConfigCatCache` abstract class: ```dart class MyCustomCache extends ConfigCatCache { @override Future read(String key) { // here you have to return with the cached value } @override Future write(String key, String value) { // here you have to store the new value in the cache } } ``` Then use your custom cache implementation: ```dart final client = ConfigCatClient.get( sdkKey: '', options: ConfigCatOptions(cache: MyCustomCache())); ``` info The Dart (Flutter) SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## HttpClient[​](#httpclient "Direct link to HttpClient") The ConfigCat SDK internally uses a [Dio HTTP client](https://github.com/flutterchina/dio) instance to download the latest config JSON over HTTP. You have the option to customize the internal HTTP client. ### HTTP Timeout[​](#http-timeout "Direct link to HTTP Timeout") You can set the maximum wait time for a ConfigCat HTTP response by using Dio's timeouts. ```dart final client = ConfigCatClient.get( sdkKey: '', options: ConfigCatOptions( connectTimeout: Duration(seconds: 10), // timeout for establishing a HTTP connection with the server sendTimeout: Duration(seconds: 10), // timeout for sending a HTTP request to the server receiveTimeout: Duration(seconds: 10), // timeout for reading the server's HTTP response ) ); ``` Default timeout values: * `connectTimeout`: 10 seconds * `sendTimeout`: 20 seconds * `receiveTimeout`: 20 seconds ### HTTP Proxy[​](#http-proxy "Direct link to HTTP Proxy") If your application runs behind a proxy you can do the following: ```dart import 'package:dio/adapter.dart'; (client.httpClient.httpClientAdapter as DefaultHttpClientAdapter) .onHttpClientCreate = (client) { client.findProxy = (uri) { return 'PROXY proxyHost:proxyPort'; }; }; ``` ## Force refresh[​](#force-refresh "Direct link to Force refresh") Call the `forceRefresh()` method on the client to download the latest config JSON and update the cache. ## Logging[​](#logging "Direct link to Logging") The default logger used by the SDK simply outputs the log messages with `print()`, but you can override it with your implementation via the `logger` client option. The custom implementation must satisfy the [Logger](https://github.com/configcat/dart-sdk/blob/main/lib/src/log/logger.dart) abstract class. ```dart class MyCustomLogger implements Logger { @override void close() { // close the logger } @override void debug(message, [error, StackTrace? stackTrace]) { // write the debug logs } @override void error(message, [error, StackTrace? stackTrace]) { // write the error logs } @override void info(message, [error, StackTrace? stackTrace]) { // write the info logs } @override void warning(message, [error, StackTrace? stackTrace]) { // write the warning logs } } ``` Then you can use your custom logger implementation at the SDK's initialization: ```dart final client = ConfigCatClient.get( sdkKey: '', options: ConfigCatOptions( logger: ConfigCatLogger(internalLogger: MyCustomLogger()), ) ); ``` You can change the verbosity of the logs by passing a `LogLevel` parameter to the `logger` option. ```dart final client = ConfigCatClient.get( sdkKey: '', options: ConfigCatOptions( logger: ConfigCatLogger(level: LogLevel.info), ) ); ``` Available log levels: | Level | Description | | --------- | --------------------------------------------------------------------------------------- | | `nothing` | Turn the logging off. | | `error` | Only error level events are logged. | | `warning` | Default. Errors and Warnings are logged. | | `info` | Errors, Warnings and feature flag evaluation is logged. | | `debug` | All of the above plus debug info is logged. Debug logs can be different for other SDKs. | Info level logging helps to inspect how a feature flag was evaluated: ```bash [INFO] 2022-01-20T18:22:02.313703 ConfigCat - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"","Email":"configcat@example.com","Country":"US","SubscriptionType":"Pro","Role":"Admin","version":"1.0.0"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'False' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'True' => MATCH, applying rule Returning 'True'. ``` ## Sample Apps[​](#sample-apps "Direct link to Sample Apps") Check out our Sample Applications how they use the ConfigCat SDK * [Console Application](https://github.com/configcat/dart-sdk/tree/main/example/lib) * [Flutter Application](https://github.com/configcat/dart-sdk/tree/main/example/flutter) ## Guides[​](#guides "Direct link to Guides") See [this](https://configcat.com/blog/2022/10/18/feature-flags-in-dart/) guide on how to use ConfigCat's Dart SDK. ## Look Under the Hood[​](#look-under-the-hood "Direct link to Look Under the Hood") * [ConfigCat Dart (Flutter) SDK's repository on GitHub](https://github.com/configcat/dart-sdk) * [ConfigCat Dart (Flutter) SDK's pub.dev page](https://pub.dev/packages/configcat_client) --- # Source: https://configcat.com/docs/advanced/data-governance.md # Data Governance - CDN Copy page ConfigCat's Data Governance feature gives you control over how and where your config JSONs are published and served from. This helps you comply with regional data handling requirements such as GDPR. ## CDN - Data Centers[​](#cdn---data-centers "Direct link to CDN - Data Centers") To ensure high availability and low response times worldwide, ConfigCat provides multiple global data centers, each with multiple CDN nodes for built-in redundancy and failover. ### ConfigCat Data Center locations[​](#configcat-data-center-locations "Direct link to ConfigCat Data Center locations") ConfigCat uses Cloudflare Edge Cache Network to deliver the configuration JSONs to the SDKs. Read more about Cloudflare data centers [here](https://www.cloudflare.com/network/). ## How to govern the data?[​](#how-to-govern-the-data "Direct link to How to govern the data?") Currently available geographical areas: ### Global \[Default][​](#global-default "Direct link to Global \[Default]") Provides geo-location based load balancing on all nodes around the globe to ensure the lowest response times. ### EU Only[​](#eu-only "Direct link to EU Only") Compliant with GDPR. This way your data will never leave the EU. ## Set preferences on the Dashboard[​](#set-preferences-on-the-dashboard "Direct link to Set preferences on the Dashboard") Open [Data Governance page](https://app.configcat.com/organization/data-governance) and follow the steps to set preferences. > Only team members with Organization Admin role can access Data Governance preferences. ## Set up the ConfigCat SDK in your application code[​](#set-up-the-configcat-sdk-in-your-application-code "Direct link to Set up the ConfigCat SDK in your application code") Make sure the `dataGovernance` option is specified when initializing the ConfigCat SDK in your application code. > The `dataGovernance` option's value must be in sync with the selected option on the Dashboard. ## Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") #### What if I forget to specify the `dataGovernance` option?[​](#what-if-i-forget-to-specify-the-datagovernance-option "Direct link to what-if-i-forget-to-specify-the-datagovernance-option") By default, the ConfigCat SDK contacts the ConfigCat Global CDN. However, if you switch to the EU CDN on the Dashboard, your config JSONs will only be published to the EU CDN nodes. Therefore, if you forget to specify the `dataGovernance` option when initializing the ConfigCat SDK, feature flag data download requests will need to be redirected to the EU CDN. To avoid this, it's recommended to specify the correct `dataGovernance` option, otherwise response times can be significantly longer. #### `Warning: The dataGovernance parameter specified at the client initialization is not in sync with the preferences on the ConfigCat Dashboard....`[​](#warning-the-datagovernance-parameter-specified-at-the-client-initialization-is-not-in-sync-with-the-preferences-on-the-configcat-dashboard "Direct link to warning-the-datagovernance-parameter-specified-at-the-client-initialization-is-not-in-sync-with-the-preferences-on-the-configcat-dashboard") **Don't worry,** your feature flags will still be served. See above example. --- # Source: https://configcat.com/docs/integrations/datadog.md # Datadog - Monitor your feature flags events Copy page ## Overview[​](#overview "Direct link to Overview") Monitor feature flag events in real-time. Feature flag changes will appear as events in Datadog, tagged with relevant product, config, and environment details. ![Feature flag events logged to Datadog](/docs/assets/datadog-event_192dpi.png) ## Installation[​](#installation "Direct link to Installation") 1. Have a [Datadog subscription.](https://www.datadoghq.com/) 2. Get a [Datadog API Key.](https://docs.datadoghq.com/account_management/api-app-keys/#api-keys) ![Datadog API Key](/docs/assets/datadog-apikey_192dpi.png) 3. Open the [integrations tab](https://app.configcat.com/product/integrations) on ConfigCat Dashboard. 4. Click on Datadog's **Connect** button and set your Datadog API key. 5. OPTIONAL - Set the proper site of your Datadog account. [More about Datadog site](https://docs.datadoghq.com/getting_started/site/). 6. You're all set. Go ahead and make some changes on your feature flags, then check your Events in Datadog. ## Un-installation[​](#un-installation "Direct link to Un-installation") 1. Open the [integrations tab](https://app.configcat.com/product/integrations) on ConfigCat Dashboard. 2. Click on Datadog's **Connected** button. 3. Select the connection from the **Connected** dropdown. 4. Click the **Disconnect** button in the edit dialog. 5. Click **Yes** in the confirmation dialog. ## Event details[​](#event-details "Direct link to Event details") Every event sent to Datadog by ConfigCat has a *source* property of `configcat` and *tagged* with the `product_name`, `config_name` and `environment_name` where the change has happened. ### Searching for Events[​](#searching-for-events "Direct link to Searching for Events") For example here is how to search for events that happened in the production environment: `sources:configcat production` ![Filtering feature flag change events](/docs/assets/datadog-filtering_192dpi.png) ## Useful Resources[​](#useful-resources "Direct link to Useful Resources") * [How to send feature flag change notifications to DataDog - Blog Post](https://configcat.com/blog/2021/03/17/connect-configcat-and-datadog/) * [ConfigCat Integrations API](https://configcat.com/docs/api/reference/integrations/) --- # Source: https://configcat.com/docs/api/reference/delete-config.md # Delete Config Copy page This endpoint removes a Config identified by the `configId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-environment.md # Delete Environment Copy page This endpoint removes an Environment identified by the `environmentId` parameter. If the `cleanupAuditLogs` flag is set to true, it also deletes the audit log records related to the environment (except for the `Created a new environment` and `Deleted an environment` records). ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/delete-group.md # Delete Group Copy page This endpoint deletes an existing group. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 401 * 404 * 429 No content. Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-integration.md # Delete Integration Copy page This endpoint removes a Integration identified by the `integrationId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-invitation.md # Delete Invitation Copy page This endpoint removes an Invitation identified by the `invitationId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-organization-member.md # Delete Member from Organization Copy page This endpoint removes a Member identified by the `userId` from the given Organization identified by the `organizationId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-permission-group.md # Delete Permission Group Copy page This endpoint removes a Permission Group identified by the `permissionGroupId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-product-member.md # Delete Member from Product Copy page This endpoint removes a Member identified by the `userId` from the given Product identified by the `productId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-product.md # Delete Product Copy page This endpoint removes a Product identified by the `productId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-proxy-profile.md # Delete Proxy Profile Copy page This endpoint removes a Proxy Profile identified by the `proxyProfileId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-reference-reports.md # Delete Reference reports Copy page ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 OK Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-segment.md # Delete Segment Copy page This endpoint removes a Segment identified by the `segmentId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-setting.md # Delete Flag Copy page This endpoint removes a Feature Flag or Setting from a specified Config, identified by the `configId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-tag.md # Delete Tag Copy page This endpoint deletes a Tag identified by the `tagId` parameter. To remove a Tag from a Feature Flag or Setting use the [Update Flag](https://configcat.com/docs/api/reference/update-setting.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/delete-user.md # Delete User Copy page This endpoint deletes an existing user. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 401 * 404 * 429 No content. Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/delete-webhook.md # Delete Webhook Copy page This endpoint removes a Webhook identified by the `webhookId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 204 * 400 * 404 * 429 When the delete was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/sdk-reference/js/deno.md # Deno SDK Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/js-unified-sdk.svg?style=social)](https://github.com/configcat/js-unified-sdk/stargazers) [![JS SDK CI](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml/badge.svg?branch=master)](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml) [![SonarCloud Coverage](https://img.shields.io/sonar/coverage/configcat_js-unified-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_js-unified-sdk) [![Known Vulnerabilities](https://snyk.io/test/github/configcat/js-unified-sdk/badge.svg?targetFile=package.json)](https://snyk.io/test/github/configcat/js-unified-sdk?targetFile=package.json) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=configcat_js-sdk\&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=configcat_js-sdk) [![JSDELIVR](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge)](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge) [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install and import package[​](#1-install-and-import-package "Direct link to 1. Install and import package") First install the [NPM package](https://npmjs.com/package/@configcat/sdk): ```bash npm i @configcat/sdk ``` Then import it into your application: ```js import * as configcat from "@configcat/sdk/deno"; ``` info To make this work in older versions of Deno, you may need to enable the [unstable-byonm](https://deno.com/blog/node-to-deno-challenge#what-are-all-these-unstable-node-compatibility-settings) feature or adjust your [import map](https://docs.deno.com/runtime/fundamentals/modules/#differentiating-between-imports-or-importmap-in-deno.json-and---import-map-option). ### 2. Create the *ConfigCat* client with your SDK Key[​](#2-create-the-configcat-client-with-your-sdk-key "Direct link to 2-create-the-configcat-client-with-your-sdk-key") ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); ``` ### 3. Get your setting value[​](#3-get-your-setting-value "Direct link to 3. Get your setting value") The async/await way: ```js const value = await configCatClient.getValueAsync( 'isMyAwesomeFeatureEnabled', false, ); if (value) { do_the_new_thing(); } else { do_the_old_thing(); } ``` The Promise way: ```js configCatClient .getValueAsync('isMyAwesomeFeatureEnabled', false) .then((value) => { if (value) { do_the_new_thing(); } else { do_the_old_thing(); } }); ``` The *ConfigCat SDK* also offers a synchronous API for feature flag evaluation. Read more [here](#snapshots-and-synchronous-feature-flag-evaluation). ### 4. Dispose the *ConfigCat* client[​](#4-dispose-the-configcat-client "Direct link to 4-dispose-the-configcat-client") You can safely dispose all clients at once or individually and release all associated resources on application exit. ```js configcat.disposeAllClients(); // disposes all clients // -or- configCatClient.dispose(); // disposes a specific client ``` ## Creating the *ConfigCat* Client[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `configcat.getClient('')` returns a client with default options. The `getClient` function has optional parameters, which can be used to adjust the behavior of the client. | Parameters | Description | Default | | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | | `sdkKey` | **REQUIRED.** SDK Key to access your feature flags and settings. Get it from *ConfigCat Dashboard*. | - | | `pollingMode` | Optional. The polling mode to use to fetch the config data from the ConfigCat CDN. [More about polling modes](#polling-modes). | `PollingMode.AutoPoll` | | `options` | Optional. The options object. See the table below. | - | The available options depends on the chosen polling mode. However, there are some common options which can be set in the case of every polling mode: | Option Parameter | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `configFetcher` | Custom [`IConfigCatConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigFetcher.ts) instance for downloading a config. | [`DenoHttpConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/deno/DenoHttpConfigFetcher.ts) | | `cache` | Custom [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) implementation for caching the downloaded config. | [`InMemoryConfigCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) | | `logger` | Custom [`IConfigCatLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) implementation for tracing. | [`ConfigCatConsoleLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) (with WARN level) | | `logFilter` | Sets a custom log filter. [More about log filtering](#log-filtering). | `undefined` (none) | | `baseUrl` | Sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | | `requestTimeoutMs` | The amount of milliseconds the SDK waits for a response from the ConfigCat servers before returning values from the cache. | 30000 | | `flagOverrides` | Local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | | `dataGovernance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `DataGovernance.Global`, `DataGovernance.EuOnly`. | `DataGovernance.Global` | | `defaultUser` | Sets the default user. [More about default user](#default-user). | `undefined` (none) | | `offline` | Determines whether the client should be initialized to offline mode. [More about offline mode](#online--offline-mode). | `false` | Options also include a property named `setupHook`, which you can use to subscribe to the hooks (events) at the time of initialization. [More about hooks](#hooks). For example: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('clientReady', function() { const keys = this.configCatClient.snapshot().getAllKeys(); console.log(`Client is ready! Number of available feature flags: ${keys.length}`); }), }, ); ``` info You can acquire singleton client instances for your SDK keys using the `configcat.getClient(sdkKey: "")` factory function. (However, please keep in mind that subsequent calls to `getClient()` with the *same SDK Key* return a *shared* client instance, which was set up by the first call.) You can close all open clients at once using the `configcat.disposeAllClients()` function or do it individually using the `configCatClient.dispose()` method. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") Returns a Promise with the value. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((value) => { console.log(value); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | `typeof defaultValue` | | -------------- | --------------------- | | On/Off Toggle | `boolean` | | Text | `string` | | Whole Number | `number` | | Decimal Number | `number` | In addition to the types mentioned above, you also have the option to provide `null` or `undefined` for the `defaultValue` parameter regardless of the setting kind. However, if you do so, the return type of the `getValue` method will be * `boolean | string | number | null` when `defaultValue` is `null` or * `boolean | string | number | undefined` when `defaultValue` is `undefined`. This is because in these cases the exact return type cannot be determined at compile-time as the TypeScript compiler has no information about the setting type. It's important to note that providing any other type for the `defaultValue` parameter will result in a `TypeError`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueDetailsAsync()`[​](#anatomy-of-getvaluedetailsasync "Direct link to anatomy-of-getvaluedetailsasync") `getValueDetailsAsync()` is similar to `getValueAsync()` but instead of returning the evaluated value only, it provides more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const details = await configCatClient.getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((details) => { console.log(details); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `key` | `string` | The key of the evaluated feature flag or setting. | | `value` | `boolean` / `string` / `number` | The evaluated value of the feature flag or setting. | | `user` | `User` | The User Object used for the evaluation. | | `isDefaultValue` | `boolean` | True when the default value passed to `getValueDetailsAsync()` is returned due to an error. | | `errorCode` | `EvaluationErrorCode` | In case of an error, this property contains a code that identifies the reason for the error. | | `errorMessage` | `string` | In case of an error, this property contains the error message. | | `errorException` | `any` | In case of an error, this property contains the related exception object (if any). | | `matchedTargetingRule` | `TargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matchedPercentageOption` | `PercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `fetchTime` | `Date` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. For simple targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; ``` ```js const userObject = { identifier: 'john@example.com' }; ``` | Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any `string` value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | For advanced targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#', email: 'john@example.com', country: 'United Kingdom', custom: { SubscriptionType: 'Pro', UserRole: 'Admin', }, }; ``` The `custom` dictionary also allows attribute values other than `string` values: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; userObject.custom = { Rating: 4.5, RegisteredAt: new Date('2023-11-22T12:34:56.000Z'), Roles: ['Role1', 'Role2'], }; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `string` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `number` values, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `number` values representing a second-based Unix timestamp, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `string`, * accept `string` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") It's possible to set a default User Object that will be used on feature flag and setting evaluation. It can be useful when your application has a single user only or rarely switches users. You can set the default User Object either on SDK initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { defaultUser: { identifier: 'john@example.com' }, }, ); ``` ...or using the `setDefaultUser()` method of the `configCatClient` object: ```js configCatClient.setDefaultUser({ identifier: 'john@example.com' }); ``` Whenever the evaluation methods like `getValueAsync()`, `getValueDetailsAsync()`, etc. are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); // The default user will be used in the evaluation process. const value = await configCatClient.getValueAsync('keyOfMyFeatureFlag', false); ``` When a `user` parameter is passed to the evaluation methods, it takes precedence over the default user. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); const otherUser = { identifier: 'brian@example.com' }; // otherUser will be used in the evaluation process. const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', false, otherUser, ); ``` You can also remove the default user by doing the following: ```js configCatClient.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValueAsync()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. [More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `pollIntervalSeconds` option parameter to change the polling interval. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { pollIntervalSeconds: 95, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `pollIntervalSeconds` | Polling interval in seconds. | 60s | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5s | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValueAsync()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValueAsync()` will return the setting value after the cache is updated. Use `cacheTimeToLiveSeconds` option parameter to set cache lifetime. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.LazyLoad, { cacheTimeToLiveSeconds: 600, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------- | ------- | | `cacheTimeToLiveSeconds` | Cache TTL in seconds. | 60s | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefreshAsync()` is your application's responsibility. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); await configCatClient.forceRefreshAsync(); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` > `getValueAsync()` returns `defaultValue` if the cache is empty. Call `forceRefreshAsync()` to update the cache. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); // console: "my default value" await configCatClient.forceRefreshAsync(); value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `clientReady: [cacheState: ClientCacheState]`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `cacheState` argument. * `configFetched: [result: RefreshResult, isInitiatedByUser: boolean]`: This event is emitted each time the client attempts to refresh the cached config by fetching the latest version from the ConfigCat CDN. It is emitted not only when `ForceRefreshAsync` is called but also when the refresh is initiated by the client automatically. Thus, this event allows you to observe potential network issues that occur under the hood. * `configChanged: [newConfig: IConfig]`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `flagEvaluated: [evaluationDetails: IEvaluationDetails]`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetailsAsync()`](#anatomy-of-getvaluedetailsasync). * `clientError: [message: string, exception?: any]`: This event is emitted when an error occurs within the client. You can subscribe to these events either on initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', function() { /* handle the event */ }), }, ); ``` ...or directly on the `ConfigCatClient` instance: ```js configCatClient.on('flagEvaluated', function() { /* handle the event */ }); ``` caution Some events (e.g. `clientReady`, `configChanged` and `clientError`) may be emitted before `getClient` returns. This means you may miss them unless you subscribe on initialization. However, even if you do, there's another gotcha: it's not safe to use the outer `configCatClient` variable in your event handler because it may not yet be assigned when the handler is called. Instead, you can safely access the client instance via `this.configCatClient` - provided that the event handler is a normal function, not an arrow function. ## Snapshots and synchronous feature flag evaluation[​](#snapshots-and-synchronous-feature-flag-evaluation "Direct link to Snapshots and synchronous feature flag evaluation") On JavaScript platforms, the *ConfigCat* client provides only asynchronous methods for evaluating feature flags and settings because these operations may involve network communication (e.g. downloading config data from the ConfigCat CDN servers), which is necessarily an asynchronous operation in JavaScript. However, there can be circumstances where synchronous evaluation is preferable, thus, since v8.1.0, the JavaScript SDK provides a way to synchronously evaluate feature flags and settings via *snapshots*. Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, ); // Wait for the client to initialize. await configCatClient.waitForReady(); const snapshot = configCatClient.snapshot(); const user = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; for (const key of snapshot.getAllKeys()) { const value = snapshot.getValue(key, null, user); console.log(`${key}: ${value}`); } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefreshAsync`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTimeSeconds` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```js const clientCacheState = await configCatClient.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { // Handle initialization failure (see below). console.warn('ConfigCat client failed to obtain the config data during initialization.'); } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `configChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases where you want to prevent the SDK from making HTTP calls, you can switch it to offline mode: ```js configCatClient.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To switch the SDK back to online mode, do the following: ```js configCatClient.setOnline(); ``` Using the `configCatClient.isOffline` property you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `{ [key: string]: boolean | string | number }` object or from a custom flag override data source. ### Map[​](#map "Direct link to Map") You can specify simple feature flag & setting overrides using a `{ [key: string]: boolean | string | number }` map. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: configcat.createFlagOverridesFromMap( { enabledFeature: true, disabledFeature: false, intSetting: 5, doubleSetting: 3.14, stringSetting: 'test', }, configcat.OverrideBehaviour.LocalOnly, ), }, ); ``` ### Custom data source implementation[​](#custom-data-source-implementation "Direct link to Custom data source implementation") You can create a custom flag override data source by implementing `IOverrideDataSource`. The SDK provides the `createSettingFromValue` function to create `Setting` objects from simple `boolean`, `string` and `number` values. In case you need complex (full-featured) flag overrides, you can use the `deserializeConfig` function to obtain `Setting` objects from a config JSON conforming to the [config JSON v6 format](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ```ts class MyCustomOverrideDataSource implements IOverrideDataSource { private settings: Record; constructor(configJson: string) { this.settings = deserializeConfig(configJson).f ?? {}; } getOverrides(): Record { return this.settings; } } ``` or ```js function MyCustomOverrideDataSource(configJson) { this.settings = deserializeConfig(configJson).f ?? {}; } MyCustomOverrideDataSource.prototype.getOverrides = function () { return this.settings; }; ``` then ```js // Set the `MyCustomOverrideDataSource` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: { dataSource: new MyCustomOverrideDataSource('{ "f": { ... } }'), behaviour: configcat.OverrideBehaviour.LocalOnly, } }, ); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: configcat.createConsoleLogger(configcat.LogLevel.Info), // Setting log level to Info }, ); ``` Available log levels: | Level | Description | | ----- | ------------------------------------------------------- | | Off | Nothing gets logged. | | Error | Only error level events are logged. | | Warn | Default. Errors and Warnings are logged. | | Info | Errors, Warnings and feature flag evaluation is logged. | | Debug | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash ConfigCat - INFO - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"#SOME-USER-ID#","Email":"configcat@example.com"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") The SDK provides a simple logger implementation that logs to [the debugging console](https://developer.mozilla.org/en-US/docs/Web/API/console) (`configcat.createConsoleLogger(...)`) but it also allows you to inject any custom implementation of `IConfigCatLogger`. ```ts class MyCustomLogger implements IConfigCatLogger { /** * Writes an event into the log. * @param level Event severity level. * @param eventId Event identifier. * @param message Message. * @param exception The exception object related to the message (if any). */ log( level: LogLevel, eventId: LogEventId, message: LogMessage, exception?: any, ): void { // insert your custom log logic } } ``` or ```js function MyCustomLogger() {} MyCustomLogger.prototype.log = function (level, eventId, message, exception) { // insert your custom log logic }; ``` then ```js // Set the `MyCustomLogger` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: new MyCustomLogger(), }, ); ``` ### Log Filtering[​](#log-filtering "Direct link to Log Filtering") You can define a custom log filter by providing a callback function via the `logFilter` option. The callback will be called by the *ConfigCat SDK* each time a log event occurs (and the event passes the minimum log level specified by the `IConfigCatLogger.level` property). That is, the callback allows you to filter log events by `level`, `eventId`, `message` or `exception`. The formatted message string can be obtained via `message.toString()`. If the callback function returns `true`, the event will be logged, otherwise it will be skipped. ```js // Filter out events with id 1001 from the log. const logFilter = (level, eventId, message, exception) => eventId != 1001; const configCatClient = configcat.getClient( "#YOUR-SDK-KEY#", configcat.PollingMode.AutoPoll, { logFilter: logFilter } ); ``` caution Please make sure that your log filter logic doesn't perform heavy computation. A complex or incorrectly implemented log filter can degrade the performance of the SDK. ## `getAllKeysAsync()`[​](#getallkeysasync "Direct link to getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeysAsync()` method. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); const keys = await configCatClient.getAllKeysAsync(); console.log(keys); ``` ## `getAllValuesAsync()`[​](#getallvaluesasync "Direct link to getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValuesAsync(); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValuesAsync(userObject); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); ``` ## `getAllValueDetailsAsync()`[​](#getallvaluedetailsasync "Direct link to getallvaluedetailsasync") Evaluates and returns the values along with evaluation details of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValueDetailsAsync(); settingValues.forEach((details) => console.log(details)); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValueDetailsAsync(userObject); settingValues.forEach((details) => console.log(details)); ``` ## Using custom cache implementation[​](#using-custom-cache-implementation "Direct link to Using custom cache implementation") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) interface and set the `cache` property in the options passed to `getClient`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```ts class MyCustomCache implements IConfigCatCache { set(key: string, value: string): Promise | void { // insert your cache write logic here } get( key: string, ): Promise | string | null | undefined { // insert your cache read logic here } } ``` or ```js function MyCustomCache() {} MyCustomCache.prototype.set = function (key, value) { // insert your cache write logic here }; MyCustomCache.prototype.get = function (key) { // insert your cache read logic here }; ``` then ```js // Set the `MyCustomCache` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { cache: new MyCustomCache(), }, ); ``` info The JavaScript SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the *ConfigCat SDK* that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Platform compatibility[​](#platform-compatibility "Direct link to Platform compatibility") The SDK should be compatible with latest versions of Deno. The SDK is [tested](https://github.com/configcat/js-unified-sdk/blob/master/.github/workflows/js-sdk-ci.yml) against the following runtimes: * Deno (v1.31, v1.46, latest stable) on Windows / Ubuntu / macOS The SDK is compatible with TypeScript v4.0.2 or newer. Earlier versions may work but those are not tested, thus, not supported officially. These tests are running on each pull request, before each deploy, and on a daily basis. You can view a sample run [here](https://github.com/configcat/js-unified-sdk/actions/runs/11745259578). ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [Sample Deno console application](https://github.com/configcat/js-unified-sdk/tree/master/samples/deno-console) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) * [ConfigCat SDK for JavaScript in NPM](https://www.npmjs.com/package/@configcat/sdk) --- # Source: https://configcat.com/docs/api/reference/deselect-proxy-profile-sdk-keys.md # Deselect SDK keys Copy page This endpoint removes the given list of Config / Environment pairs' SDK Keys from a Proxy Profile identified by the `proxyProfileId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 403 * 404 * 429 When the deselection was successful. Bad request. Forbidden. When selection rules are applied to the Proxy Profile. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/glossary/devops-engineer.md # DevOps Engineer - The Backbone of Efficient Software Deployment Copy page ## Introduction[​](#introduction "Direct link to Introduction") The role of a DevOps Engineer has become indispensable. Bridging the gap between software creation and its operational performance, a DevOps Engineer is a key player in the orchestration of code life cycles, ensuring that everything from development to deployment and beyond runs seamlessly. Let’s delve into what makes the DevOps Engineer role so vital. ## Who is a DevOps Engineer?[​](#who-is-a-devops-engineer "Direct link to Who is a DevOps Engineer?") A DevOps Engineer is a multi-faceted professional who specializes in the development (Dev) and operations (Ops) aspects of software engineering. Their responsibilities extend across the entire development pipeline, focusing on streamlining processes, enhancing performance, and ensuring the reliability of both software and infrastructure. ## Key Responsibilities of a DevOps Engineer[​](#key-responsibilities-of-a-devops-engineer "Direct link to Key Responsibilities of a DevOps Engineer") * **Development and Maintenance**: Spearheading the development of infrastructure and ensuring its robust maintenance. * **Deployment**: Orchestrating the deployment process to ensure smooth and timely delivery of software. * **Monitoring**: Vigilantly monitoring both software and infrastructure to preemptively identify and address issues. * **Continuous Improvement**: Implementing strategies for continuous development, integration, and deployment. * **Collaboration**: Acting as a bridge between various teams to foster a cohesive working environment. ## The Importance of DevOps Engineers[​](#the-importance-of-devops-engineers "Direct link to The Importance of DevOps Engineers") * **Efficiency**: By automating processes and improving communication between development and operations teams, DevOps Engineers significantly enhance efficiency. * **Agility**: They enable organizations to respond swiftly to market changes and customer demands. * **Reliability**: Through continuous monitoring and maintenance, they ensure that systems are robust and downtime is minimized. * **Innovation**: By streamlining workflows, they provide more room for innovation and experimentation. ## Challenges Faced by DevOps Engineers and Solutions[​](#challenges-faced-by-devops-engineers-and-solutions "Direct link to Challenges Faced by DevOps Engineers and Solutions") * **Complex Workflows**: Handling intricate workflows can be challenging. Solution: Implementation of automation tools and clear communication channels. * **Rapid Technology Changes**: Keeping pace with ever-evolving technologies. Solution: Continuous learning and adaptation. * **Balancing Speed and Security**: Ensuring rapid deployment without compromising on security. Solution: Integrating security measures into the development process. ## Conclusion[​](#conclusion "Direct link to Conclusion") The DevOps Engineer is more than just a role; it’s a mindset that embodies efficiency, collaboration, and continuous improvement. In the current technological era, a proficient DevOps Engineer is not just an asset but a necessity for organizations aiming for resilience, agility, and sustained growth. --- # Source: https://configcat.com/docs/advanced/team-management/domain-verification.md # Domain Verification Copy page In order to use the [SAML Single Sign-On](https://configcat.com/docs/advanced/team-management/saml/saml-overview.md) and the [Auto-assign Users](https://configcat.com/docs/advanced/team-management/auto-assign-users.md) features, you have to verify the ownership of the domain that your company uses for email addresses. ## Steps to verify your domain[​](#steps-to-verify-your-domain "Direct link to Steps to verify your domain") * Open your organization's authentication settings on the [ConfigCat Dashboard](https://app.configcat.com/organization/authentication). ![ConfigCat authentication settings](/docs/assets/saml/dashboard/authentication.png) * Click `ADD & VERIFY DOMAIN`. ![ConfigCat add & verify domain](/docs/assets/saml/dashboard/add_domain_new.png) * Type your domain name, then click `ADD` ![ConfigCat add domain](/docs/assets/saml/dashboard/domain_name_new.png) * Follow the instructions on the appearing dialog to verify your domain. ![ConfigCat verify domain](/docs/assets/saml/dashboard/verify_domain_new.png) --- # Source: https://configcat.com/docs/sdk-reference/openfeature/dotnet.md # Source: https://configcat.com/docs/sdk-reference/dotnet.md # .NET SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/.net-sdk.svg?style=social)](https://github.com/configcat/.net-sdk/stargazers) [![Build status](https://github.com/configcat/.net-sdk/actions/workflows/dotnet-sdk-ci.yml/badge.svg?branch=master)](https://github.com/configcat/.net-sdk/actions/workflows/dotnet-sdk-ci.yml) [![NuGet Version](https://img.shields.io/nuget/v/ConfigCat.Client)](https://www.nuget.org/packages/ConfigCat.Client/) [![Sonar Coverage](https://img.shields.io/sonar/coverage/net-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=net-sdk) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=net-sdk\&metric=alert_status)](https://sonarcloud.io/dashboard?id=net-sdk) [ConfigCat .NET SDK on GitHub](https://github.com/configcat/.net-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install *ConfigCat SDK* [NuGet package](https://www.nuget.org/packages/ConfigCat.Client)[​](#1-install-configcat-sdk-nuget-package "Direct link to 1-install-configcat-sdk-nuget-package") * Powershell / NuGet Package Manager Console * .NET CLI ```powershell Install-Package ConfigCat.Client ``` ```text dotnet add package ConfigCat.Client ``` info To get the *ConfigCat SDK* up and running in Unity, please refer to [this guide](https://configcat.com/docs/sdk-reference/unity.md). ### 2. Import package[​](#2-import-package "Direct link to 2. Import package") ```csharp using ConfigCat.Client; ``` ### 3. Create the *ConfigCat* client with your *SDK Key*[​](#3-create-the-configcat-client-with-your-sdk-key "Direct link to 3-create-the-configcat-client-with-your-sdk-key") ```csharp var client = ConfigCatClient.Get("#YOUR-SDK-KEY#"); ``` ### 4. Get your setting value[​](#4-get-your-setting-value "Direct link to 4. Get your setting value") ```csharp var isMyAwesomeFeatureEnabled = await client.GetValueAsync("isMyAwesomeFeatureEnabled", false); if (isMyAwesomeFeatureEnabled) { doTheNewThing(); } else { doTheOldThing(); } ``` The *ConfigCat SDK* also offers a synchronous API for feature flag evaluation. Read more [here](#snapshots-and-non-blocking-synchronous-feature-flag-evaluation). ### 5. Dispose the *ConfigCat* client[​](#5-dispose-the-configcat-client "Direct link to 5-dispose-the-configcat-client") You can safely dispose all clients at once or individually and release all associated resources on application exit. ```csharp ConfigCatClient.DisposeAll(); // disposes all clients // -or- client.Dispose(); // disposes a specific client ``` ## Creating the *ConfigCat Client*[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `ConfigCatClient.Get(sdkKey: "")` returns a client with default options. ### Customizing the *ConfigCat Client*[​](#customizing-the-configcat-client "Direct link to customizing-the-configcat-client") To customize the SDK's behavior, you can pass an additional `Action` parameter to the `Get()` static factory method where the `ConfigCatClientOptions` class is used to set up the *ConfigCat Client*. ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.PollingMode = PollingModes.ManualPoll; options.Logger = new ConsoleLogger(LogLevel.Info); }); ``` These are the available options on the `ConfigCatClientOptions` class: | Properties | Description | Default | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | | `PollingMode` | Optional, sets the polling mode for the client. [More about polling modes](#polling-modes). | `PollingModes.AutoPoll()` | | `ConfigFetcher` | Optional, [`IConfigCatConfigFetcher`](https://github.com/configcat/.net-sdk/blob/master/src/ConfigCatClient/ConfigService/IConfigCatConfigFetcher.cs) instance for downloading a config. | [`HttpClientConfigFetcher`](https://github.com/configcat/.net-sdk/blob/master/src/ConfigCatClient/ConfigService/HttpClientConfigFetcher.cs) | | `ConfigCache` | Optional, [`IConfigCatCache`](https://github.com/configcat/.net-sdk/blob/master/src/ConfigCatClient/Cache/IConfigCatCache.cs) instance for caching the downloaded config. | [`InMemoryConfigCache`](https://github.com/configcat/.net-sdk/blob/master/src/ConfigCatClient/Cache/InMemoryConfigCache.cs) | | `Logger` | Optional, [`IConfigCatLogger`](https://github.com/configcat/.net-sdk/blob/master/src/ConfigCatClient/Logging/IConfigCatLogger.cs) instance for tracing. | [`ConsoleLogger`](https://github.com/configcat/.net-sdk/blob/master/src/ConfigCatClient/Logging/ConsoleLogger.cs) (with WARNING level) | | `LogFilter` | Optional, sets a custom log filter. [More about log filtering](#log-filtering). | `null` (none) | | `BaseUrl` | Optional, sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | | `HttpClientHandler` | Optional, `HttpClientHandler` to provide network credentials and proxy settings. [More about the proxy settings](#using-configcat-behind-a-proxy). | built-in `HttpClientHandler` | | `HttpTimeout` | Optional, sets the underlying HTTP client's timeout. [More about the HTTP timeout](#http-timeout). | `TimeSpan.FromSeconds(30)` | | `FlagOverrides` | Optional, sets the local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | | `DataGovernance` | Optional, describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `Global`, `EuOnly` | `Global` | | `DefaultUser` | Optional, sets the default user. [More about default user](#default-user). | `null` (none) | | `Offline` | Optional, determines whether the client should be initialized to offline mode. [More about offline mode](#online--offline-mode). | `false` | Via the events provided by `ConfigCatClientOptions` you can also subscribe to the hooks (events) at the time of initialization. [More about hooks](#hooks). For example: ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.ClientReady += (s, e) => { var keys = ((IConfigCatClient)s).Snapshot().GetAllKeys(); Console.WriteLine("Client is ready! Number of available feature flags: " + keys.Count); }; }); ``` info You can acquire singleton client instances for your SDK keys using the `ConfigCatClient.Get(sdkKey: "")` static factory method. (However, please keep in mind that subsequent calls to `ConfigCatClient.Get()` with the *same SDK Key* return a *shared* client instance, which was set up by the first call.) You can close all open clients at once using the `ConfigCatClient.DisposeAll()` method or do it individually using the `client.Dispose()` method. ## Anatomy of `GetValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```csharp User userObject = new User("#UNIQUE-USER-IDENTIFIER#"); // Optional User Object var value = await client.GetValueAsync("keyOfMyFeatureFlag", false, userObject); ``` caution It is important to provide an argument for the `defaultValue` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | Type parameter `T` | | -------------- | --------------------------------- | | On/Off Toggle | `bool` / `bool?` | | Text | `string` / `string?` | | Whole Number | `int` / `int?` / `long` / `long?` | | Decimal Number | `double` / `double?` | In addition to the types mentioned above, you also have the option to provide `object` or `object?` for the type parameter regardless of the setting kind. However, this approach is not recommended as it may involve [boxing](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing). It's important to note that providing any other type for the type parameter will result in an `ArgumentException`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. When relying on type inference and not explicitly specifying the type parameter, be mindful of potential type mismatch issues, especially with number types. For example, `client.GetValueAsync("keyOfMyDecimalSetting", 0)` will return `defaultValue` (`0`) instead of the actual value of the decimal setting because the compiler infers the type as `int` instead of `double`, that is, the call is equivalent to `client.GetValueAsync("keyOfMyDecimalSetting", 0)`, which is a type mismatch. To correctly evaluate a decimal setting, you should use: ```csharp var value = await client.GetValueAsync("keyOfMyDecimalSetting", 0.0); // -or- var value = await client.GetValueAsync("keyOfMyDecimalSetting", 0d); // -or- var value = await client.GetValueAsync("keyOfMyDecimalSetting", 0); ``` ## Anatomy of `GetValueDetailsAsync()`[​](#anatomy-of-getvaluedetailsasync "Direct link to anatomy-of-getvaluedetailsasync") `GetValueDetailsAsync()` is similar to `GetValueAsync()` but instead of returning the evaluated value only, it provides more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```csharp User userObject = new User("#UNIQUE-USER-IDENTIFIER#"); // Optional User Object var details = await client.GetValueDetailsAsync("keyOfMyFeatureFlag", false, userObject); ``` caution It is important to provide an argument for the `defaultValue` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------- | | `Key` | `string` | The key of the evaluated feature flag or setting. | | `Value` | `bool` / `string` / `int` / `double` | The evaluated value of the feature flag or setting. | | `User` | `User` | The User Object used for the evaluation. | | `IsDefaultValue` | `bool` | True when the default value passed to `GetValueDetailsAsync()` is returned due to an error. | | `ErrorCode` | `EvaluationErrorCode` | In case of an error, this property contains a code that identifies the reason for the error. | | `ErrorMessage` | `string` | In case of an error, this property contains the error message. | | `ErrorException` | `Exception` | In case of an error, this property contains the related exception object (if any). | | `MatchedTargetingRule` | `ITargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `MatchedPercentageOption` | `IPercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `FetchTime` | `DateTime` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. ```csharp User userObject = new User("#UNIQUE-USER-IDENTIFIER#"); ``` ```csharp User userObject = new User("john@example.com"); ``` | Parameters | Description | | ---------- | ------------------------------------------------------------------------------------------------------------------------------- | | `Id` | **REQUIRED.** Unique identifier of a user in your application. Can be any `string` value, even an email address. | | `Email` | Optional parameter for easier Targeting Rule definitions. | | `Country` | Optional parameter for easier Targeting Rule definitions. | | `Custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | ```csharp User userObject = new User("#UNIQUE-USER-IDENTIFIER#") { Email = "john@example.com", Country = "United Kingdom", Custom = { ["SubscriptionType"] = "Pro", ["UserRole"] = "Admin" } }; ``` The `Custom` dictionary also allows attribute values other than `string` values: ```csharp User userObject = new User("#UNIQUE-USER-IDENTIFIER#") { Custom = { ["Rating"] = 4.5, ["RegisteredAt"] = DateTimeOffset.Parse("2023-11-22 12:34:56 +00:00", CultureInfo.InvariantCulture), ["Roles"] = new[] { "Role1", "Role2" } } }; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `string` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `double` values and all other numeric values which can safely be converted to `double`, * accept `string` values containing a properly formatted, valid `double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `DateTime` or `DateTimeOffset` values, which are automatically converted to a second-based Unix timestamp, * accept `double` values representing a second-based Unix timestamp and all other numeric values which can safely be converted to `double`, * accept `string` values containing a properly formatted, valid `double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `string`, * accept `string` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") It's possible to set a default User Object that will be used on feature flag and setting evaluation. It can be useful when your application has a single user only or rarely switches users. You can set the default User Object either on SDK initialization: ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => options.DefaultUser = new User(identifier: "john@example.com")); ``` ...or using the `SetDefaultUser()` method of the `ConfigCatClient` object: ```csharp client.SetDefaultUser(new User(identifier: "john@example.com")); ``` Whenever the evaluation methods like `GetValueAsync()`, `GetValueDetailsAsync()`, etc. are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```csharp var user = new User(identifier: "john@example.com"); client.SetDefaultUser(user); // The default user will be used in the evaluation process. var value = await client.GetValueAsync(key: "keyOfMyFeatureFlag", defaultValue: false); ``` When a `user` parameter is passed to the evaluation methods, it takes precedence over the default user. ```csharp var user = new User(identifier: "john@example.com"); client.SetDefaultUser(user); var otherUser = new User(identifier: "brian@example.com"); // otherUser will be used in the evaluation process. var value = await client.GetValueAsync(key: "keyOfMyFeatureFlag", defaultValue: false, user: otherUser); ``` You can also remove the default user by doing the following: ```csharp client.ClearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `GetValueAsync()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. [More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `pollInterval` option parameter to change the polling interval. ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.PollingMode = PollingModes.AutoPoll(pollInterval: TimeSpan.FromSeconds(95)); }); ``` Available options: | Option Parameter | Description | Default | | ----------------- | ---------------------------------------------------------------------------------------- | ------- | | `pollInterval` | Polling interval. | 60s | | `maxInitWaitTime` | Maximum waiting time between the client initialization and the first config acquisition. | 5s | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `GetValueAsync()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `GetValueAsync()` will return the setting value after the cache is updated. Use `cacheTimeToLive` parameter to manage configuration lifetime. ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.PollingMode = PollingModes.LazyLoad(cacheTimeToLive: TimeSpan.FromSeconds(600)); }); ``` Available options: | Option Parameter | Description | Default | | ----------------- | ----------- | ------- | | `cacheTimeToLive` | Cache TTL. | 60s | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `ForceRefreshAsync()` is your application's responsibility. ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.PollingMode = PollingModes.ManualPoll; }); await client.ForceRefreshAsync(); ``` > `GetValueAsync()` returns `defaultValue` if the cache is empty. Call `ForceRefreshAsync()` to update the cache. ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.PollingMode = PollingModes.ManualPoll; }); Console.WriteLine(await client.GetValueAsync("keyOfMyTextSetting", "my default value")); // console: "my default value" await client.ForceRefreshAsync(); Console.WriteLine(await client.GetValueAsync("keyOfMyTextSetting", "my default value")); // console: "value from server" ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. Via the following events you can subscribe to particular events raised by the *ConfigCat* client: * `event EventHandler ClientReady`: This event is raised when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTime` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `CacheState` property of the event arguments. * `event EventHandler ConfigFetched`: This event is raised each time the client attempts to refresh the cached config by fetching the latest version from the ConfigCat CDN. It is raised not only when `ForceRefreshAsync` is called but also when the refresh is initiated by the client automatically. Thus, this event allows you to observe potential network issues that occur under the hood. * `event EventHandler ConfigChanged`: This event is raised first when the client's internal cache gets populated. Afterwards, it is raised again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `event EventHandler FlagEvaluated`: This event is raised each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`GetValueDetailsAsync()`](#anatomy-of-getvaluedetailsasync). * `event EventHandler Error`: This event is raised when an error occurs within the client. You can subscribe to these events either on initialization: ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.PollingMode = PollingModes.ManualPoll; options.FlagEvaluated += (s, e) => { /* handle the event */ }; }); ``` ...or directly on the `ConfigCatClient` instance: ```csharp client.FlagEvaluated += (s, e) => { /* handle the event */ }; ``` caution Some events (e.g. `ClientReady`, `ConfigChanged` and `Error`) may be raised before `ConfigCatClient.Get` returns. This means you may miss them unless you subscribe on initialization. However, even if you do, there's another gotcha: it's not safe to use the outer `client` variable in your event handler because it may not yet be assigned when the handler is called. Instead, you can safely access the client instance via the sender parameter like `var client = (IConfigCatClient)s;`. ## Snapshots and non-blocking synchronous feature flag evaluation[​](#snapshots-and-non-blocking-synchronous-feature-flag-evaluation "Direct link to Snapshots and non-blocking synchronous feature flag evaluation") Currently, the *ConfigCat* client provides both asynchronous and synchronous methods for evaluating feature flags and settings. However, depending on the setup, the synchronous methods may block the executing thread for longer periods of time (e.g. when downloading config data from the ConfigCat CDN servers), which can lead to an unresponsive application. To prevent such issues, the problematic methods have been deprecated and are going to be removed in a future major version. As an alternative, since v9.2.0, the .NET SDK provides a way to synchronously evaluate feature flags and settings as a non-blocking operation, via *snapshots*. Using the `Snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```csharp using var client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => options.PollingMode = PollingModes.AutoPoll()); // Wait for the client to initialize. await client.WaitForReadyAsync(); var snapshot = client.Snapshot(); var user = new User("#UNIQUE-USER-IDENTIFIER#"); foreach (var key in snapshot.GetAllKeys()) { var value = snapshot.GetValue(key, default(object), user); Console.WriteLine($"{key}: {value}"); } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `ForceRefreshAsync`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `WaitForReadyAsync` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTime` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `WaitForReadyAsync` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```csharp var clientCacheState = await client.WaitForReadyAsync(); if (clientCacheState == ClientCacheState.NoFlagData) { // Handle initialization failure (see below). Console.WriteLine("ConfigCat client failed to obtain the config data during initialization."); } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `ConfigChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases where you want to prevent the SDK from making HTTP calls, you can switch it to offline mode: ```csharp client.SetOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To switch the SDK back to online mode, do the following: ```csharp client.SetOnline(); ``` Using the `client.IsOffline` property you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can load your feature flag & setting overrides from a file or from a simple `Dictionary` structure. ### JSON File[​](#json-file "Direct link to JSON File") The SDK can load your feature flag & setting overrides from a file. You can also specify whether the file should be reloaded when it gets modified. #### File[​](#file "Direct link to File") ```csharp IConfigCatClient client = ConfigCatClient.Get("localhost", options => { options.FlagOverrides = FlagOverrides.LocalFile( "path/to/local_flags.json", // path to the file true, // reload the file when it gets modified OverrideBehaviour.LocalOnly ); }); ``` #### JSON File Structure[​](#json-file-structure "Direct link to JSON File Structure") The SDK supports 2 types of JSON structures to describe feature flags & settings. ##### 1. Simple (key-value) structure[​](#1-simple-key-value-structure "Direct link to 1. Simple (key-value) structure") ```json { "flags": { "enabledFeature": true, "disabledFeature": false, "intSetting": 5, "doubleSetting": 3.14, "stringSetting": "test" } } ``` ##### 2. Complex (full-featured) structure[​](#2-complex-full-featured-structure "Direct link to 2. Complex (full-featured) structure") This is the same format that the SDK downloads from the ConfigCat CDN. It allows the usage of all features that are available on the ConfigCat Dashboard. You can download your current config JSON from ConfigCat's CDN and use it as a baseline. A convenient way to get the config JSON for a specific SDK Key is to install the [ConfigCat CLI](https://github.com/configcat/cli) tool and execute the following command: ```bash configcat config-json get -f v6 -p {YOUR-SDK-KEY} > config.json ``` (Depending on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings, you may need to add the `--eu` switch.) Alternatively, you can download the config JSON manually, based on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings: * GLOBAL: `https://cdn-global.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` * EU: `https://cdn-eu.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` ```json { "p": { // hash salt, required only when confidential text comparator(s) are used "s": "80xCU/SlDz1lCiWFaxIBjyJeJecWjq46T4eu6GtozkM=" }, "s": [ // array of segments { "n": "Beta Users", // segment name "r": [ // array of User Conditions (there is a logical AND relation between the elements) { "a": "Email", // comparison attribute "c": 0, // comparator (see below) "l": [ // comparison value (see below) "john@example.com", "jane@example.com" ] } ] } ], "f": { // key-value map of feature flags & settings "isFeatureEnabled": { // key of a particular flag / setting "t": 0, // setting type, possible values: // 0 -> on/off setting (feature flag) // 1 -> text setting // 2 -> whole number setting // 3 -> decimal number setting "r": [ // array of Targeting Rules (there is a logical OR relation between the elements) { "c": [ // array of conditions (there is a logical AND relation between the elements) { "u": { // User Condition "a": "Email", // comparison attribute "c": 2, // comparator, possible values and required comparison value types: // 0 -> IS ONE OF (cleartext) + string array comparison value ("l") // 1 -> IS NOT ONE OF (cleartext) + string array comparison value ("l") // 2 -> CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 3 -> NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 4 -> IS ONE OF (semver) + semver string array comparison value ("l") // 5 -> IS NOT ONE OF (semver) + semver string array comparison value ("l") // 6 -> < (semver) + semver string comparison value ("s") // 7 -> <= (semver + semver string comparison value ("s") // 8 -> > (semver) + semver string comparison value ("s") // 9 -> >= (semver + semver string comparison value ("s") // 10 -> = (number) + number comparison value ("d") // 11 -> <> (number + number comparison value ("d") // 12 -> < (number) + number comparison value ("d") // 13 -> <= (number + number comparison value ("d") // 14 -> > (number) + number comparison value ("d") // 15 -> >= (number) + number comparison value ("d") // 16 -> IS ONE OF (hashed) + string array comparison value ("l") // 17 -> IS NOT ONE OF (hashed) + string array comparison value ("l") // 18 -> BEFORE (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 19 -> AFTER (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 20 -> EQUALS (hashed) + string comparison value ("s") // 21 -> NOT EQUALS (hashed) + string comparison value ("s") // 22 -> STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 23 -> NOT STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 24 -> ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 25 -> NOT ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 26 -> ARRAY CONTAINS ANY OF (hashed) + string array comparison value ("l") // 27 -> ARRAY NOT CONTAINS ANY OF (hashed) + string array comparison value ("l") // 28 -> EQUALS (cleartext) + string comparison value ("s") // 29 -> NOT EQUALS (cleartext) + string comparison value ("s") // 30 -> STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 31 -> NOT STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 32 -> ENDS WITH ANY OF (cleartext) + string array comparison value ("l") // 33 -> NOT ENDS WITH ANY OF (cleartext + string array comparison value ("l") // 34 -> ARRAY CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 35 -> ARRAY NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") "l": [ // comparison value - depending on the comparator, another type of value may need // to be specified (see above): // "s": string // "d": number "@example.com" ] } }, { "p": { // Flag Condition (Prerequisite) "f": "mainIntFlag", // key of prerequisite flag "c": 0, // comparator, possible values: 0 -> EQUALS, 1 -> NOT EQUALS "v": { // comparison value (value's type must match the prerequisite flag's type) "i": 42 } } }, { "s": { // Segment Condition "s": 0, // segment index, a valid index into the top-level segment array ("s") "c": 1 // comparator, possible values: 0 -> IS IN SEGMENT, 1 -> IS NOT IN SEGMENT } } ], "s": { // alternatively, an array of Percentage Options ("p", see below) can also be specified "v": { // the value served when the rule is selected during evaluation "b": true }, "i": "bcfb84a7" } } ], "p": [ // array of Percentage Options { "p": 10, // % value "v": { // the value served when the Percentage Option is selected during evaluation "b": true }, "i": "bcfb84a7" }, { "p": 90, "v": { "b": false }, "i": "bddac6ae" } ], "v": { // fallback value, served when none of the Targeting Rules match, // no Percentage Options are defined or evaluation of these is not possible "b": false // depending on the setting type, another type of value may need to be specified: // text setting -> "s": string // whole number setting -> "i": number // decimal number setting -> "d": number }, "i": "430bded3" // variation id (for analytical purposes) } } } ``` For a more comprehensive specification of the config JSON v6 format, you may refer to [this JSON schema document](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ### Dictionary[​](#dictionary "Direct link to Dictionary") You can set up the SDK to load your feature flag & setting overrides from a `Dictionary`. ```csharp var dictionary = new Dictionary { {"enabledFeature", true}, {"disabledFeature", false}, {"intSetting", 5}, {"doubleSetting", 3.14}, {"stringSetting", "test"}, }; IConfigCatClient client = ConfigCatClient.Get("localhost", options => { options.FlagOverrides = FlagOverrides.LocalDictionary(dictionary, OverrideBehaviour.LocalOnly); }); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log level[​](#setting-log-level "Direct link to Setting log level") ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#"); client.LogLevel = LogLevel.Info; ``` Available log levels: | Level | Description | | ------- | ------------------------------------------------------- | | Off | Nothing is logged. | | Error | Only error level events are logged. | | Warning | Default. Errors and Warnings are logged. | | Info | Errors, Warnings and feature flag evaluation is logged. | | Debug | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash ConfigCat.INFO [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"","Email":"configcat@example.com","Country":"US","SubscriptionType":"Pro","Role":"Admin","version":"1.0.0"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'False' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'True' => MATCH, applying rule Returning 'True'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") By default, the SDK logs to [the console's standard output](https://learn.microsoft.com/en-us/dotnet/api/system.console.out) but it also allows you to inject any custom logger implementation via the `ConfigCatClientOptions.Logger` property. Sample code on how to create a basic file logger implementation for ConfigCat client: [See Sample Code](https://github.com/configcat/.net-sdk/blob/master/samples/FileLoggerSample.cs) Another sample which shows how to implement an adapter to [the built-in logging framework](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging) of .NET Core/.NET 5+: [See Sample Code](https://github.com/configcat/.net-sdk/blob/master/samples/ASP.NETCore/WebApplication/Adapters/ConfigCatToMSLoggerAdapter.cs) ### Log Filtering[​](#log-filtering "Direct link to Log Filtering") You can define a custom log filter by providing a callback function via the `ConfigCatClientOptions.LogFilter` property. The callback will be called by the *ConfigCat SDK* each time a log event occurs (and the event passes the minimum log level specified by the `IConfigCatLogger.LogLevel` property). That is, the callback allows you to filter log events by `level`, `eventId`, `message` or `exception`. The formatted message string can be obtained via `message.InvariantFormattedMessage`. If the callback function returns `true`, the event will be logged, otherwise it will be skipped. ```cs // Filter out events with id 1001 from the log. LogFilterCallback logFilter = (LogLevel level, LogEventId eventId, ref FormattableLogMessage message, Exception? exception) => eventId != 1001; var client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => options.LogFilter = logFilter); ``` caution Please make sure that your log filter logic doesn't perform heavy computation and doesn't block the executing thread. A complex or incorrectly implemented log filter can degrade the performance of the SDK. ## `GetAllKeysAsync()`[​](#getallkeysasync "Direct link to getallkeysasync") You can get the keys for all available feature flags and settings by calling the `GetAllKeysAsync()` method of the `ConfigCatClient`. ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#"); IEnumerable keys = await client.GetAllKeysAsync(); ``` ## `GetAllValuesAsync()`[​](#getallvaluesasync "Direct link to getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#"); IDictionary settingValues = await client.GetAllValuesAsync(); // invoke with User Object User userObject = new User("#UNIQUE-USER-IDENTIFIER#"); IDictionary settingValuesTargeting = await client.GetAllValuesAsync(userObject); ``` ## `GetAllValueDetailsAsync()`[​](#getallvaluedetailsasync "Direct link to getallvaluedetailsasync") Evaluates and returns the values along with evaluation details of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#"); IReadOnlyList settingValues = await client.GetAllValueDetailsAsync(); // invoke with User Object User userObject = new User("435170f4-8a8b-4b67-a723-505ac7cdea92"); IReadOnlyList settingValuesTargeting = await client.GetAllValueDetailsAsync(userObject); ``` ## Using custom cache implementation[​](#using-custom-cache-implementation "Direct link to Using custom cache implementation") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`IConfigCatCache`](https://github.com/configcat/.net-sdk/blob/master/src/ConfigCatClient/Cache/IConfigCatCache.cs) interface and set the `ConfigCache` parameter in the setup callback of `ConfigCatClient.Get`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```csharp public class MyCustomCache : IConfigCatCache { public string? Get(string key) { /* insert your synchronous cache read logic here */ } public Task GetAsync(string key, CancellationToken cancellationToken = default) { /* insert your asynchronous cache read logic here */ } public void Set(string key, string value) { /* insert your synchronous cache write logic here */ } public Task SetAsync(string key, string value, CancellationToken cancellationToken = default) { /* insert your asynchronous cache write logic here */ } } ``` then ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.ConfigCache = new MyCustomCache() }); ``` info The .NET SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Using ConfigCat behind a proxy[​](#using-configcat-behind-a-proxy "Direct link to Using ConfigCat behind a proxy") Provide your own network credentials (username/password) and proxy server settings (proxy server/port) by setting the `HttpClientHandler` property in the setup callback of `ConfigCatClient.Get`. ```csharp var myProxySettings = new WebProxy(proxyHost, proxyPort) { UseDefaultCredentials = false, Credentials = new NetworkCredential(proxyUserName, proxyPassword) }; var myHttpClientHandler = new HttpClientHandler { Proxy = myProxySettings }; IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.HttpClientHandler = myHttpClientHandler; }); ``` ## HTTP Timeout[​](#http-timeout "Direct link to HTTP Timeout") You can set the maximum wait time for a ConfigCat HTTP response. ```csharp IConfigCatClient client = ConfigCatClient.Get("#YOUR-SDK-KEY#", options => { options.HttpTimeout = TimeSpan.FromSeconds(10); }); ``` The default timeout is 30 seconds. ## Platform compatibility[​](#platform-compatibility "Direct link to Platform compatibility") The *ConfigCat SDK* supports all the widespread .NET JIT runtimes, everything that implements [.NET Standard 2.0](https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0)+ and supports TLS 1.2 should work. Starting with v9.3.0, it can also be used in applications that employ [trimmed self-contained](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained) or various [ahead-of-time (AOT) compilation](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) deployment models. Based on our tests, the SDK is compatible with the following runtimes/deployment models: * .NET Framework 4.5+ (including Ngen) * .NET Core 3.1, .NET 5+ (including Crossgen2/ReadyToRun and Native AOT) * Mono 5.10+ * .NET for Android (formerly known as Xamarin.Android) * .NET for iOS (formerly known as Xamarin.iOS) * Unity 2021.3+ (Mono JIT) * Unity 2021.3+ (IL2CPP)\* * Universal Windows Platform 10.0.16299.0+ (.NET Native)\*\* * WebAssembly (Mono AOT/Emscripten, also known as wasm-tools) \*Unity WebGL also works but needs a bit of extra effort: you will need to enable WebGL compatibility by calling the `ConfigCatClient.PlatformCompatibilityOptions.EnableUnityWebGLCompatibility` method. For more details, see [Sample Scripts](https://github.com/configcat/.net-sdk/tree/master/samples/UnityWebGL).
\*\*To make the SDK work in Release builds on UWP, you will need to add `` to your application's [.rd.xml](https://learn.microsoft.com/en-us/windows/uwp/dotnet-native/runtime-directives-rd-xml-configuration-file-reference) file. See also [this discussion](https://github.com/dotnet/runtime/issues/29912#issuecomment-638471351). info We strive to provide an extensive support for the various .NET runtimes and versions. If you still encounter an issue with the SDK on some platform, please open a [GitHub issue](https://github.com/configcat/.net-sdk/issues/new/choose) or [contact support](https://configcat.com/support). ## Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") When the *ConfigCat SDK* does not work as expected in your application, please check for the following potential problems: * **Symptom:** Instead of the actual value, the default one is constantly returned by `GetValueAsync()` and the log contains the following message (provided that the client is set up to log error level events as described [here](#logging)): "Secure connection could not be established. Please make sure that your application is enabled to use TLS 1.2+." **Problem:** ConfigCat CDN servers require TLS 1.2 or newer security protocol for communication. As for allowed security protocols, please keep in mind that newer .NET runtimes rely on operating system settings, older versions, however, may need additional setup to make secure communication with the CDN servers work. | Runtime Version | Default Protocols | | -------------------------------------------- | ---------------------- | | .NET Framework 4.5 and earlier | SSL 3.0, TLS 1.0 | | .NET Framework 4.6 | TLS 1.0, 1.1, 1.2, 1.3 | | .NET Framework 4.7+, .NET Core 1.0+, .NET 5+ | System (OS) Defaults | As shown in the table above, if your application runs on .NET Framework 4.5, by default it will fail to establish a connection to the CDN servers. Read [this](https://stackoverflow.com/a/58195987/8656352) for more details. **Solution**: The best solution to the problem is to upgrade your application to target a newer runtime but in case that is not possible, you can use the following workaround: ```csharp ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; ``` (Place this code at the startup of your application, **before** any instances of `ConfigCatClient` is created.) ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") Check out our Sample Applications how they use the *ConfigCat SDK*: * [Sample Console App](https://github.com/configcat/.net-sdk/tree/master/samples/ConsoleApp) * [Sample Multi-page Web App (ASP.NET Core MVC)](https://github.com/configcat/.net-sdk/tree/master/samples/ASP.NETCore) * [Sample Single-page Web App (ASP.NET Core Blazor WebAssembly)](https://github.com/configcat/.net-sdk/tree/master/samples/BlazorWasm) * [Sample Mobile/Windows Store App (.NET MAUI)](https://github.com/configcat/.net-sdk/tree/master/samples/MAUI) ## Guides[​](#guides "Direct link to Guides") See the following guides on how to use ConfigCat's .NET SDK: * [.NET 6](https://configcat.com/blog/2022/11/25/feature-flags-in-net6/) * [ASP.NET Core](https://configcat.com/blog/2021/10/10/aspnetcore-options-pattern/) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat .NET SDK on GitHub](https://github.com/configcat/.net-sdk) * [ConfigCat .NET SDK on nuget.org](https://www.nuget.org/packages/ConfigCat.Client) --- # Source: https://configcat.com/docs/sdk-reference/elixir.md # Elixir SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/elixir-sdk.svg?style=social)](https://github.com/configcat/elixir-sdk/stargazers) [![Elixir CI](https://github.com/configcat/elixir-sdk/actions/workflows/elixir-ci.yml/badge.svg?branch=main)](https://github.com/configcat/elixir-sdk/actions/workflows/elixir-ci.yml) [![Coverage Status](https://codecov.io/github/configcat/elixir-sdk/badge.svg?branch=main)](https://codecov.io/github/configcat/elixir-sdk?branch=main) [![Hex.pm](https://img.shields.io/hexpm/v/configcat.svg?style=circle)](https://hex.pm/packages/configcat) [![HexDocs.pm](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/configcat/) [![Hex.pm](https://img.shields.io/hexpm/dt/configcat.svg?style=circle)](https://hex.pm/packages/configcat) [![Hex.pm](https://img.shields.io/hexpm/l/configcat.svg)](https://hex.pm/packages/configcat) [![Last Updated](https://img.shields.io/github/last-commit/configcat/elixir-sdk.svg)](https://github.com/configcat/elixir-sdk/commits/main) [ConfigCat Elixir SDK on GitHub](https://github.com/configcat/elixir-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Add `configcat` to your list of dependencies in `mix.exs`[​](#1-add-configcat-to-your-list-of-dependencies-in-mixexs "Direct link to 1-add-configcat-to-your-list-of-dependencies-in-mixexs") ```elixir def deps do [ {:configcat, "~> 4.0.0"} ] end ``` ### 2. Add `ConfigCat` to your application Supervisor tree[​](#2-add-configcat-to-your-application-supervisor-tree "Direct link to 2-add-configcat-to-your-application-supervisor-tree") ```elixir def start(_type, _args) do children = [ {ConfigCat, [sdk_key: "#YOUR-SDK-KEY#"]}, MyApp ] opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) end ``` ### 3. Get your setting value[​](#3-get-your-setting-value "Direct link to 3. Get your setting value") ```elixir isMyAwesomeFeatureEnabled = ConfigCat.get_value("isMyAwesomeFeatureEnabled", false) if isMyAwesomeFeatureEnabled do do_the_new_thing() else do_the_old_thing() end ``` ## Setting up the *ConfigCat Client*[​](#setting-up-the-configcat-client "Direct link to setting-up-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `{ConfigCat, options}` returns a client with default options. | Properties | Description | | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sdk_key` | **REQUIRED.** SDK Key to access your feature flags and settings. Get it from the *ConfigCat Dashboard*. | | `base_url` | Sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | `data_governance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. Defaults to `:global`. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `:global`, `:eu_only`. | | `cache_policy` | `CachePolicy.auto/1`, `CachePolicy.lazy/1` and `CachePolicy.manual/0`. Defaults to: `CachePolicy.auto/0` See [See below](#polling-modes) for details. | | `cache` | Caching module you want `configcat` to use. Defaults to: `ConfigCat.InMemoryCache`. [More about cache](#custom-cache-behaviour-with-cache-option-parameter). | | `http_proxy` | Specify this option if you need to use a proxy server to access your ConfigCat settings. You can provide a simple URL, like `https://my_proxy.example.com` or include authentication information, like `https://user:password@my_proxy.example.com/`. | | `connect_timeout_milliseconds` | Timeout for establishing a TCP or SSL connection, in milliseconds. Default is 8000. | | `read_timeout_milliseconds` | Timeout for receiving an HTTP response from the socket, in milliseconds. Default is 5000. | | `flag_overrides` | Local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides) | | `default_user` | Sets the default user. [More about default user](#default-user). | | `offline` | Defaults to `false`. Indicates whether the SDK should be initialized in offline mode. [More about offline mode](#online--offline-mode). | | `hooks` | Used to subscribe events that the SDK sends in specific scenarios. [More about hooks](#hooks). | | `name` | A unique identifier for this instance of `ConfigCat`. Defaults to `ConfigCat`. Must be provided if you need to run more than one instance of `ConfigCat` in the same application. If you provide a `name`, you must then pass that name to all of the API functions using the `client` option. [More about multiple instances](#multiple-configcat-instances). | ## Anatomy of `get_value()`[​](#anatomy-of-get_value "Direct link to anatomy-of-get_value") | Parameters | Description | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `default_value` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *ConfigCat.User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | | `client` | If you are running multiple instances of `ConfigCat`, provide the `client: :unique_name` option, specifying the name of the instance which you want to access. | ```elixir value = ConfigCat.get_value( "keyOfMySetting", # Setting Key false, # Default value ConfigCat.User.new("#UNIQUE-USER-IDENTIFIER#") # Optional User Object ) ``` ## Anatomy of `get_value_details()`[​](#anatomy-of-getvaluedetails "Direct link to anatomy-of-getvaluedetails") `get_value_details()` is similar to `get_value()` but instead of returning the evaluated value only, it gives more detailed information about the evaluation result. | Parameters | Description | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `default_value` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | | `client` | If you are running multiple instances of `ConfigCat`, provide the `client: :unique_name` option, specifying the name of the instance which you want to access. | ```elixir details = ConfigCat.get_value_details( "keyOfMySetting", # Setting Key false, # Default value ConfigCat.User.new("#UNIQUE-USER-IDENTIFIER#") # Optional User Object ) ``` The `details` result contains the following information: | Field | Description | | --------------------------- | ---------------------------------------------------------------------------------------------------------- | | `value` | The evaluated value of the feature flag or setting. | | `key` | The key of the evaluated feature flag or setting. | | `default_value?` | True when the default value passed to `get_value_details()` is returned due to an error. | | `error` | In case of an error, this field contains the error message. | | `user` | The User Object that was used for evaluation. | | `matched_targeting_rule` | The targeting rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matched_percentage_option` | The percentage option (if any) that was used to select the evaluated value. | | `fetch_time` | The last download time (UTC DateTime) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. ```elixir user_object = ConfigCat.User.new("#UNIQUE-USER-IDENTIFIER#") user_object = ConfigCat.User.new("john@example.com") ``` | Parameters | Description | | ------------ | -------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any `String` value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional `Map` for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | ```elixir user_object = ConfigCat.User.new("#UNIQUE-USER-IDENTIFIER#", email: "john@example", country: "United Kingdom", custom: %{SubscriptionType: "Pro", UserRole: "Admin"}) ``` The `custom` dictionary also allows attribute values other than `String` values: ```elixir user_object = ConfigCat.User.new( "#UNIQUE-USER-IDENTIFIER#", custom: %{ "Rating" => 4.5, "RegisteredAt" => ~U[2023-09-19T11:01:35.999Z], "Roles" => [ "Role1", "Role2" ] } ) ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `String` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS\_ONE\_OF, etc.) * accept `String` values, * all other values are automatically converted to `String` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS\_ONE\_OF\_SEMVER, LESS\_THAN\_SEMVER, GREATER\_THAN\_SEMVER, etc.) * accept `String` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (EQUALS\_NUMBER, LESS\_THAN\_NUMBER, GREATER\_THAN\_OR\_EQUAL\_NUMBER, etc.) * accept `Float` values and all other numeric values which can safely be converted to `Float`, * accept `String` values containing a properly formatted, valid `Float` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE\_DATETIME / AFTER\_DATETIME) * accept `DateTime` and `NaiveDateTime` values, which are automatically converted to a second-based Unix timestamp (`NaiveDateTime` values are considered to be in UTC), * accept `Float` values representing a second-based Unix timestamp and all other numeric values which can safely be converted to `Float`, * accept `String` values containing a properly formatted, valid `Float` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY\_CONTAINS\_ANY\_OF / ARRAY\_NOT\_CONTAINS\_ANY\_OF) * accept arrays of `String`, * accept `String` values containing a valid JSON string which can be deserialized to an array of `String`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") There's an option to set a default User Object that will be used at feature flag and setting evaluation. It can be useful when your application has a single user only, or rarely switches users. You can set the default User Object either on SDK initialization: ```elixir {ConfigCat, [ sdk_key: "#YOUR-SDK-KEY#", default_user: ConfigCat.User.new("john@example.com") ]} ``` or with the `set_default_user` method of the ConfigCat client. ```elixir ConfigCat.set_default_user(ConfigCat.User.new("john@example.com")) ``` Whenever the `get_value`, `get_value_details`, `get_variation_id`, `get_all_variation_ids`, or `get_all_values` methods are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```elixir {ConfigCat, [ sdk_key: "#YOUR-SDK-KEY#", default_user: ConfigCat.User.new("john@example.com") ]} ``` ```elixir # The default user will be used in the evaluation process. value = ConfigCat.get_value("keyOfMySetting", false) ``` When the `user` parameter is specified on the requesting method, it takes precedence over the default user. ```elixir other_user = ConfigCat.User.new("brian@example.com") # otherUser will be used in the evaluation process. value = ConfigCat.get_value("keyOfMySetting", false, other_user) ``` For deleting the default user, you can do the following: ```elixir ConfigCat.clear_default_user() ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `get_value()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle.
[More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `poll_interval_seconds` option parameter to change the polling interval. ```elixir {ConfigCat, [ sdk_key: "#YOUR-SDK-KEY#", cache_policy: ConfigCat.CachePolicy.auto(poll_interval_seconds: 60) ]}, ``` Available options: | Option Parameter | Description | Default | | ---------------------------- | ---------------------------------------------------------------------------------------------------- | ------- | | `poll_interval_seconds` | Polling interval. | 60 | | `max_init_wait_time_seconds` | Maximum waiting time between the client initialization and the first config acquisition in secconds. | 5 | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `get_value()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `get_value()` will return the setting value after the cache is updated. Use `cache_refresh_interval_seconds` option parameter to set cache lifetime. ```elixir {ConfigCat, [ sdk_key: "#YOUR-SDK-KEY#", cache_policy: ConfigCat.CachePolicy.lazy(cache_refresh_interval_seconds: 300) ]} ``` Available options: | Option Parameter | Description | Default | | -------------------------------- | ----------- | ------- | | `cache_refresh_interval_seconds` | Cache TTL. | 60 | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `force_refresh()` is your application's responsibility. ```elixir ConfigCat.force_refresh() ``` > `get_value()` returns `default_value` if the cache is empty. Call `force_refresh()` to update the cache. ```elixir value = ConfigCat.get_value("key", "my default value") # Returns "my default value" ConfigCat.force_refresh() value = ConfigCat.get_value("key", "my default value") # Returns "value from server" ``` ### Custom cache behaviour with `cache:` option parameter[​](#custom-cache-behaviour-with-cache-option-parameter "Direct link to custom-cache-behaviour-with-cache-option-parameter") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`ConfigCache`](https://github.com/configcat/elixir-sdk/blob/main/lib/config_cat/config_cache.ex) behaviour and provide the `cache` option when initializing the SDK. This allows you to integrate ConfigCat with your existing caching infrastructure seamlessly. To be able to customize the caching layer, you need to implement the `ConfigCat.ConfigCache` behaviour: ```elixir defmodule MyApp.CustomConfigCache do alias ConfigCat.ConfigCache @behaviour ConfigCache @impl ConfigCache def get(cache_key) do # here you have to return with the cached value end @impl ConfigCache def set(cache_key, value) do # here you have to store the new value in the cache end end ``` Then use your custom cache implementation: ```elixir {ConfigCat, [ sdk_key: "#YOUR-SDK-KEY#", cache: MyApp.CustomConfigCache ]} ``` info The Elixir SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ### Multiple `ConfigCat` instances[​](#multiple-configcat-instances "Direct link to multiple-configcat-instances") If you need to run more than one instance of `ConfigCat`, there are two ways you can do it. #### Module-Based[​](#module-based "Direct link to Module-Based") You can create a module that uses ConfigCat and then call the ConfigCat API functions on that module. This is the recommended option, as it makes the calling code a bit clearer and simpler.
You can pass any of the options listed above as arguments to `use ConfigCat` or specify them in your supervisor. Arguments specified by the supervisor take precedence over those provided to `use ConfigCat`. ```elixir # lib/my_app/first_flags.ex defmodule MyApp.FirstFlags do use ConfigCat, sdk_key: "sdk_key_1" end # lib/my_app/second_flags.ex defmodule MyApp.SecondFlags do use ConfigCat, sdk_key: "sdk_key_2" end # lib/my_app/application.ex def start(_type, _args) do children = [ # ... other children ... FirstFlags, SecondFlags, ] opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) end # Calling code: FirstFlags.get_value("someKey", "default value") SecondFlags.get_value("otherKey", "other default") ``` #### Explicit Client[​](#explicit-client "Direct link to Explicit Client") If you prefer not to use the module-based solution, you can instead add multiple `ConfigCat` children to your application's supervision tree. You will need to give `ConfigCat` a unique `name` option for each, as well as using `Supervisor.child_spec/2` to provide a unique `id` for each instance. When calling the ConfigCat API functions, you'll pass a `client:` keyword argument with the unique `name` you gave to that instance. ```elixir # lib/my_app/application.ex def start(_type, _args) do children = [ # ... other children ... Supervisor.child_spec({ConfigCat, [sdk_key: "sdk_key_1", name: :first]}, id: :config_cat_1), Supervisor.child_spec({ConfigCat, [sdk_key: "sdk_key_2", name: :second]}, id: :config_cat_2), ] opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) end # Calling code: ConfigCat.get_value("someKey", "default value", client: :first) ConfigCat.get_value("otherKey", "other default", client: :second) ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `on_client_ready`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after instantiation. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `max_init_wait_time_seconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. Alternatively, in Auto Polling mode, you can wait for the first `onConfigChanged` event to be notified when the internal cache is actually populated with config data. * `on_config_changed(config: map())`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `on_flag_evaluated(evaluation_details: EvaluationDetails.t())`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`get_value_details`](#anatomy-of-getvaluedetails). * `on_error(error: String.t())`: This event is emitted when an error occurs within the client. You can subscribe to these events either on SDK initialization: ```elixir def on_flag_evaluated(evaluation_details) do # handle the event end {ConfigCat, [ sdk_key: "#YOUR-SDK-KEY#", hooks: [on_flag_evaluated: {__MODULE__, :on_flag_evaluated, []}] ]} ``` or with the `Hooks` property of the ConfigCat client: ```elixir ConfigCat.Hooks.add_on_flag_evaluated({__MODULE__, :on_flag_evaluated, []}) ``` A hook callback is either an anonymous function or a module/function name/extra\_arguments tuple. Each callback is passed specific arguments. These specific arguments are prepended to the extra arguments provided in the tuple (if any). For example, you might want to define a callback that sends a message to another process which the config changes. You can pass the pid of that process as an extra argument: ```elixir def MyModule do def subscribe_to_config_changes(subscriber_pid) do ConfigCat.hooks() |> ConfigCat.Hooks.add_on_config_changed({__MODULE__, :on_config_changed, [subscriber_pid]}) end def on_config_changed(config, pid) do send pid, {:config_changed, config} end end ``` ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases when you'd want to prevent the SDK from making HTTP calls, you can put it in offline mode: ```elixir ConfigCat.set_offline() ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To put the SDK back in online mode, you can do the following: ```elixir ConfigCat.set_online() ``` > With `ConfigCat.offline?` you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`:local_only`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`:local_over_remote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`:remote_over_local`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a file or a map. ### JSON File[​](#json-file "Direct link to JSON File") The SDK can load your feature flag & setting overrides from a file. #### File[​](#file "Direct link to File") ```elixir {ConfigCat, [ sdk_key: "#YOUR-SDK-KEY#", flag_overrides: ConfigCat.LocalFileDataSource.new( "path/to/the/local_flags.json", # path to the file :local_only # local/offline mode ) ]} ``` #### JSON File Structure[​](#json-file-structure "Direct link to JSON File Structure") The SDK supports 2 types of JSON structures to describe feature flags & settings. ##### 1. Simple (key-value) structure[​](#1-simple-key-value-structure "Direct link to 1. Simple (key-value) structure") ```json { "flags": { "enabledFeature": true, "disabledFeature": false, "intSetting": 5, "doubleSetting": 3.14, "stringSetting": "test" } } ``` ##### 2. Complex (full-featured) structure[​](#2-complex-full-featured-structure "Direct link to 2. Complex (full-featured) structure") This is the same format that the SDK downloads from the ConfigCat CDN. It allows the usage of all features that are available on the ConfigCat Dashboard. You can download your current config JSON from ConfigCat's CDN and use it as a baseline. A convenient way to get the config JSON for a specific SDK Key is to install the [ConfigCat CLI](https://github.com/configcat/cli) tool and execute the following command: ```bash configcat config-json get -f v6 -p {YOUR-SDK-KEY} > config.json ``` (Depending on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings, you may need to add the `--eu` switch.) Alternatively, you can download the config JSON manually, based on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings: * GLOBAL: `https://cdn-global.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` * EU: `https://cdn-eu.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` ```json { "p": { // hash salt, required only when confidential text comparator(s) are used "s": "80xCU/SlDz1lCiWFaxIBjyJeJecWjq46T4eu6GtozkM=" }, "s": [ // array of segments { "n": "Beta Users", // segment name "r": [ // array of User Conditions (there is a logical AND relation between the elements) { "a": "Email", // comparison attribute "c": 0, // comparator (see below) "l": [ // comparison value (see below) "john@example.com", "jane@example.com" ] } ] } ], "f": { // key-value map of feature flags & settings "isFeatureEnabled": { // key of a particular flag / setting "t": 0, // setting type, possible values: // 0 -> on/off setting (feature flag) // 1 -> text setting // 2 -> whole number setting // 3 -> decimal number setting "r": [ // array of Targeting Rules (there is a logical OR relation between the elements) { "c": [ // array of conditions (there is a logical AND relation between the elements) { "u": { // User Condition "a": "Email", // comparison attribute "c": 2, // comparator, possible values and required comparison value types: // 0 -> IS ONE OF (cleartext) + string array comparison value ("l") // 1 -> IS NOT ONE OF (cleartext) + string array comparison value ("l") // 2 -> CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 3 -> NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 4 -> IS ONE OF (semver) + semver string array comparison value ("l") // 5 -> IS NOT ONE OF (semver) + semver string array comparison value ("l") // 6 -> < (semver) + semver string comparison value ("s") // 7 -> <= (semver + semver string comparison value ("s") // 8 -> > (semver) + semver string comparison value ("s") // 9 -> >= (semver + semver string comparison value ("s") // 10 -> = (number) + number comparison value ("d") // 11 -> <> (number + number comparison value ("d") // 12 -> < (number) + number comparison value ("d") // 13 -> <= (number + number comparison value ("d") // 14 -> > (number) + number comparison value ("d") // 15 -> >= (number) + number comparison value ("d") // 16 -> IS ONE OF (hashed) + string array comparison value ("l") // 17 -> IS NOT ONE OF (hashed) + string array comparison value ("l") // 18 -> BEFORE (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 19 -> AFTER (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 20 -> EQUALS (hashed) + string comparison value ("s") // 21 -> NOT EQUALS (hashed) + string comparison value ("s") // 22 -> STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 23 -> NOT STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 24 -> ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 25 -> NOT ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 26 -> ARRAY CONTAINS ANY OF (hashed) + string array comparison value ("l") // 27 -> ARRAY NOT CONTAINS ANY OF (hashed) + string array comparison value ("l") // 28 -> EQUALS (cleartext) + string comparison value ("s") // 29 -> NOT EQUALS (cleartext) + string comparison value ("s") // 30 -> STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 31 -> NOT STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 32 -> ENDS WITH ANY OF (cleartext) + string array comparison value ("l") // 33 -> NOT ENDS WITH ANY OF (cleartext + string array comparison value ("l") // 34 -> ARRAY CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 35 -> ARRAY NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") "l": [ // comparison value - depending on the comparator, another type of value may need // to be specified (see above): // "s": string // "d": number "@example.com" ] } }, { "p": { // Flag Condition (Prerequisite) "f": "mainIntFlag", // key of prerequisite flag "c": 0, // comparator, possible values: 0 -> EQUALS, 1 -> NOT EQUALS "v": { // comparison value (value's type must match the prerequisite flag's type) "i": 42 } } }, { "s": { // Segment Condition "s": 0, // segment index, a valid index into the top-level segment array ("s") "c": 1 // comparator, possible values: 0 -> IS IN SEGMENT, 1 -> IS NOT IN SEGMENT } } ], "s": { // alternatively, an array of Percentage Options ("p", see below) can also be specified "v": { // the value served when the rule is selected during evaluation "b": true }, "i": "bcfb84a7" } } ], "p": [ // array of Percentage Options { "p": 10, // % value "v": { // the value served when the Percentage Option is selected during evaluation "b": true }, "i": "bcfb84a7" }, { "p": 90, "v": { "b": false }, "i": "bddac6ae" } ], "v": { // fallback value, served when none of the Targeting Rules match, // no Percentage Options are defined or evaluation of these is not possible "b": false // depending on the setting type, another type of value may need to be specified: // text setting -> "s": string // whole number setting -> "i": number // decimal number setting -> "d": number }, "i": "430bded3" // variation id (for analytical purposes) } } } ``` For a more comprehensive specification of the config JSON v6 format, you may refer to [this JSON schema document](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ### Map[​](#map "Direct link to Map") You can set up the SDK to load your feature flag & setting overrides from a map. ```elixir map = %{ "enabledFeature" => true, "disabledFeature" => false, "intSetting" => 5, "doubleSetting" => 3.14, "stringSetting" => "test" } {ConfigCat, [ sdk_key: "#YOUR-SDK-KEY#", flag_overrides: ConfigCat.LocalMapDataSource.new(map, :local_only) ]} ``` ## Logging[​](#logging "Direct link to Logging") In the *ConfigCat SDK*, we use the default Elixir's [Logger](https://hexdocs.pm/logger/Logger.html) so you can customise as you like. Debug level logging helps to inspect how a feature flag was evaluated: ```bash [debug] [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"","Email":"configcat@example.com","Country":"US","SubscriptionType":"Pro","Role":"Admin","version":"1.0.0"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` The following example shows how to set the *Log Level* on the internal *ConfigCat* logger. Set the log level of the module with [put\_module\_level/2](https://hexdocs.pm/logger/1.15.6/Logger.html#put_module_level/2) function. Put the following code into your application.ex file and run it on start: ```elixir defp set_config_cat_log_level do :configcat |> Application.spec(:modules) |> Logger.put_module_level(:debug) end ``` On Elixir 1.13 or later you can use [put\_application\_level/2](https://hexdocs.pm/logger/1.15.6/Logger.html#put_application_level/2) function which is equivalent to the code above. ## `get_all_keys()`[​](#get_all_keys "Direct link to get_all_keys") You can get the keys for all available feature flags and settings by calling the `get_all_keys()` method. ```elixir keys = ConfigCat.get_all_keys() ``` ## `get_all_values()`[​](#get_all_values "Direct link to get_all_values") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```elixir values = ConfigCat.get_all_values( ConfigCat.User.new("#UNIQUE-USER-IDENTIFIER#") # Optional User Object ) ``` ## `get_all_value_details()`[​](#get_all_value_details "Direct link to get_all_value_details") Evaluates and returns the detailed values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```elixir all_value_details = ConfigCat.get_all_value_details( ConfigCat.User.new("#UNIQUE-USER-IDENTIFIER#") # Optional User Object ) ``` ## Using ConfigCat behind a proxy[​](#using-configcat-behind-a-proxy "Direct link to Using ConfigCat behind a proxy") Provide your own network credentials (username/password), and proxy server settings (proxy server/port) by passing the proxy details to the creator method. ```elixir {ConfigCat, [ sdk_key: "#YOUR-SDK-KEY#", http_proxy: "https://user@pass:yourproxy.com" ]} ``` ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [Sample App](https://github.com/configcat/elixir-sdk/tree/main/samples) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat's Elixir SDK on GitHub](https://github.com/configcat/elixir-sdk) * [ConfigCat's HexDocs](https://hexdocs.pm/configcat) * [ConfigCat's Elixir SDK on Hex.pm](https://hex.pm/packages/configcat) --- # Source: https://configcat.com/docs/advanced/proxy/endpoints.md # Endpoints Copy page The Proxy accepts HTTP requests on the following endpoints. ## CDN Proxy[​](#cdn-proxy "Direct link to CDN Proxy") The CDN proxy endpoint's purpose is to forward the underlying *config JSON* to other ConfigCat SDKs used by your application. GETOPTIONS/configuration-files/{path} This endpoint is mainly used by ConfigCat SDKs to retrieve all required data for feature flag evaluation. **Route parameters**: * `path`: It's set by the ConfigCat SDK configured to use the ConfigCat Proxy. It contains either an SDK key or an [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that uniquely identifies an SDK within the Proxy. **Responses**: * 200: The `config.json` file is downloaded successfully. * 204: In response to an `OPTIONS` request. * 304: The `config.json` file isn't modified based on the `Etag` sent in the `If-None-Match` header. * 400: The `sdkId` is missing. * 404: The `sdkId` is pointing to a non-existent SDK. ### SDK Usage[​](#sdk-usage "Direct link to SDK Usage") In order to let a ConfigCat SDK use the Proxy, you have to set the SDK's `baseUrl` parameter to point to the Proxy's host. example.js ```js import * as configcat from "@configcat/sdk"; const configCatClient = configcat.getClient( "#YOUR-SDK-KEY#", configcat.PollingMode.AutoPoll, { baseUrl: "http://localhost:8050" } // Proxy URL ); ``` Additionally, as the Proxy maps [unique identifiers to each configured SDK key](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) it works with, you can use that identifier prefixed with `configcat-proxy/` as the SDK key at the ConfigCat SDK's initialization. So, let's assume you set up the Proxy with an SDK key mapped to the `my_sdk` SDK identifier: example.js ```js import * as configcat from "@configcat/sdk"; const configCatClient = configcat.getClient( "configcat-proxy/my_sdk", // SDK identifier prefixed with 'configcat-proxy/' configcat.PollingMode.AutoPoll, { baseUrl: "http://localhost:8050" } // Proxy URL ); ``` ### Supported SDK Versions[​](#supported-sdk-versions "Direct link to Supported SDK Versions") The following SDK versions are supported by the `>=v0.3.X` Proxy's CDN endpoint: | SDK | Version | | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | .NET | >= [v9.0.0](https://github.com/configcat/.net-sdk/releases/tag/v9.0.0) | | Android (Java) | >= [v10.0.0](https://github.com/configcat/android-sdk/releases/tag/v10.0.0) | | C++ | >= [v4.0.0](https://github.com/configcat/cpp-sdk/releases/tag/v4.0.0) | | Dart (Flutter) | >= [v4.0.0](https://github.com/configcat/dart-sdk/releases/tag/4.0.0) | | Elixir | >= [v4.0.0](https://github.com/configcat/elixir-sdk/releases/tag/v4.0.0) | | Go | >= [v9.0.0](https://github.com/configcat/go-sdk/releases/tag/v9.0.0) | | Java | >= [v9.0.0](https://github.com/configcat/java-sdk/releases/tag/v9.0.0) | | JavaScript (Browser, Bun, Chromium Extension, Cloudflare Worker, Deno, Node) | >= [v1.0.0](https://github.com/configcat/js-unified-sdk/releases) | | JS - Legacy | >= [v9.0.0](https://github.com/configcat/js-sdk/releases/tag/v9.0.0) | | JS SSR - Legacy | >= [v8.0.0](https://github.com/configcat/js-ssr-sdk/releases/tag/v8.0.0) | | Kotlin | >= [v3.0.0](https://github.com/configcat/kotlin-sdk/releases/tag/3.0.0) | | Node - Legacy | >= [v11.0.0](https://github.com/configcat/node-sdk/releases/tag/v11.0.0) | | PHP 8.1+ | >= [v9.0.0](https://github.com/configcat/php-sdk/releases/tag/v9.0.0) | | PHP 7.1+ | >= [v3.0.0](https://github.com/configcat/php7-sdk/releases/tag/v3.0.0) | | Python | >= [v9.0.3](https://github.com/configcat/python-sdk/releases/tag/v9.0.3) | | React | >= [v4.0.0](https://github.com/configcat/react-sdk/releases/tag/v4.0.0) | | Ruby | >= [v8.0.0](https://github.com/configcat/ruby-sdk/releases/tag/v8.0.0) | | Rust | >= [v0.1.0](https://github.com/configcat/rust-sdk/releases/tag/v0.1.0) | | Swift (iOS) | >= [v11.0.0](https://github.com/configcat/swift-sdk/releases/tag/11.0.0) | ### Available Options[​](#available-options "Direct link to Available Options") The following CDN Proxy related options are available: | Option | Default | Description | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | - YAML
- Environment variable```yaml http: cdn_proxy: enabled: ``````shell CONFIGCAT_HTTP_CDN_PROXY_ENABLED= ``` | `true` | Turns the hosting of the CDN proxy endpoint on/off. This endpoint can be used by other ConfigCat SDKs in your applications. | | - YAML
- Environment variable```yaml http: cdn_proxy: cors: enabled: ``````shell CONFIGCAT_HTTP_CDN_PROXY_CORS_ENABLED= ``` | `true` | Turns the sending of CORS headers on/off. It can be used to restrict access to specific domains. By default, the Proxy allows each origin by setting the `Access-Control-Allow-Origin` response header to the request's origin. You can override this functionality by restricting the allowed origins with the `allowed_origins` or `allowed_origins_regex` options. | | - YAML
- Environment variable```yaml http: cdn_proxy: cors: allowed_origins: - https://domain1.com - https://domain2.com ``````shell CONFIGCAT_HTTP_CDN_PROXY_CORS_ALLOWED_ORIGINS='["https://domain1.com","https://domain2.com"]' ``` | - | List of allowed CORS origins. When it's set, the Proxy will include only that origin in the `Access-Control-Allow-Origin` response header which matches the request's `Origin`.
When there's no matching request origin and the `allowed_origins_regex` option is not set, the Proxy will set the `Access-Control-Allow-Origin` response header to the first item in the allowed origins list. | | - YAML
- Environment variable```yaml http: cdn_proxy: cors: allowed_origins_regex: patterns: - https:\/\/.*domain1\.com - https:\/\/.*domain2\.com ``````shell CONFIGCAT_HTTP_CDN_PROXY_CORS_ALLOWED_ORIGINS_REGEX_PATTERNS='["https:\\/\\/.*domain1\\.com","https:\\/\\/.*domain2\\.com"]' ``` | - | List of regex patterns used to match allowed CORS origins. When it's set, the Proxy will match the request's `Origin` with the given regex patterns. When there's a match, the `Access-Control-Allow-Origin` response header will be set to the matched origin.
When there's no matching request origin, the Proxy will set the `Access-Control-Allow-Origin` response header to the `if_no_match` field's value.
The `if_no_match` option is mandatory if this option is used.
When using the environment variable, the regex escape character must be doubled (`\\`) because it's parsed as a JSON list and `\` is also a JSON escape character. | | - YAML
- Environment variable```yaml http: cdn_proxy: cors: allowed_origins_regex: if_no_match: https://domain1.com ``````shell CONFIGCAT_HTTP_CDN_PROXY_CORS_ALLOWED_ORIGINS_REGEX_IF_NO_MATCH="https://domain1.com" ``` | - | Required when the previous `patterns` option is set. It's value is used in the `Access-Control-Allow-Origin` header when an incoming request's `Origin` doesn't match with any previously configured regex patterns. | | - YAML
- Environment variable```yaml http: cdn_proxy: headers: Custom-Header-Name: "" ``````shell CONFIGCAT_HTTP_CDN_PROXY_HEADERS='{"Custom-Header-Name":""}' ``` | - | Additional headers that must be sent back on each CDN proxy endpoint response. | ## API[​](#api "Direct link to API") These API endpoints are for server side feature flag evaluation. ### Endpoints using SDK key[​](#endpoints-using-sdk-key "Direct link to Endpoints using SDK key") The following endpoints are using SDK keys to determine which config / environment is the target of the desired action. The SDK key must be provided in the `X-ConfigCat-SdkKey` HTTP header. info These endpoints are only available from Proxy version [`v3.0.0`](https://github.com/configcat/configcat-proxy/releases/tag/v3.0.0). POSTOPTIONS/api/eval This endpoint evaluates a single feature flag identified by a `key` with the given [User Object](https://configcat.com/docs/targeting/user-object.md). **Headers**: * `X-ConfigCat-SdkKey`: The SDK key that determines the feature flag's config / environment. **Request body**: ```json { "key": "", "user": { "Identifier": "", "Rating": 4.5, "Roles": ["Role1","Role2"], // any other attribute } } ``` The type of the `user` object's fields can only be `string`, `number`, or `string[]`. **Responses**: * 200: The feature flag evaluation finished successfully. * Response body: ```json { "value": , "variationId": "" } ``` 204: In response to an `OPTIONS` request. * 400: The `X-ConfigCat-SdkKey` header or the `key` from the request body is missing. * 404: The `X-ConfigCat-SdkKey` header is pointing to a non-existent SDK. **Example**: example.js ```js const url = "http://localhost:8050/api/eval"; // Proxy API URL const data = { key: "isMyAwesomeFeatureEnabled", // Feature flag key user: { // User Object for evaluation Identifier: "#UNIQUE-USER-IDENTIFIER#" } }; const requestOptions = { method: "POST", headers: { "X-ConfigCat-SdkKey": "#YOUR-SDK-KEY#", "Content-Type": "application/json", }, body: JSON.stringify(data), }; try { const response = await fetch(url, requestOptions); const responseData = await response.json(); console.log(responseData); // {"value":,"variationId":""} } catch (error) { console.error("Error:", error) } ``` POSTOPTIONS/api/eval-all This endpoint evaluates all feature flags with the given [User Object](https://configcat.com/docs/targeting/user-object.md). **Headers**: * `X-ConfigCat-SdkKey`: The SDK key that determines which config's feature flags should be evaluated in which environment. **Request body**: ```json { "user": { "Identifier": "", "Rating": 4.5, "Roles": ["Role1","Role2"], // any other attribute } } ``` The type of the `user` object's fields can only be `string`, `number`, or `string[]`. **Responses**: * 200: The evaluation of all feature flags finished successfully. * Response body: ```json { "feature-flag-key-1": { "value": , "variationId": "" }, "feature-flag-key-2": { "value": , "variationId": "" } } ``` 204: In response to an `OPTIONS` request. * 400: The `X-ConfigCat-SdkKey` header is missing. * 404: The `X-ConfigCat-SdkKey` header is pointing to a non-existent SDK. **Example**: example.js ```js const url = "http://localhost:8050/api/eval-all"; // Proxy API URL const data = { user: { // User Object for evaluation Identifier: "#UNIQUE-USER-IDENTIFIER#" } }; const requestOptions = { method: "POST", headers: { "X-ConfigCat-SdkKey": "#YOUR-SDK-KEY#", "Content-Type": "application/json", }, body: JSON.stringify(data), }; try { const response = await fetch(url, requestOptions); const responseData = await response.json(); console.log(responseData); } catch (error) { console.error("Error:", error) } ``` POSTOPTIONS/api/refresh This endpoint commands the underlying SDK to download the latest available *config JSON*. **Headers**: * `X-ConfigCat-SdkKey`: The SDK key that identifies an SDK within the Proxy. **Responses**: * 200: The refresh was successful. * 204: In response to an `OPTIONS` request. * 400: The `X-ConfigCat-SdkKey` header is missing. * 404: The `X-ConfigCat-SdkKey` header is pointing to a non-existent SDK. GETOPTIONS/api/keys This endpoint returns all feature flag keys belonging to the given SDK key. **Headers**: * `X-ConfigCat-SdkKey`: The SDK key that identifies an SDK within the Proxy. **Responses**: * 200: The keys are returned successfully. * Response body: ```json { "keys": [ "feature-flag-key-1", "feature-flag-key-2" ] } ``` 204: In response to an `OPTIONS` request. * 400: The `X-ConfigCat-SdkKey` header is missing. * 404: The `X-ConfigCat-SdkKey` header is pointing to a non-existent SDK. ### Endpoints using SDK identifier[​](#endpoints-using-sdk-identifier "Direct link to Endpoints using SDK identifier") The following endpoints are using an [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) to determine which config / environment is the target of the desired action. The SDK identifier must be provided as a route parameter of the HTTP request. POSTOPTIONS/api/{sdkId}/eval This endpoint evaluates a single feature flag identified by a `key` with the given [User Object](https://configcat.com/docs/targeting/user-object.md). **Route parameters**: * `sdkId`: The [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that determines the feature flag's config / environment. **Request body**: ```json { "key": "", "user": { "Identifier": "", "Rating": 4.5, "Roles": ["Role1","Role2"], // any other attribute } } ``` The type of the `user` object's fields can only be `string`, `number`, or `string[]`. **Responses**: * 200: The feature flag evaluation finished successfully. * Response body: ```json { "value": , "variationId": "" } ``` 204: In response to an `OPTIONS` request. * 400: The `sdkId` or the `key` from the request body is missing. * 404: The `sdkId` is pointing to a non-existent SDK. **Example**: example.js ```js const url = "http://localhost:8050/api/#SDK-IDENTIFIER#/eval"; // Proxy API URL with SDK identifier const data = { key: "isMyAwesomeFeatureEnabled", // Feature flag key user: { // User Object for evaluation Identifier: "#UNIQUE-USER-IDENTIFIER#" } }; const requestOptions = { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }; try { const response = await fetch(url, requestOptions); const responseData = await response.json(); console.log(responseData); // {"value":,"variationId":""} } catch (error) { console.error("Error:", error) } ``` POSTOPTIONS/api/{sdkId}/eval-all This endpoint evaluates all feature flags with the given [User Object](https://configcat.com/docs/targeting/user-object.md). **Route parameters**: * `sdkId`: The [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that determines which config's feature flags should be evaluated in which environment. **Request body**: ```json { "user": { "Identifier": "", "Rating": 4.5, "Roles": ["Role1","Role2"], // any other attribute } } ``` The type of the `user` object's fields can only be `string`, `number`, or `string[]`. **Responses**: * 200: The evaluation of all feature flags finished successfully. * Response body: ```json { "feature-flag-key-1": { "value": , "variationId": "" }, "feature-flag-key-2": { "value": , "variationId": "" } } ``` 204: In response to an `OPTIONS` request. * 400: The `sdkId` is missing. * 404: The `sdkId` is pointing to a non-existent SDK. **Example**: example.js ```js const url = "http://localhost:8050/api/#SDK-IDENTIFIER#/eval-all"; // Proxy API URL with SDK identifier const data = { user: { // User Object for evaluation Identifier: "#UNIQUE-USER-IDENTIFIER#" } }; const requestOptions = { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }; try { const response = await fetch(url, requestOptions); const responseData = await response.json(); console.log(responseData); } catch (error) { console.error("Error:", error) } ``` POSTOPTIONS/api/{sdkId}/refresh This endpoint commands the underlying SDK to download the latest available *config JSON*. **Route parameters**: * `sdkId`: The [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that uniquely identifies an SDK within the Proxy. **Responses**: * 200: The refresh was successful. * 204: In response to an `OPTIONS` request. * 400: The `sdkId` is missing. * 404: The `sdkId` is pointing to a non-existent SDK. GETOPTIONS/api/{sdkId}/keys This endpoint returns all feature flag keys belonging to the given [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key). **Route parameters**: * `sdkId`: The [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that uniquely identifies an SDK within the Proxy. **Responses**: * 200: The keys are returned successfully. * Response body: ```json { "keys": [ "feature-flag-key-1", "feature-flag-key-2" ] } ``` 204: In response to an `OPTIONS` request. * 400: The `sdkId` is missing. * 404: The `sdkId` is pointing to a non-existent SDK. ### Available Options[​](#available-options-1 "Direct link to Available Options") The following API related options are available: | Option | Default | Description | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | - YAML
- Environment variable```yaml http: api: enabled: ``````shell CONFIGCAT_HTTP_API_ENABLED= ``` | `true` | Turns the hosting of the API endpoints on/off. These endpoints can be used for server side feature flag evaluation. | | - YAML
- Environment variable```yaml http: api: cors: enabled: ``````shell CONFIGCAT_HTTP_API_CORS_ENABLED= ``` | `true` | Turns the sending of CORS headers on/off. It can be used to restrict access to specific domains. By default, the Proxy allows each origin by setting the `Access-Control-Allow-Origin` response header to the request's origin. You can override this functionality by restricting the allowed origins with the `allowed_origins` or `allowed_origins_regex` options. | | - YAML
- Environment variable```yaml http: api: cors: allowed_origins: - https://domain1.com - https://domain2.com ``````shell CONFIGCAT_HTTP_API_CORS_ALLOWED_ORIGINS='["https://domain1.com","https://domain2.com"]' ``` | - | List of allowed CORS origins. When it's set, the Proxy will include only that origin in the `Access-Control-Allow-Origin` response header which matches the request's `Origin`.
When there's no matching request origin and the `allowed_origins_regex` option is not set, the Proxy will set the `Access-Control-Allow-Origin` response header to the first item in the allowed origins list. | | - YAML
- Environment variable```yaml http: api: cors: allowed_origins_regex: patterns: - https:\/\/.*domain1\.com - https:\/\/.*domain2\.com ``````shell CONFIGCAT_HTTP_API_CORS_ALLOWED_ORIGINS_REGEX_PATTERNS='["https:\\/\\/.*domain1\\.com","https:\\/\\/.*domain2\\.com"]' ``` | - | List of regex patterns used to match allowed CORS origins. When it's set, the Proxy will match the request's `Origin` with the given regex patterns. When there's a match, the `Access-Control-Allow-Origin` response header will be set to the matched origin.
When there's no matching request origin, the Proxy will set the `Access-Control-Allow-Origin` response header to the `if_no_match` field's value.
The `if_no_match` option is mandatory if this option is used.
When using the environment variable, the regex escape character must be doubled (`\\`) because it's parsed as a JSON list and `\` is also a JSON escape character. | | - YAML
- Environment variable```yaml http: api: cors: allowed_origins_regex: if_no_match: https://domain1.com ``````shell CONFIGCAT_HTTP_API_CORS_ALLOWED_ORIGINS_REGEX_IF_NO_MATCH="https://domain1.com" ``` | - | Required when the previous `patterns` option is set. It's value is used in the `Access-Control-Allow-Origin` header when an incoming request's `Origin` doesn't match with any previously configured regex patterns. | | - YAML
- Environment variable```yaml http: api: headers: Custom-Header-Name: "" ``````shell CONFIGCAT_HTTP_API_HEADERS='{"Custom-Header-Name":""}' ``` | - | Additional headers that must be sent back on each API endpoint response. | | - YAML
- Environment variable```yaml http: api: auth_headers: X-API-KEY: "" ``````shell CONFIGCAT_HTTP_API_AUTH_HEADERS='{"X-API-KEY":""}' ``` | - | Additional headers that must be on each request sent to the API endpoints. If the request doesn't include the specified header, or the values are not matching, the Proxy will respond with a `401` HTTP status code. | ## OpenFeature Remote Evaluation Protocol (OFREP)[​](#openfeature-remote-evaluation-protocol-ofrep "Direct link to OpenFeature Remote Evaluation Protocol (OFREP)") info OFREP compatibility is only available from Proxy version [`v2.0.0`](https://github.com/configcat/configcat-proxy/releases/tag/v2.0.0). The Proxy conforms to the [OpenFeature Remote Evaluation Protocol](https://github.com/open-feature/protocol), which means it can be used with OFREP compatible OpenFeature providers. ### Endpoints using SDK key[​](#endpoints-using-sdk-key-1 "Direct link to Endpoints using SDK key") The following endpoints are using SDK keys to determine which config / environment is the target of the desired action. The SDK key must be provided in the `X-ConfigCat-SdkKey` HTTP header. info These endpoints are only available from Proxy version [`v3.0.0`](https://github.com/configcat/configcat-proxy/releases/tag/v3.0.0). POSTOPTIONS/ofrep/v1/evaluate/flags/{key} This endpoint is used by OFREP compatible OpenFeature providers to evaluate a feature flag. **Route parameters**: * `key`: The key of the feature flag to evaluate. **Headers**: * `X-ConfigCat-SdkKey`: The SDK key that determines the feature flag's config / environment. **Request body**: ```json { "context": { "targetingKey": "", "Rating": 4.5, "Roles": ["Role1","Role2"], } } ``` **Responses**: * 200: The feature flag evaluation finished successfully. * Response body: ```json { "key": "", "value": , "variant": "", "reason": "" } ``` 204: In response to an `OPTIONS` request. * 400: The `X-ConfigCat-SdkKey` header is missing. * 404: The `X-ConfigCat-SdkKey` header is pointing to a non-existent SDK or the feature flag for `key` is not found. **Example**: example.js ```js import { OpenFeature } from "@openfeature/web-sdk"; import { OFREPWebProvider } from '@openfeature/ofrep-web-provider'; OpenFeature.setProvider( new OFREPWebProvider({ baseUrl: "http://localhost:8050", // Proxy URL headers: [ ["X-ConfigCat-SdkKey", "#YOUR-SDK-KEY#"], ], }), ); ``` POSTOPTIONS/ofrep/v1/evaluate/flags This endpoint is used by OFREP compatible OpenFeature providers to evaluate all feature flags. **Headers**: * `X-ConfigCat-SdkKey`: The SDK key that determines which config's feature flags should be evaluated in which environment. **Request body**: ```json { "context": { "targetingKey": "", "Rating": 4.5, "Roles": ["Role1","Role2"], } } ``` **Responses**: * 200: The evaluation of all feature flags finished successfully. * Response body: ```json { "flags": [ { "key": "", "value": , "variant": "", "reason": "" }, { "key": "", "value": , "variant": "", "reason": "" } ] } ``` 204: In response to an `OPTIONS` request. * 400: The `X-ConfigCat-SdkKey` header is missing. * 404: The `X-ConfigCat-SdkKey` header is pointing to a non-existent SDK. **Example**: example.js ```js import { OpenFeature } from "@openfeature/web-sdk"; import { OFREPWebProvider } from '@openfeature/ofrep-web-provider'; OpenFeature.setProvider( new OFREPWebProvider({ baseUrl: "http://localhost:8050", // Proxy URL headers: [ ["X-ConfigCat-SdkKey", "#YOUR-SDK-KEY#"], ], }), ); ``` ### Endpoints using SDK identifier[​](#endpoints-using-sdk-identifier-1 "Direct link to Endpoints using SDK identifier") The following endpoints are using an [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) to determine which config / environment is the target of the desired action. The SDK identifier must be provided in the `X-ConfigCat-SdkId` HTTP header. POSTOPTIONS/ofrep/v1/evaluate/flags/{key} This endpoint is used by OFREP compatible OpenFeature providers to evaluate a feature flag. **Route parameters**: * `key`: The key of the feature flag to evaluate. **Headers**: * `X-ConfigCat-SdkId`: The [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that determines the feature flag's config / environment. **Request body**: ```json { "context": { "targetingKey": "", "Rating": 4.5, "Roles": ["Role1","Role2"], } } ``` **Responses**: * 200: The feature flag evaluation finished successfully. * Response body: ```json { "key": "", "value": , "variant": "", "reason": "" } ``` 204: In response to an `OPTIONS` request. * 400: The `X-ConfigCat-SdkId` header is missing. * 404: The `X-ConfigCat-SdkId` header is pointing to a non-existent SDK or the feature flag for `key` is not found. **Example**: example.js ```js import { OpenFeature } from "@openfeature/web-sdk"; import { OFREPWebProvider } from '@openfeature/ofrep-web-provider'; OpenFeature.setProvider( new OFREPWebProvider({ baseUrl: "http://localhost:8050", // Proxy URL headers: [ ["X-ConfigCat-SdkId", "#SDK-IDENTIFIER#"], ], }), ); ``` POSTOPTIONS/ofrep/v1/evaluate/flags This endpoint is used by OFREP compatible OpenFeature providers to evaluate all feature flags. **Headers**: * `X-ConfigCat-SdkId`: The [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that determines which config's feature flags should be evaluated in which environment. **Request body**: ```json { "context": { "targetingKey": "", "Rating": 4.5, "Roles": ["Role1","Role2"], } } ``` **Responses**: * 200: The evaluation of all feature flags finished successfully. * Response body: ```json { "flags": [ { "key": "", "value": , "variant": "", "reason": "" }, { "key": "", "value": , "variant": "", "reason": "" } ] } ``` 204: In response to an `OPTIONS` request. * 400: The `X-ConfigCat-SdkId` header is missing. * 404: The `X-ConfigCat-SdkId` header is pointing to a non-existent SDK. **Example**: example.js ```js import { OpenFeature } from "@openfeature/web-sdk"; import { OFREPWebProvider } from '@openfeature/ofrep-web-provider'; OpenFeature.setProvider( new OFREPWebProvider({ baseUrl: 'http://localhost:8050', // Proxy URL headers: [ ["X-ConfigCat-SdkId", "#SDK-IDENTIFIER#"], ], }), ); ``` ### Available Options[​](#available-options-2 "Direct link to Available Options") The following OFREP related options are available: | Option | Default | Description | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | - YAML
- Environment variable```yaml http: ofrep: enabled: ``````shell CONFIGCAT_HTTP_OFREP_ENABLED= ``` | `true` | Turns the hosting of the OFREP endpoints on/off. These endpoints can be used by OFREP compatible OpenFeature providers for server side feature flag evaluation. | | - YAML
- Environment variable```yaml http: ofrep: cors: enabled: ``````shell CONFIGCAT_HTTP_OFREP_CORS_ENABLED= ``` | `true` | Turns the sending of CORS headers on/off. It can be used to restrict access to specific domains. By default, the Proxy allows each origin by setting the `Access-Control-Allow-Origin` response header to the request's origin. You can override this functionality by restricting the allowed origins with the `allowed_origins` or `allowed_origins_regex` options. | | - YAML
- Environment variable```yaml http: ofrep: cors: allowed_origins: - https://domain1.com - https://domain2.com ``````shell CONFIGCAT_HTTP_OFREP_CORS_ALLOWED_ORIGINS='["https://domain1.com","https://domain2.com"]' ``` | - | List of allowed CORS origins. When it's set, the Proxy will include only that origin in the `Access-Control-Allow-Origin` response header which matches the request's `Origin`.
When there's no matching request origin and the `allowed_origins_regex` option is not set, the Proxy will set the `Access-Control-Allow-Origin` response header to the first item in the allowed origins list. | | - YAML
- Environment variable```yaml http: ofrep: cors: allowed_origins_regex: patterns: - https:\/\/.*domain1\.com - https:\/\/.*domain2\.com ``````shell CONFIGCAT_HTTP_OFREP_CORS_ALLOWED_ORIGINS_REGEX_PATTERNS='["https:\\/\\/.*domain1\\.com","https:\\/\\/.*domain2\\.com"]' ``` | - | List of regex patterns used to match allowed CORS origins. When it's set, the Proxy will match the request's `Origin` with the given regex patterns. When there's a match, the `Access-Control-Allow-Origin` response header will be set to the matched origin.
When there's no matching request origin, the Proxy will set the `Access-Control-Allow-Origin` response header to the `if_no_match` field's value.
The `if_no_match` option is mandatory if this option is used.
When using the environment variable, the regex escape character must be doubled (`\\`) because it's parsed as a JSON list and `\` is also a JSON escape character. | | - YAML
- Environment variable```yaml http: ofrep: cors: allowed_origins_regex: if_no_match: https://domain1.com ``````shell CONFIGCAT_HTTP_OFREP_CORS_ALLOWED_ORIGINS_REGEX_IF_NO_MATCH="https://domain1.com" ``` | - | Required when the previous `patterns` option is set. It's value is used in the `Access-Control-Allow-Origin` header when an incoming request's `Origin` doesn't match with any previously configured regex patterns. | | - YAML
- Environment variable```yaml http: ofrep: headers: Custom-Header-Name: "" ``````shell CONFIGCAT_HTTP_OFREP_HEADERS='{"Custom-Header-Name":""}' ``` | - | Additional headers that must be sent back on each OFREP endpoint response. | | - YAML
- Environment variable```yaml http: ofrep: auth_headers: X-API-KEY: "" ``````shell CONFIGCAT_HTTP_OFREP_AUTH_HEADERS='{"X-API-KEY":""}' ``` | - | Additional headers that must be on each request sent to the OFREP endpoints. If the request doesn't include the specified header, or the values are not matching, the Proxy will respond with a `401` HTTP status code. | ## SSE[​](#sse "Direct link to SSE") The SSE endpoint allows you to subscribe for feature flag value changes through [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) connections. ### Endpoints using SDK key[​](#endpoints-using-sdk-key-2 "Direct link to Endpoints using SDK key") The following endpoints are using SDK keys to determine which config / environment is the target of the desired action. The SDK key must be provided in the `sdkKey` field of the base64 encoded `data` route parameter. info These endpoints are only available from Proxy version [`v3.0.0`](https://github.com/configcat/configcat-proxy/releases/tag/v3.0.0). GETOPTIONS/sse/eval/k/{data} This endpoint subscribes to a single flag's changes. Whenever the watched flag's value changes, the Proxy sends the new value to each connected client. **Route parameters**: * `data`: The `base64` encoded input data for feature flag evaluation that must contain the SDK key, the feature flag's key, and a [User Object](https://configcat.com/docs/targeting/user-object.md). **Responses**: * 200: The SSE connection established successfully. * Response body: ```json { "value": , "variationId": "" } ``` 204: In response to an `OPTIONS` request. * 400: The `data`, or the `sdkKey` or `key` field of `data` is missing. * 404: The `sdkKey` is pointing to a non-existent SDK. **Example**: example.js ```js const rawData = { sdkKey: "#YOUR-SDK-KEY#", key: "isMyAwesomeFeatureEnabled", user: { // field types can only be `string`, `number`, or `string[]`. Identifier: "#UNIQUE-USER-IDENTIFIER#", Rating: 4.5, Roles: ["Role1","Role2"], // any other attribute } }; const data = btoa(JSON.stringify(rawData)); const evtSource = new EventSource("http://localhost:8050/sse/eval/k/" + data); evtSource.onmessage = (event) => { console.log(event.data); // {"value":,"variationId":""} }; ``` GETOPTIONS/sse/eval-all/k/{data} This endpoint subscribes to all feature flags' changes behind the given SDK key. When any of the watched flags' value change, the Proxy sends its new value to each connected client. **Route parameters**: * `data`: The `base64` encoded input data for feature flag evaluation that contains the SDK key and a [User Object](https://configcat.com/docs/targeting/user-object.md). **Responses**: * 200: The SSE connection established successfully. * Response body: ```json { "feature-flag-key-1": { "value": , "variationId": "" }, "feature-flag-key-2": { "value": , "variationId": "" } } ``` 204: In response to an `OPTIONS` request. * 400: The `sdkKey` field of `data` is missing. * 404: The `sdkKey` is pointing to a non-existent SDK. **Example**: example.js ```js const rawData = { sdkKey: "#YOUR-SDK-KEY#", user: { // field types can only be `string`, `number`, or `string[]`. Identifier: "#UNIQUE-USER-IDENTIFIER#", Rating: 4.5, Roles: ["Role1","Role2"], // any other attribute } }; const data = btoa(JSON.stringify(rawData)); const evtSource = new EventSource("http://localhost:8050/sse/eval-all/k/" + data); evtSource.onmessage = (event) => { console.log(event.data); // {"feature-flag-key":{"value":,"variationId":""}} }; ``` ### Endpoints using SDK identifier[​](#endpoints-using-sdk-identifier-2 "Direct link to Endpoints using SDK identifier") The following endpoints are using an SDK identifier to determine which config / environment is the target of the desired action. The SDK identifier must be provided in the `sdkId` route parameter. GETOPTIONS/sse/{sdkId}/eval/{data} This endpoint subscribes to a single flag's changes. Whenever the watched flag's value changes, the Proxy sends the new value to each connected client. **Route parameters**: * `sdkId`: The [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that uniquely identifies an SDK within the Proxy. * `data`: The `base64` encoded input data for feature flag evaluation that must contain the feature flag's key and a [User Object](https://configcat.com/docs/targeting/user-object.md). **Responses**: * 200: The SSE connection established successfully. * Response body: ```json { "value": , "variationId": "" } ``` 204: In response to an `OPTIONS` request. * 400: The `sdkId`, `data`, or the `key` attribute of `data` is missing. * 404: The `sdkId` is pointing to a non-existent SDK. **Example**: example.js ```js const rawData = { key: "isMyAwesomeFeatureEnabled", user: { // field types can only be `string`, `number`, or `string[]`. Identifier: "#UNIQUE-USER-IDENTIFIER#", Rating: 4.5, Roles: ["Role1","Role2"], // any other attribute } }; const data = btoa(JSON.stringify(rawData)); const evtSource = new EventSource("http://localhost:8050/sse/#SDK-IDENTIFIER#/eval/" + data); evtSource.onmessage = (event) => { console.log(event.data); // {"value":,"variationId":""} }; ``` GETOPTIONS/sse/{sdkId}/eval-all/{data} This endpoint subscribes to all feature flags' changes behind the given [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key). When any of the watched flags' value change, the Proxy sends its new value to each connected client. **Route parameters**: * `sdkId`: The [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that uniquely identifies an SDK within the Proxy. * `data`: **Optional**. The `base64` encoded input data for feature flag evaluation that contains a [User Object](https://configcat.com/docs/targeting/user-object.md). **Responses**: * 200: The SSE connection established successfully. * Response body: ```json { "feature-flag-key-1": { "value": , "variationId": "" }, "feature-flag-key-2": { "value": , "variationId": "" } } ``` 204: In response to an `OPTIONS` request. * 400: The `sdkId` is missing. * 404: The `sdkId` is pointing to a non-existent SDK. **Example**: example.js ```js const rawData = { user: { // field types can only be `string`, `number`, or `string[]`. Identifier: "#UNIQUE-USER-IDENTIFIER#", Rating: 4.5, Roles: ["Role1","Role2"], // any other attribute } }; const data = btoa(JSON.stringify(rawData)); const evtSource = new EventSource("http://localhost:8050/sse/#SDK-IDENTIFIER#/eval-all/" + data); evtSource.onmessage = (event) => { console.log(event.data); // {"feature-flag-key":{"value":,"variationId":""}} }; ``` ### Available Options[​](#available-options-3 "Direct link to Available Options") The following SSE related options are available: | Option | Default | Description | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | - YAML
- Environment variable```yaml http: sse: enabled: ``````shell CONFIGCAT_HTTP_SSE_ENABLED= ``` | `true` | Turns the hosting of the SSE endpoint on/off, This endpoint can be used to stream feature flag value changes. | | - YAML
- Environment variable```yaml http: sse: cors: enabled: ``````shell CONFIGCAT_HTTP_SSE_CORS_ENABLED= ``` | `true` | Turns the sending of CORS headers on/off. It can be used to restrict access to specific domains. By default, the Proxy allows each origin by setting the `Access-Control-Allow-Origin` response header to the request's origin. You can override this functionality by restricting the allowed origins with the `allowed_origins` or `allowed_origins_regex` options. | | - YAML
- Environment variable```yaml http: sse: cors: allowed_origins: - https://domain1.com - https://domain2.com ``````shell CONFIGCAT_HTTP_SSE_CORS_ALLOWED_ORIGINS='["https://domain1.com","https://domain2.com"]' ``` | - | List of allowed CORS origins. When it's set, the Proxy will include only that origin in the `Access-Control-Allow-Origin` response header which matches the request's `Origin`.
When there's no matching request origin and the `allowed_origins_regex` option is not set, the Proxy will set the `Access-Control-Allow-Origin` response header to the first item in the allowed origins list. | | - YAML
- Environment variable```yaml http: sse: cors: allowed_origins_regex: patterns: - https:\/\/.*domain1\.com - https:\/\/.*domain2\.com ``````shell CONFIGCAT_HTTP_SSE_CORS_ALLOWED_ORIGINS_REGEX_PATTERNS='["https:\\/\\/.*domain1\\.com","https:\\/\\/.*domain2\\.com"]' ``` | - | List of regex patterns used to match allowed CORS origins. When it's set, the Proxy will match the request's `Origin` with the given regex patterns. When there's a match, the `Access-Control-Allow-Origin` response header will be set to the matched origin.
When there's no matching request origin, the Proxy will set the `Access-Control-Allow-Origin` response header to the `if_no_match` field's value.
The `if_no_match` option is mandatory if this option is used.
When using the environment variable, the regex escape character must be doubled (`\\`) because it's parsed as a JSON list and `\` is also a JSON escape character. | | - YAML
- Environment variable```yaml http: sse: cors: allowed_origins_regex: if_no_match: https://domain1.com ``````shell CONFIGCAT_HTTP_SSE_CORS_ALLOWED_ORIGINS_REGEX_IF_NO_MATCH="https://domain1.com" ``` | - | Required when the previous `patterns` option is set. It's value is used in the `Access-Control-Allow-Origin` header when an incoming request's `Origin` doesn't match with any previously configured regex patterns. | | - YAML
- Environment variable```yaml http: sse: headers: Custom-Header-Name: "" ``````shell CONFIGCAT_HTTP_SSE_HEADERS='{"Custom-Header-Name":""}' ``` | - | Additional headers that must be sent back on each [SSE endpoint](#sse) response. | | - YAML
- Environment variable```yaml http: sse: log: level: "" ``````shell CONFIGCAT_HTTP_SSE_LOG_LEVEL="" ``` | `warn` | The verbosity of the SSE related logs.
Possible values: `error`, `warn`, `info` or `debug`. | ## Webhook[​](#webhook "Direct link to Webhook") Through the webhook endpoint, you can notify the Proxy about the availability of new feature flag evaluation data. Also, with the appropriate [SDK options](https://configcat.com/docs/advanced/proxy/proxy-overview.md#additional-options-for-underlying-sdks), the Proxy can [validate the signature](https://configcat.com/docs/advanced/notifications-webhooks.md#verifying-webhook-requests) of each incoming webhook request. info If you use the [automatic configuration with Proxy profiles](https://configcat.com/docs/advanced/proxy/proxy-overview.md#1-automatic-configuration-with-proxy-profiles), you don't have to set up individual webhooks manually. You can follow the documentation of webhook notifications for Proxy profiles [here](https://configcat.com/docs/advanced/proxy/proxy-overview.md#webhook-notification). GETPOST/hook/{sdkId} Notifies the Proxy that the SDK with the given [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) must refresh its *config JSON* to the latest version. **Route parameters**: * `sdkId`: The [SDK identifier](https://configcat.com/docs/advanced/proxy/proxy-overview.md#sdk-identifier--sdk-key) that uniquely identifies an SDK within the Proxy. **Responses**: * 200: The Proxy accepted the notification. * 400: The `sdkId` is missing or the [webhook signature validation](https://configcat.com/docs/advanced/notifications-webhooks.md#verifying-webhook-requests) failed. * 404: The `sdkId` is pointing to a non-existent SDK. ### ConfigCat Dashboard[​](#configcat-dashboard "Direct link to ConfigCat Dashboard") You can set up webhooks to invoke the Proxy on the [Webhooks page](https://app.configcat.com/product/webhooks) of the ConfigCat Dashboard. ![Webhook](/docs/assets/proxy/webhook.png) ### Available Options[​](#available-options-4 "Direct link to Available Options") The following webhook related options are available: | Option | Default | Description | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | - YAML
- Environment variable```yaml http: webhook: enabled: ``````shell CONFIGCAT_HTTP_WEBHOOK_ENABLED= ``` | `true` | Turns the hosting of the Webhook endpoint on/off. This endpoint can be used to notify the Proxy about the availability of new feature flag evaluation data. | | - YAML
- Environment variable```yaml http: webhook: auth: user: "" ``````shell CONFIGCAT_HTTP_WEBHOOK_AUTH_USER="" ``` | - | Basic authentication user. The basic authentication webhook header can be set on the [Webhooks page](https://app.configcat.com/product/webhooks) of the ConfigCat Dashboard. | | - YAML
- Environment variable```yaml http: webhook: auth: password: "" ``````shell CONFIGCAT_HTTP_WEBHOOK_AUTH_PASSWORD="" ``` | - | Basic authentication password. The basic authentication webhook header can be set on the [Webhooks page](https://app.configcat.com/product/webhooks) of the ConfigCat Dashboard. | | - YAML
- Environment variable```yaml http: webhook: auth_headers: X-API-KEY: "" ``````shell CONFIGCAT_HTTP_WEBHOOK_AUTH_HEADERS='{"X-API-KEY":""}' ``` | - | Additional headers that ConfigCat must send with each request to the Webhook endpoint. Webhook headers can be set on the [Webhooks page](https://app.configcat.com/product/webhooks) of the ConfigCat Dashboard. | --- # Source: https://configcat.com/docs/advanced/team-management/scim/identity-providers/entra-id.md # User Provisioning (SCIM) with Entra ID (Azure AD) Copy page ## Introduction[​](#introduction "Direct link to Introduction") Each Identity Provider requires specific information to configure a SCIM integration. The following guide will walk you through how you can connect ConfigCat with Entra ID via SCIM. ## 1. Create an Entra ID Enterprise Application[​](#1-create-an-entra-id-enterprise-application "Direct link to 1. Create an Entra ID Enterprise Application") info If you already configured your organization to use Entra ID as a SAML provider, you can use the existing Entra ID Enterprise application and skip to the [next step](#2-configure-provisioning-scim-for-the-azure-enterprise-application). * Log in to the [Azure Portal](https://portal.azure.com/), go to the `Entra ID` resource, select `Enterprise applications`, and click on `New application`. ![Entra ID enterprise applications](/docs/assets/scim/entra_id/new_application.png) * Click on `Create your own application`. ![Entra ID create own application](/docs/assets/scim/entra_id/create_application.png) * Enter a descriptive `App name`, select the `Integrate any other application you don't find in the gallery (Non-gallery)` option, then click `Create`. ![Entra ID app name](/docs/assets/scim/entra_id/app_name.png) The next step will guide you on how to setup Entra ID to synchronize your Identity Provider users and Identity Provider groups to ConfigCat. ## 2. Configure Provisioning (SCIM) for the Azure Enterprise Application[​](#2-configure-provisioning-scim-for-the-azure-enterprise-application "Direct link to 2. Configure Provisioning (SCIM) for the Azure Enterprise Application") * On the `Manage` section of the application, select `Provisioning`, then click on `New Configuration`. ![Entra ID new SCIM configuration](/docs/assets/scim/entra_id/new_config.png) * Gather the `SCIM URL` and the `Token` from the [Authentication & Provisioning](https://app.configcat.com/organization/authentication/) page in ConfigCat. ![SCIM URL and token](/docs/assets/scim/dashboard/token_generate_url.png) ![SCIM token](/docs/assets/scim/dashboard/token.png) * Add the `SCIM URL` as the `Tenant URL` and the `Token` as the `Secret token` on the New provisioning configuration page in Azure. Click on the `Create` button. ![Entra ID SCIM URL and token](/docs/assets/scim/entra_id/scim_meta.png) * Select the `Provisioning` menu and in the Mappings, configure the mapping for Users and Groups. ![Entra ID SCIM mappings](/docs/assets/scim/entra_id/mappings.png) * Mapping for Users: Configure only the following mappings and remove all other mappings if there are any. | Provisioning Attribute | Microsoft Entra ID Attribute | | ---------------------- | ------------------------------------------------------------ | | externalId | objectId | | userName | userPrincipalName | | displayName | displayName | | active | Switch(\[IsSoftDeleted], , "False", "True", "True", "False") | ![Entra ID SCIM User mappings](/docs/assets/scim/entra_id/user_mappings2.png) * Mapping for Groups: Configure only the following mappings and remove all other mappings if there are any. | Provisioning Attribute | Microsoft Entra ID Attribute | | ---------------------- | ---------------------------- | | externalId | objectId | | displayName | displayName | | members | members | ![Entra ID SCIM Group mappings](/docs/assets/scim/entra_id/group_mappings.png) ## 3. Assign Users/Groups to the Enterprise Application[​](#3-assign-usersgroups-to-the-enterprise-application "Direct link to 3. Assign Users/Groups to the Enterprise Application") To start user provisioning with Entra ID, you need to assign groups to the Enterprise application. * Select `Users and groups` on the `Manage` section of the menu, and click `Add user/group`. Then, you can select the groups you want to assign. ![Entra ID users and groups](/docs/assets/scim/entra_id/add_user.png) caution In ConfigCat, you can assign permissions only to groups that are synchronized from your Identity Provider, therefore it's important to select groups for synchronization rather than individual users. ## 4. Start provisioning[​](#4-start-provisioning "Direct link to 4. Start provisioning") * Go to the `Overview` page of the provisioning configuration and click on `Start provisioning`. ![Entra ID start provisioning](/docs/assets/scim/entra_id/start_provisioning.png) * Wait until the first provisioning is finished, and you should see each synced group and user on ConfigCat's [Authentication & Provisioning](https://app.configcat.com/organization/authentication/) page. ## 5. Next Steps[​](#5-next-steps "Direct link to 5. Next Steps") * Continue with [assigning ConfigCat permissions to the synced groups](https://configcat.com/docs/advanced/team-management/scim/scim-overview.md#groups). --- # Source: https://configcat.com/docs/api/reference/environments.md # Environments Copy page With these endpoints you can update existing Environments or add new ones into your selected [Product](https://configcat.com/docs/api/reference/products.md). [Here](https://configcat.com/docs/main-concepts.md#environment) you can read more about the concept of Environments. ## [📄️ List Environments](https://configcat.com/docs/api/reference/get-environments.md) [This endpoint returns the list of the Environments that belongs to the given Product identified by the](https://configcat.com/docs/api/reference/get-environments.md) ## [📄️ Create Environment](https://configcat.com/docs/api/reference/create-environment.md) [This endpoint creates a new Environment in a specified Product](https://configcat.com/docs/api/reference/create-environment.md) ## [📄️ Get Environment](https://configcat.com/docs/api/reference/get-environment.md) [This endpoint returns the metadata of an Environment](https://configcat.com/docs/api/reference/get-environment.md) ## [📄️ Update Environment](https://configcat.com/docs/api/reference/update-environment.md) [This endpoint updates an Environment identified by the \`environmentId\` parameter.](https://configcat.com/docs/api/reference/update-environment.md) ## [📄️ Delete Environment](https://configcat.com/docs/api/reference/delete-environment.md) [This endpoint removes an Environment identified by the \`environmentId\` parameter.](https://configcat.com/docs/api/reference/delete-environment.md) --- # Source: https://configcat.com/docs/faq.md # FAQ - Frequently Asked Questions Copy page A collection of frequently asked questions. ## General[​](#general "Direct link to General") ### Learning how ConfigCat can work with your product[​](#learning-how-configcat-can-work-with-your-product "Direct link to Learning how ConfigCat can work with your product") You can book a free demo session [here](https://calendly.com/configcat/demo), where we'll show you how to use ConfigCat and answer any questions you have. ## Billing, Payments & Subscriptions[​](#billing-payments--subscriptions "Direct link to Billing, Payments & Subscriptions") ### What if I exceed the [config JSON download](https://configcat.com/docs/requests.md) limit of my plan?[​](#what-if-i-exceed-the-config-json-download-limit-of-my-plan "Direct link to what-if-i-exceed-the-config-json-download-limit-of-my-plan") Don't worry, we will keep serving your data and feature flags. Someone from our team will contact you to discuss your options. You can always check your Usage & Quota [here](https://app.configcat.com/organization/usage). ### Where can I find and download my invoices?[​](#where-can-i-find-and-download-my-invoices "Direct link to Where can I find and download my invoices?") All the invoices we've issued are available for download from the [Billing & Invoices page](https://app.configcat.com/organization/billing). You need to have the [Billing Manager](https://configcat.com/docs/organization.md#billing-manager-role) role to access the Billing & Invoices page. ### Is it possible to pay via wire transfer?[​](#is-it-possible-to-pay-via-wire-transfer "Direct link to Is it possible to pay via wire transfer?") Using a credit card via the ConfigCat Dashboard is the preferred way of payment, but a wire transfer is also an option for larger subscription plans. [Contact us](https://configcat.com/support/) directly for more details. ### How do I upgrade / downgrade my billing plan?[​](#how-do-i-upgrade--downgrade-my-billing-plan "Direct link to How do I upgrade / downgrade my billing plan?") You can change your billing plan on the [Plans](https://app.configcat.com/organization/plans) page. You need to have the [Billing Manager](https://configcat.com/docs/organization.md#billing-manager-role) role to access the Plans page. ### Can I get a discounted rate?[​](#can-i-get-a-discounted-rate "Direct link to Can I get a discounted rate?") Discounts are available through our partnership program. [Contact us](https://configcat.com/support/) directly for more information. ### Can I change the email address associated with my account?[​](#can-i-change-the-email-address-associated-with-my-account "Direct link to Can I change the email address associated with my account?") Currently, there's no direct way to change the email address of an account. However, you can: 1. Invite the new email to join your ConfigCat organization; this will create a fresh ConfigCat account. 2. Grant all the necessary permissions to the new account. 3. Proceed with deleting your old account from [here](https://app.configcat.com/my-account). If you don't have the required permissions, contact your organization admin or a team member who has "Team members and permission groups" permissions. Please note: Switching emails means you'll lose preferences from your old account, such as permissions, API keys, and Zombie flag settings. Transfer essential settings first. ### How do I change the billing email address where I receive my invoices?[​](#how-do-i-change-the-billing-email-address-where-i-receive-my-invoices "Direct link to How do I change the billing email address where I receive my invoices?") Go to the [Billing & Invoices page](https://app.configcat.com/organization/billing) and click the `Update billing details` link. You need to have the [Billing Manager](https://configcat.com/docs/organization.md#billing-manager-role) role to access the Billing & Invoices page. ### How do I change my payment method or billing information?[​](#how-do-i-change-my-payment-method-or-billing-information "Direct link to How do I change my payment method or billing information?") Go to the [Billing & Invoices page.](https://app.configcat.com/organization/billing) and click the `Update billing details` link. You need to have a [Billing Manager](https://configcat.com/docs/organization.md#billing-manager-role) role to access the Billing & Invoices page. ### The ChargeBee payment gets stuck | Throws an error[​](#the-chargebee-payment-gets-stuck--throws-an-error "Direct link to The ChargeBee payment gets stuck | Throws an error") If you're using Firefox, try switching to a Chromium-based browser that has extensions turned off. If this doesn't work, [contact us](https://configcat.com/support/) for help. ### How do I cancel my account?[​](#how-do-i-cancel-my-account "Direct link to How do I cancel my account?") Go to the [Plans](https://app.configcat.com/organization/plans) page and click the `Switch Plan` button under the Free plan. You need to have a [Billing Manager](https://configcat.com/docs/organization.md#billing-manager-role) role to access the Plans page. ### How do I change my currency?[​](#how-do-i-change-my-currency "Direct link to How do I change my currency?") Go to the [Plans](https://app.configcat.com/organization/plans) page and use the currency toggle to switch between USD and EUR. You need to have a [Billing Manager](https://configcat.com/docs/organization.md#billing-manager-role) role to access the Plans page. ## Security[​](#security "Direct link to Security") ### Are you ISO certified?[​](#are-you-iso-certified "Direct link to Are you ISO certified?") Yes, ConfigCat complies with the ISO/IEC 27001:2022 standard for Information Security Management Systems (ISMS). Click [here](https://configcat.com/iso/) to learn more. ### I'm setting up my firewall, which addresses should I whitelist?[​](#im-setting-up-my-firewall-which-addresses-should-i-whitelist "Direct link to I'm setting up my firewall, which addresses should I whitelist?") If possible, you can allow the whole "configcat.com" domain. Alternatively, you can manually whitelist the following addresses: * Global CDN: `https://cdn-global.configcat.com` * EU CDN: `https://cdn-eu.configcat.com` * The Public Management API: * The Dashboard URL: ### I can't log in to ConfigCat using two-factor authentication (2FA).[​](#i-cant-log-in-to-configcat-using-two-factor-authentication-2fa "Direct link to I can't log in to ConfigCat using two-factor authentication (2FA).") *Solution 1:* There might be an authenticator app on your phone that you can use to log in to ConfigCat. *Solution 2:* Use your recovery codes that you received when you first set your 2FA up. *Solution 3:* Contact your `Organization Admin`, and ask them to disable 2FA for your account until you set it up again. `Organization Admins` can disable 2FA on the [Members & Roles](https://app.configcat.com/organization/members) page. After you re-enable the 2FA, new recovery codes will also be (re)generated. It might be a good idea to save them to avoid such issues in the future. ### The Audit log doesn't show old operations[​](#the-audit-log-doesnt-show-old-operations "Direct link to The Audit log doesn't show old operations") The Free plan includes a 7-day retention period. The Pro and Smart plans offer a 35-day retention, while the Enterprise and Dedicated plans provide a 2-year retention. ### Is there a way to allow a group access to only one config rather than all of them?[​](#is-there-a-way-to-allow-a-group-access-to-only-one-config-rather-than-all-of-them "Direct link to Is there a way to allow a group access to only one config rather than all of them?") You can't set config-level access in one product. Instead, split your configs into multiple products with the appropriate permission settings. ### I cannot access my account using Google sign-in.[​](#i-cannot-access-my-account-using-google-sign-in "Direct link to I cannot access my account using Google sign-in.") Browser extensions may interfere. Please disable all browser extensions and try again. ## Privacy[​](#privacy "Direct link to Privacy") ### How can I be sure that my data is safe?[​](#how-can-i-be-sure-that-my-data-is-safe "Direct link to How can I be sure that my data is safe?") ConfigCat SDKs evaluate feature flags locally, in your application. They send no user data to the ConfigCat servers. See our architecture explained [here](https://configcat.com/architecture/). ### Can we sign a data processing agreement with you?[​](#can-we-sign-a-data-processing-agreement-with-you "Direct link to Can we sign a data processing agreement with you?") Yes. You can review our DPA through our [Trust Center](https://configcat.com/trust-center/) page, or [contact us](https://configcat.com/support/?prefilled=dpa-sign-request) and we'll send it to you for signing. ### Does ConfigCat collect browser data when serving feature flag data download requests?[​](#does-configcat-collect-browser-data-when-serving-feature-flag-data-download-requests "Direct link to Does ConfigCat collect browser data when serving feature flag data download requests?") No. ConfigCat doesn't collect, store or process any user or browser fingerprinting data. The data flow is one directional - the SDKs are only downloading the config JSON files and the feature flag evaluation happens in the SDKs. ConfigCat doesn't collect any information about the customer's users. ### Is data hosted only within the EU?[​](#is-data-hosted-only-within-the-eu "Direct link to Is data hosted only within the EU?") Our main infrastructure and database is in the EU, but CDN servers are located both in the EU and globally. You can set where you want us to keep your data, so its always within reach for your needs. You can read more [here](https://configcat.com/docs/advanced/data-governance.md). ### Is it possible to export the feature flags?[​](#is-it-possible-to-export-the-feature-flags "Direct link to Is it possible to export the feature flags?") Yes! You can export and download your current product as a standard JSON file anytime you want. The export will include: * All feature flags and settings together with their values, Targeting Rules, Percentage Options, segments, tags * All configs * All environments * All tags * All segments ### How long does ConfigCat keep my data?[​](#how-long-does-configcat-keep-my-data "Direct link to How long does ConfigCat keep my data?") We keep organization data as long as we see activity in that organization. After several months of inactivity, we send you a series of email notifications about or plans to delete your organization and all associated data. We consider an organization inactive if it meets all of the following criteria: * no audit log events are generated in the organization, * no valid calls are made to the organization via the Public Management API, * config JSONs aren't downloaded from the ConfigCat CDN, * the organization does not have an active paid subscription. ## A/B Testing & Targeting[​](#ab-testing--targeting "Direct link to A/B Testing & Targeting") ### Can I use AND operators in my Targeting Rules?[​](#can-i-use-and-operators-in-my-targeting-rules "Direct link to Can I use AND operators in my Targeting Rules?") Yes, you can use AND operators in your Targeting Rules. (Only available in [Config V2](https://configcat.com/docs/advanced/config-v2.md) and later) ### Are Percentage Options sticky?[​](#are-percentage-options-sticky "Direct link to Are Percentage Options sticky?") Yes. The percentage-based targeting is sticky by design and consistent across all SDKs. Also, consider the following: * All SDKs evaluate the rules in the exact same way. (10% is the same 10% in all SDKs) * The percentage rules are sticky by feature flag. (10% is a different 10% for each feature flag) More on [stickiness](https://configcat.com/docs/targeting/percentage-options.md#stickiness) and [consistency](https://configcat.com/docs/targeting/percentage-options.md#consistency) ### How to use Targeting Rules based on sensitive data?[​](#how-to-use-targeting-rules-based-on-sensitive-data "Direct link to How to use Targeting Rules based on sensitive data?") If you want to use Targeting Rules based on email address, phone number, or other sensitive data, you can use the [Confidential text comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators). ## Technical Debt[​](#technical-debt "Direct link to Technical Debt") ### What are Zombie (Stale) Flags?[​](#what-are-zombie-stale-flags "Direct link to What are Zombie (Stale) Flags?") ![Zombie cat](/docs/assets/faq/zombie.svg) Zombie (Stale) flags are feature flags that are not changed in the last (configurable) number of days. Most of the time if a feature flag isn't changed for a long time it means it is time to be removed from your source code and from the [ConfigCat Dashboard](https://app.configcat.com/) as well to avoid technical debt. ### What is the Zombie (Stale) Flags Report?[​](#what-is-the-zombie-stale-flags-report "Direct link to What is the Zombie (Stale) Flags Report?") The [Zombie (Stale) Flags Report](https://app.configcat.com/my-account/zombie-flags-report) is a list of all feature flags that are not changed in the last (configurable) number of days. You can use this report to identify and remove stale feature flags from your source code. This report is weekly emailed to you. You can set your [email preferences here](https://app.configcat.com/my-account/zombie-flags-report). ### I am not getting the Zombie Feature Flag email report. What am I doing wrong?[​](#i-am-not-getting-the-zombie-feature-flag-email-report-what-am-i-doing-wrong "Direct link to I am not getting the Zombie Feature Flag email report. What am I doing wrong?") You can change the frequency, criteria and scope of the Zombie Feature Flag report on the Dashboard. **Note:** Please be aware that feature flags are only treated as zombie flags if they haven't been modified (with save & publish) in the past given timeframe. It currently doesn't have any connection with your real usage in your code. ### How to avoid technical debt caused by feature flags?[​](#how-to-avoid-technical-debt-caused-by-feature-flags "Direct link to How to avoid technical debt caused by feature flags?") The [ConfigCat CLI](https://configcat.com/docs/advanced/code-references/overview.md) can scan your code, upload code references to the [ConfigCat Dashboard](https://app.configcat.com/) and notify you about stale feature flags. ![Code references screenshot](/docs/assets/cli/code-refs.png) ### Is there a way to compare flag statuses between two or more environments?[​](#is-there-a-way-to-compare-flag-statuses-between-two-or-more-environments "Direct link to Is there a way to compare flag statuses between two or more environments?") Yes, you can see the state of all your Feature Flags across all your environments in our simplified [overview](https://app.configcat.com/overview). ## Joining an Organization[​](#joining-an-organization "Direct link to Joining an Organization") ### Is there an expiration date for sent invitations?[​](#is-there-an-expiration-date-for-sent-invitations "Direct link to Is there an expiration date for sent invitations?") Invitations are valid for 14 days by default, but you can re-send them anytime to extend their expiration. ### I can't see the organization that I just joined[​](#i-cant-see-the-organization-that-i-just-joined "Direct link to I can't see the organization that I just joined") If you created a new account before joining an organization via an invite (like the one sent by your company via email), then it is likely that a duplicate organization is created for you by ConfigCat. Once you find the proper organization where you are supposed to be, we recommend deleting the duplicate from [here](https://app.configcat.com/organization/preferences), but please make sure that you don't accidentally delete the one that you want to keep. ## Technical Ones[​](#technical-ones "Direct link to Technical Ones") ### Is it possible to rename a product or config?[​](#is-it-possible-to-rename-a-product-or-config "Direct link to Is it possible to rename a product or config?") Yes, you can rename almost everything within ConfigCat. Organizations, products, configs, environments, tags and feature flags can all be renamed. What you can't rename is feature flag keys, as that could cause a tsunami of reference error messages in your applications. ### Can I change my Feature Flag based on a date?[​](#can-i-change-my-feature-flag-based-on-a-date "Direct link to Can I change my Feature Flag based on a date?") You can pass the current date as a [custom User Object attribute](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#comparison-attribute) to the ConfigCat SDK attribute when evaluating the feature flag, and you can use that attribute with our [Date and Time comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#date-and-time-comparators) in your targeting rules to target specific dates. ### Does ConfigCat guarantee percentage distribution?[​](#does-configcat-guarantee-percentage-distribution "Direct link to Does ConfigCat guarantee percentage distribution?") ConfigCat guarantees percentage distribution across all SDKs, and it guarantees that each user will receive the same experience every time. ### Is it possible to set up A/B/C test (33%/33%/33%) distribution with ConfigCat?[​](#is-it-possible-to-set-up-abc-test-333333-distribution-with-configcat "Direct link to Is it possible to set up A/B/C test (33%/33%/33%) distribution with ConfigCat?") Yes, it is possible. All you have to do is to create a text setting and apply the percentage rules. With a normal feature flag you have only two options - true or false, but with a text setting you can apply as many A/B/n options as you want with the percentages. ### Is there a way to create feature flags via the API?[​](#is-there-a-way-to-create-feature-flags-via-the-api "Direct link to Is there a way to create feature flags via the API?") Yes there is. We have a public management API at . ### How to resolve Domain verification issues?[​](#how-to-resolve-domain-verification-issues "Direct link to How to resolve Domain verification issues?") **Txt record-based verification** **Solution 1:** Check the 'Host' field in your DNS settings. One common cause of verification failure is an incorrectly set 'Host' field. Make sure that it is set to '@' or left empty. To check this setting, you will need to log into your domain provider's management console. **Solution 2:** After you've added the TXT record to your DNS settings, it may take some time for the changes to propagate through the DNS system. If you have recently added or updated the TXT record, it's possible that the verification hasn't been completed due to DNS caching. Sometimes you even need to wait a few hours before trying to verify the domain again. **File-Based verification** If you're having trouble verifying your domain with the file-based verification method, make sure you've uploaded the file to the proper directory, and you can download it from under your domain. --- # Source: https://configcat.com/docs/targeting/feature-flag-evaluation.md # Feature Flag Evaluation Copy page This document offers an in-depth explanation of how the SDK determines the value of a feature flag when executing the `GetValue` function. Understanding this process requires prior knowledge of [targeting concepts](https://configcat.com/docs/targeting/targeting-overview.md). The feature flag's value is determined by: * The feature flag's rules defined on the Dashboard, * The [User Object](https://configcat.com/docs/targeting/user-object.md) provided to the `GetValue` function, and * The [default value](https://configcat.com/docs/targeting/targeting-overview.md#default-value) passed to the `GetValue` function. The feature flag's value always comes from exactly one rule, following this algorithm: 1. **Evaluation of Targeting Rules:** If Targeting Rules are present, the SDK evaluates them one by one, from top to bottom. It checks if all the conditions in the rule's IF part are met (i.e. all the conditions evaluate to true). * If the conditions are met, the THEN part determines the value to return. However, if the THEN part contains Percentage Options but the [Percentage Evaluation Attribute](https://configcat.com/docs/targeting/percentage-options.md#percentage-evaluation-attribute) is missing from the User Object, the SDK will skip the Targeting Rule and continue with the next rule - even though the Targeting Rule's conditions are met. * If the conditions aren't met, the SDK moves to the next Targeting Rule, or to step 2 (below) if there are no more Targeting Rules. 2. **Evaluation of Percentage Options:** If a Percentage Options rule exists, the SDK executes the [Evaluation of Percentage Options](#evaluation-of-percentage-options) algorithm to determine which Percentage Option applies to the user and returns the value associated with that option. If the [Percentage Evaluation Attribute](https://configcat.com/docs/targeting/percentage-options.md#percentage-evaluation-attribute) is missing from the User Object, the SDK skips to step 3 (below). 3. **Returning simple value:** At this stage, the only remaining "rule" is the simple value specified at the end of the feature flag, which the SDK then returns. In the event of an unexpected error during evaluation, the SDK returns the [default value](https://configcat.com/docs/targeting/targeting-overview.md#default-value) passed to the `GetValue` function. ## Evaluation of a Targeting Rule[​](#evaluation-of-a-targeting-rule "Direct link to Evaluation of a Targeting Rule") The SDK evaluates the conditions in the rule's IF part one by one, from top to bottom. The result of a condition can be one of the following: `true`, `false` or `cannot evaluate`. The result `cannot evaluate` occurs when the necessary user attribute is missing, invalid or incorrectly formatted (the SDK logs these issues as warnings). A Targeting Rule matches only when all its conditions evaluate to `true`. In any other cases, it doesn't match. ### Evaluation of a User Condition[​](#evaluation-of-a-user-condition "Direct link to Evaluation of a User Condition") The SDK looks up the comparison attribute (the user attribute referenced by the condition) in the [User Object](https://configcat.com/docs/targeting/user-object.md). It compares the attribute value to the comparison value that is set on the Dashboard. The comparison is done according to the selected comparator, resulting in a `true` or `false` value. This will be the result of the condition. The result of the condition will be `cannot evaluate` in case the comparison attribute is missing (`null`, `undefined`, `""`) or invalid (not of the type expected by the comparator or not formatted properly). In such cases, the Targeting Rule containing the condition will be skipped, and the evaluation will continue with the next rule. ### Evaluation of a Flag Condition[​](#evaluation-of-a-flag-condition "Direct link to Evaluation of a Flag Condition") Using the same User Object used to evaluate the dependent flag, the SDK evaluates the prerequisite flag (the feature flag referenced by the condition). Then, the result is checked against the comparator. In case the prerequisite flag is not a boolean setting, the result is compared to the comparison value that is set on the Dashboard. The comparison results in a `true` or `false` value. This will be the result of the condition. In case the prerequisite flag is missing or there is a type mismatch between the return value and the comparison value, the evaluation process stops, and the SDK will return the [default value](https://configcat.com/docs/targeting/targeting-overview.md#default-value). (Though this can happen only when using the [flag overrides](https://configcat.com/docs/sdk-reference/js/overview.md#flag-overrides) feature with invalid data.) ### Evaluation of a Segment Condition[​](#evaluation-of-a-segment-condition "Direct link to Evaluation of a Segment Condition") The SDK looks up the segment referenced by the condition. Then evaluates the condition described by the segment similarly to [User Conditions](https://configcat.com/docs/targeting/targeting-rule/user-condition.md). Finally, the result is checked against the comparator: * For **IS IN SEGMENT**, the result of the Segment Condition will be the same as the result of the segment itself. * For **IS NOT IN SEGMENT**, the result will be negated (i.e. it will be the opposite of the result of the segment). If the segment evaluates to `cannot evaluate`, so does the Segment Condition. The evaluation process stops if the referenced segment is missing, and the SDK will return the [default value](https://configcat.com/docs/targeting/targeting-overview.md#default-value). (Though this can happen only when using the [flag overrides](https://configcat.com/docs/sdk-reference/js/overview.md#flag-overrides) feature with invalid data.) ## Evaluation of Percentage Options[​](#evaluation-of-percentage-options "Direct link to Evaluation of Percentage Options") [Percentage Options](https://configcat.com/docs/targeting/percentage-options.md) are designed to be *consistent* and *sticky* across all SDKs, which means that users with the same attributes fall in the same group and get the same feature flag value across the supported platforms as long as the percentage split is the same. The SDK looks up the [Percentage Evaluation Attribute](https://configcat.com/docs/targeting/percentage-options.md#percentage-evaluation-attribute) in the [User Object](https://configcat.com/docs/targeting/user-object.md), then: * The SDK creates a hash from the combination of the specific feature flag's key and the Percentage Evaluation Attribute's value (by default, it is the user identifier). * The hashing algorithm assigns the user a number between 0 and 99. * The assigned number determines which group the user falls into, i.e. which Percentage Option applies to the user. The fact that the above algorithm is implemented across all SDKs guarantees [stickiness](https://configcat.com/docs/targeting/percentage-options.md#stickiness), [consistency](https://configcat.com/docs/targeting/percentage-options.md#consistency) and [randomness](https://configcat.com/docs/targeting/percentage-options.md#randomness). info The evaluation process is entirely implemented within the SDKs, meaning your users' sensitive data never leaves your system. The data flow is one-way – from ConfigCat CDN servers to your SDKs – and ConfigCat does not receive or store any attributes of the [User Object](https://configcat.com/docs/targeting/user-object.md) passed to the SDKs. This design prioritizes the privacy and security of user data. ### Example scenarios for Percentage Options[​](#example-scenarios-for-percentage-options "Direct link to Example scenarios for Percentage Options") The following scenarios show how Percentage Options enable controlled and gradual rollouts of features. Let's imagine the following setup: * you have two users: Jane and Joe, * you have two features flags: **isTwitterSharingEnabled** and **isFacebookSharingEnabled**, * the feature flags use percentage-based targeting, * the Percentage Evaluation Attribute is the user identifier (which is simply the users' name in this example). First, the users are assigned a number between 0 and 99 based on the hash of the feature flag's key and their identifier. According to the Percentage Options specified on the Dashboard, this number determines which group they are assigned to, i.e. whether or not the feature is enabled for them. Let's assume the hash algorithm produces the following numbers: | | isTwitterSharingEnabled | isFacebookSharingEnabled | | ---- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------- | | Jane | `hash('isTwitterSharingEnabled' + 'Jane') mod 100`
results in **8** | `hash('isFacebookSharingEnabled' + 'Jane') mod 100`
results in **64** | | Joe | `hash('isTwitterSharingEnabled' + 'Joe') mod 100`
results in **32** | `hash(isFacebookSharingEnabled' + 'Joe') mod 100`
results in **12** | 1\. **Initial Setup: 0% ON / 100% OFF** | | isTwitterSharingEnabled
0% ON / 100% OFF | isFacebookSharingEnabled
0% ON / 100% OFF | | ---- | --------------------------------------------- | ---------------------------------------------- | | Jane | 8 >= 0
→ **OFF** | 64 >= 0
→ **OFF** | | Joe | 32 >= 0
→ **OFF** | 12 >= 0
→ **OFF** | 2\. **Adjustment to 10% ON / 90% OFF** In this case both feature flags are enabled for only 10% of users. | | isTwitterSharingEnabled
10% ON / 90% OFF | isFacebookSharingEnabled
10% ON / 90% OFF | | ---- | --------------------------------------------- | ---------------------------------------------- | | Jane | 8 < 10
→ **ON** | 64 >= 10
→ **OFF** | | Joe | 32 >= 10
→ **OFF** | 12 >= 10
→ **OFF** | info The **isTwitterSharingEnabled** feature flag is enabled only for Jane because Joe's user identifier places him in a different group. However, **isFacebookSharingEnabled** is disabled for both of them even though both feature flags are set to 10% ON / 90% OFF. This happens because the feature flag key is also involved in computing the hash. 3\. **Increasing *isTwitterSharingEnabled* to 40% ON / 60% OFF** | | isTwitterSharingEnabled
40% ON / 60% OFF | isFacebookSharingEnabled
10% ON / 90% OFF | | ---- | --------------------------------------------- | ---------------------------------------------- | | Jane | 8 < 40
→ **ON** | 64 >= 10
→ **OFF** | | Joe | 32 < 40
→ **ON** | 12 >= 10
→ **OFF** | 4\. **Rolling Back to a Safer 10% ON / 90% OFF** Same setup as in Step 2. There are cases when you want to roll back a feature flag to a safer state. In this case, you can change the Percentage Options to 10% ON / 90% OFF again. The sticky nature of percentage-based targeting ensures that the same userbase is served **ON** as in Step 2, not another random 10% of users. | | isTwitterSharingEnabled
10% ON / 90% OFF | isFacebookSharingEnabled
10% ON / 90% OFF | | ---- | --------------------------------------------- | ---------------------------------------------- | | Jane | 8 < 10
→ **ON** | 64 >= 10
→ **OFF** | | Joe | 32 >= 10
→ **OFF** | 12 >= 10
→ **OFF** | 5\. **Final Step: Moving to 100% ON / 0% OFF** After testing the feature flags, you can safely move them to 100% ON. This enables the features for all users. | | isTwitterSharingEnabled
100% ON / 0% OFF | isFacebookSharingEnabled
100% ON / 0% OFF | | ---- | --------------------------------------------- | ---------------------------------------------- | | Jane | 8 < 100
→ **ON** | 64 < 100
→ **ON** | | Joe | 32 < 100
→ **ON** | 12 < 100
→ **ON** | --- # Source: https://configcat.com/docs/api/reference/feature-flag-setting-values-using-sdk-key-v-2.md # Feature Flag & Setting values using SDK Key V2 Copy page *These endpoints are exclusive for [**Config V2**](https://configcat.com/docs/advanced/config-v2.md) Feature Flags.*
*They can only be used on a Config that has `evaluationVersion` set to `v2`.*

With these endpoints you can control how your existing Feature Flags and Settings should serve their values. You can turn Feature Flags on or off, update Setting values and change Targeting Rules. These endpoints are determining the Environment and Config by the [SDK key](https://app.configcat.com/sdkkey) passed in the `X-CONFIGCAT-SDKKEY` request header. To identify the desired Feature Flag or Setting to change, you can use either its `settingId` or `key` attribute. You can get those attributes from the [Feature Flag & Setting](https://configcat.com/docs/api/reference/feature-flags-settings.md) endpoints. ## [📄️ Get value](https://configcat.com/docs/api/reference/get-setting-value-by-sdkkey-v-2.md) [This endpoint returns the value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/get-setting-value-by-sdkkey-v-2.md) ## [📄️ Replace value](https://configcat.com/docs/api/reference/replace-setting-value-by-sdkkey-v-2.md) [This endpoint replaces the value and the Targeting Rules of a Feature Flag or Setting](https://configcat.com/docs/api/reference/replace-setting-value-by-sdkkey-v-2.md) ## [📄️ Update value](https://configcat.com/docs/api/reference/update-setting-value-by-sdkkey-v-2.md) [This endpoint updates the value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/update-setting-value-by-sdkkey-v-2.md) --- # Source: https://configcat.com/docs/api/reference/feature-flag-setting-values-using-sdk-key.md # Feature Flag & Setting values using SDK Key Copy page With these endpoints you can control how your existing Feature Flags and Settings should serve their values. You can turn Feature Flags on or off, update Setting values and also add, remove or change the order of Percentage and Targeting Rules. These endpoints are determining the Environment and Config by the [SDK key](https://app.configcat.com/sdkkey) passed in the `X-CONFIGCAT-SDKKEY` request header. To identify the desired Feature Flag or Setting to change, you can use either its `settingId` or `key` attribute. You can get those attributes from the [Feature Flag & Setting](https://configcat.com/docs/api/reference/feature-flags-settings.md) endpoints. ## [📄️ Get value](https://configcat.com/docs/api/reference/get-setting-value-by-sdkkey.md) [This endpoint returns the value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/get-setting-value-by-sdkkey.md) ## [📄️ Replace value](https://configcat.com/docs/api/reference/replace-setting-value-by-sdkkey.md) [This endpoint replaces the value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/replace-setting-value-by-sdkkey.md) ## [📄️ Update value](https://configcat.com/docs/api/reference/update-setting-value-by-sdkkey.md) [This endpoint updates the value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/update-setting-value-by-sdkkey.md) --- # Source: https://configcat.com/docs/api/reference/feature-flag-setting-values-v-2.md # Feature Flag & Setting values V2 Copy page *These endpoints are exclusive for [**Config V2**](https://configcat.com/docs/advanced/config-v2.md) Feature Flags.*
*They can only be used on a Config that has `evaluationVersion` set to `v2`.*

With these endpoints you can control how your existing Feature Flags and Settings should serve their values. You can turn Feature Flags on or off, update Setting values and change Targeting Rules. To determine which Feature Flag or Setting you want to work with you have to pass its `settingId`. It can be obtained from the [Feature Flag & Setting](https://configcat.com/docs/api/reference/feature-flags-settings.md) endpoints. You also have to specify in which Environment you want to change the served value configuration by its `environmentId` which can be obtained from the [List Environments](https://configcat.com/docs/api/reference/get-environments.md) endpoint. ## [📄️ Get value](https://configcat.com/docs/api/reference/get-setting-value-v-2.md) [This endpoint returns the value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/get-setting-value-v-2.md) ## [📄️ Replace value](https://configcat.com/docs/api/reference/replace-setting-value-v-2.md) [This endpoint replaces the value and the Targeting Rules of a Feature Flag or Setting](https://configcat.com/docs/api/reference/replace-setting-value-v-2.md) ## [📄️ Update value](https://configcat.com/docs/api/reference/update-setting-value-v-2.md) [This endpoint updates the value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/update-setting-value-v-2.md) ## [📄️ Get values](https://configcat.com/docs/api/reference/get-setting-values-v-2.md) [This endpoint returns all Feature Flag and Setting values of a Config identified by the \`configId\` parameter](https://configcat.com/docs/api/reference/get-setting-values-v-2.md) ## [📄️ Post values](https://configcat.com/docs/api/reference/post-setting-values-v-2.md) [This endpoint batch updates the Feature Flags and Settings of a Config identified by the \`configId\` parameter](https://configcat.com/docs/api/reference/post-setting-values-v-2.md) --- # Source: https://configcat.com/docs/api/reference/feature-flag-setting-values.md # Feature Flag & Setting values Copy page With these endpoints you can control how your existing Feature Flags and Settings should serve their values. You can turn Feature Flags on or off, update Setting values and also add, remove or reorder Percentage and Targeting Rules. To determine which Feature Flag or Setting you want to work with you have to pass its `settingId`. It can be obtained from the [Feature Flag & Setting](https://configcat.com/docs/api/reference/feature-flags-settings.md) endpoints. You also have to specify in which Environment you want to change the served value configuration by its `environmentId` which can be obtained from the [List Environments](https://configcat.com/docs/api/reference/get-environments.md) endpoint. ## [📄️ Get value](https://configcat.com/docs/api/reference/get-setting-value.md) [This endpoint returns the value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/get-setting-value.md) ## [📄️ Replace value](https://configcat.com/docs/api/reference/replace-setting-value.md) [This endpoint replaces the whole value of a Feature Flag or Setting in a specified Environment.](https://configcat.com/docs/api/reference/replace-setting-value.md) ## [📄️ Update value](https://configcat.com/docs/api/reference/update-setting-value.md) [This endpoint updates the value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/update-setting-value.md) ## [📄️ Get values](https://configcat.com/docs/api/reference/get-setting-values.md) [This endpoint returns the value of a specified Config's Feature Flags or Settings identified by the \`configId\` parameter](https://configcat.com/docs/api/reference/get-setting-values.md) ## [📄️ Post values](https://configcat.com/docs/api/reference/post-setting-values.md) [This endpoint replaces the values of a specified Config's Feature Flags or Settings identified by the \`configId\` parameter](https://configcat.com/docs/api/reference/post-setting-values.md) --- # Source: https://configcat.com/docs/api/reference/feature-flags-settings.md # Feature Flags & Settings Copy page With these endpoints you can manage your Feature Flags or Settings within a Config. However you can't use them for manipulating the values of your Feature Flags and Settings, to do that please visit the [Feature Flag & Setting values using SDK Key](https://configcat.com/docs/api/reference/feature-flag-setting-values-using-sdk-key.md) and [Feature Flag & Setting values](https://configcat.com/docs/api/reference/feature-flag-setting-values.md) sections of the API. For using these endpoints, first you have to select which Config you want to work with by its `configId` which can be obtained from the [List Configs](https://configcat.com/docs/api/reference/get-configs.md) endpoint. Then you can use it to create new Feature Flags or to get information about existing ones. Then you can obtain the `settingId` or `key` of your desired Feature Flag or Setting to use them for further operations in this API. [Here](https://configcat.com/docs/main-concepts.md#setting) you can read more about the concept of Settings. ## [📄️ List Flags](https://configcat.com/docs/api/reference/get-settings.md) [This endpoint returns the list of the Feature Flags and Settings defined in a](https://configcat.com/docs/api/reference/get-settings.md) ## [📄️ Create Flag](https://configcat.com/docs/api/reference/create-setting.md) [This endpoint creates a new Feature Flag or Setting in a specified Config](https://configcat.com/docs/api/reference/create-setting.md) ## [📄️ Get predefined variations (Beta)](https://configcat.com/docs/api/reference/get-predefined-variations.md) [This endpoint returns the predefined variations along with their usages in the Environments for a Feature Flag or Setting identified by the \`settingId\` parameter.](https://configcat.com/docs/api/reference/get-predefined-variations.md) ## [📄️ Update predefined variations (Beta)](https://configcat.com/docs/api/reference/update-predefined-variations.md) [This endpoint updates the predefined variations for a Feature Flag or Setting identified by the \`settingId\` parameter.](https://configcat.com/docs/api/reference/update-predefined-variations.md) ## [📄️ Get Flag](https://configcat.com/docs/api/reference/get-setting.md) [This endpoint returns the metadata attributes of a Feature Flag or Setting](https://configcat.com/docs/api/reference/get-setting.md) ## [📄️ Replace Flag](https://configcat.com/docs/api/reference/replace-setting.md) [This endpoint replaces the whole value of a Feature Flag or Setting](https://configcat.com/docs/api/reference/replace-setting.md) ## [📄️ Update Flag](https://configcat.com/docs/api/reference/update-setting.md) [This endpoint updates the metadata of a Feature Flag or Setting](https://configcat.com/docs/api/reference/update-setting.md) ## [📄️ Delete Flag](https://configcat.com/docs/api/reference/delete-setting.md) [This endpoint removes a Feature Flag or Setting from a specified Config,](https://configcat.com/docs/api/reference/delete-setting.md) --- # Source: https://configcat.com/docs/glossary/feature-testing.md # Feature Testing - Tailoring the Ultimate User Experience Copy page ## Introduction[​](#introduction "Direct link to Introduction") The competitive edge of any software lies in its features — but how do you ensure that each feature resonates with your users? Feature Testing is the answer. It's a strategic approach that enables teams to determine the most impactful version of a feature to deliver a superior user experience. Here's an insight into Feature Testing and its vital role in user-centric development. ## What is Feature Testing?[​](#what-is-feature-testing "Direct link to What is Feature Testing?") Feature Testing, also known as A/B Testing or Split Testing, is an experimental process where two or more variants of a feature are compared to determine which one performs better in the context of user engagement and satisfaction. It involves exposing your audience to different versions of a feature within your application or website and using data-driven insights to decide which version yields the best outcomes. ## Objectives of Feature Testing[​](#objectives-of-feature-testing "Direct link to Objectives of Feature Testing") * **User Experience Enhancement**: Refining features to match user expectations and preferences. * **Performance Measurement**: Quantifying how different feature iterations affect user behavior. * **Data-Driven Decisions**: Basing feature iterations on concrete analytics rather than guesswork. * **Conversion Rate Optimization**: Improving the rate at which users take the desired action within the app or site. ## The Feature Testing Process[​](#the-feature-testing-process "Direct link to The Feature Testing Process") * **Hypothesis Formation**: Begin with a theory or question about how a feature change might impact user behavior. * **Variant Creation**: Develop multiple versions of the feature in question. * **Experimentation**: Randomly expose users to different versions and collect data on their interactions. * **Analysis**: Evaluate the data to determine which version achieved the defined objectives. ## Why Feature Testing is Indispensable[​](#why-feature-testing-is-indispensable "Direct link to Why Feature Testing is Indispensable") * **Risk Mitigation**: Before a full-scale rollout, test and understand the impact of new features. * **Improved Retention**: By optimizing features for user satisfaction, increase the likelihood of users sticking around. * **Agile Development**: Quickly adapt and respond to user feedback, making your development cycle more efficient. * **Competitive Advantage**: Stay ahead by continuously evolving your product to meet the latest user trends and needs. ## Challenges in Feature Testing and Strategies to Overcome Them[​](#challenges-in-feature-testing-and-strategies-to-overcome-them "Direct link to Challenges in Feature Testing and Strategies to Overcome Them") * **Statistical Significance**: Ensuring your test results are statistically valid. Strategy: Run tests for adequate durations and with sufficient sample sizes. * **Bias Elimination**: Preventing the test environment from skewing results. Strategy: Use randomization and control groups effectively. * **User Segmenting**: Not all users are the same. Strategy: Segment your user base to ensure relevant feedback. ## Conclusion[​](#conclusion "Direct link to Conclusion") Feature Testing is not just about choosing between 'A' or 'B' — it's about crafting experiences that resonate and retain. It empowers teams to make informed decisions, leading to a product that your users love, every single time. Unlock the potential of every feature and let the data guide your path to success. --- # Source: https://configcat.com/docs/targeting/targeting-rule/flag-condition.md # Flag Condition (Prerequisite) Copy page ## What is a Flag Condition? What is a prerequisite flag?[​](#what-is-a-flag-condition-what-is-a-prerequisite-flag "Direct link to What is a Flag Condition? What is a prerequisite flag?") A *Flag Condition* is a condition that is based on the comparison of another feature flag's value and a preset value (*comparison value*). In other words, a Flag Condition creates a dependency between the feature flag containing the condition (*dependent flag*) and another feature flag (*prerequisite flag*, aka. master feature flag, master switch, inter-dependent feature flag, global toggle, etc.) This allows you to control the value of multiple feature flags by changing the value of a single, central feature flag. Prerequisite flags are useful for managing complex feature dependencies and ensuring a smooth user experience during feature rollouts. ## How does the Flag Condition work?[​](#how-does-the-flag-condition-work "Direct link to How does the Flag Condition work?") The prerequisite flag is evaluated with the same User Object as the one used to evaluate the dependent flag, and then the result is checked against the comparator that you set on the Dashboard. The prerequisite flag can be other than a feature flag (boolean setting), in which case the prerequisite flag's evaluated value will be compared to the comparison value that you set on the Dashboard. The comparison is done according to the selected comparator and will result in true or false. This will be the result of the condition. For more details on the evaluation of Flag Conditions, please refer to [Feature Flag Evaluation](https://configcat.com/docs/targeting/feature-flag-evaluation.md#evaluation-of-a-flag-condition). ## How to set a Flag Condition?[​](#how-to-set-a-flag-condition "Direct link to How to set a Flag Condition?") You can add a Flag Condition to a feature flag by clicking the **+IF** ("Add targeting rule") button on the Dashboard. The prerequisite flag can be any feature flag already defined in the same config on the Dashboard. In the case of a non-boolean setting (e.g. text setting or number setting), you can also set a comparison value which the prerequisite flag's value will be compared to. ![Add prerequisite](/docs/assets/targeting/targeting-rule/flag-condition/add-prerequisite_192dpi.png) ## Anatomy of a Flag Condition[​](#anatomy-of-a-flag-condition "Direct link to Anatomy of a Flag Condition") #### Prerequisite is a feature flag (boolean setting)[​](#prerequisite-is-a-feature-flag-boolean-setting "Direct link to Prerequisite is a feature flag (boolean setting)") ![Flag condition anatomy (feature flag)](/docs/assets/targeting/targeting-rule/flag-condition/flag-condition-anatomy1_192dpi.png) #### Prerequisite is a string, integer or double setting[​](#prerequisite-is-a-string-integer-or-double-setting "Direct link to Prerequisite is a string, integer or double setting") ![Flag condition anatomy (non-boolean setting)](/docs/assets/targeting/targeting-rule/flag-condition/flag-condition-anatomy2_192dpi.png) A Flag Condition consists of the following: * ***Prerequisite flag key*:** The key of the feature flag or setting on which the condition is based. * ***Comparator*:** The comparison operator that defines the relation between the prerequisite flag's value and the comparison value. See the available comparators below. * ***Comparison value*:** The value that the prerequisite flag's value is compared to. Available only when the prerequisite flag is a string, integer or double setting. ### Comparator[​](#comparator "Direct link to Comparator") Different comparators are available for different types of prerequisites. When the prerequisite is a feature flag (boolean setting), the following comparators are available: | Comparator | Description | | ---------- | -------------------------------------------- | | IS ON | Checks whether the prerequisite flag is ON. | | IS OFF | Checks whether the prerequisite flag is OFF. | When the prerequisite is a string, integer or double setting, the following comparators are available: | Comparator | Description | | ---------- | ---------------------------------------------------------------------------------- | | EQUALS | Checks whether the prerequisite flag's value is equal to the comparison value. | | NOT EQUALS | Checks whether the prerequisite flag's value is not equal to the comparison value. | ## Examples[​](#examples "Direct link to Examples") ### Enable feature depending on the availability of another one[​](#enable-feature-depending-on-the-availability-of-another-one "Direct link to Enable feature depending on the availability of another one") #### Context[​](#context "Direct link to Context") Our demo company, Whisker Co. has a mobile app, which, among other things, can show the cat-friendly cafés in the neighborhood. The app can send notifications about the users' favorite cafés. This feature is not available to everyone though, it's enabled using the **Enable Cafe Notifications** feature flag. There is another feature that allows users to rate cafés, whose availability is controlled similarly, via the **Enable Cafe Ratings** feature flag. #### Goal[​](#goal "Direct link to Goal") We want to make sure that users only receive notifications about their favorite cafés if they can rate them. #### Solution[​](#solution "Direct link to Solution") ConfigCat offers a built-in way to solve this problem without the need of extra coding: prerequisite flags. We can achieve our goal by adding a Targeting Rule containing a Flag Condition to **Enable Cafe Notifications**, then referencing **Enable Cafe Ratings** in the condition and setting the comparator to **IS ON**, meaning that the **Enable Cafe Notifications** feature flag will be enabled only if the **Enable Cafe Ratings** feature flag is ON. On the Dashboard: ![Flag condition example](/docs/assets/targeting/targeting-rule/flag-condition/flag-condition-example_192dpi.png) --- # Source: https://configcat.com/docs/api/reference/generate-proxy-profile-secret.md # Generate Secret Copy page This endpoint (re)generates a secret token for a Proxy Profile identified by the `proxyProfileId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When the generation was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-auditlogs.md # List Audit log items for Product Copy page This endpoint returns the list of Audit log items for a given Product and the result can be optionally filtered by Config and/or Environment. If neither `fromUtcDateTime` nor `toUtcDateTime` is set, the audit logs for the **last 7 days** will be returned. The distance between `fromUtcDateTime` and `toUtcDateTime` cannot exceed **30 days**. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-config.md # Get Config Copy page This endpoint returns the metadata of a Config identified by the `configId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the config data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-configs.md # List Configs Copy page This endpoint returns the list of the Configs that belongs to the given Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-deleted-settings.md # List Deleted Settings Copy page This endpoint returns the list of Feature Flags and Settings that were deleted from the given Config. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-environment.md # Get Environment Copy page This endpoint returns the metadata of an Environment identified by the `environmentId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the environment data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-environments.md # List Environments Copy page This endpoint returns the list of the Environments that belongs to the given Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/get-group.md # Get Group Copy page This endpoint returns a group. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/get-groups.md # Get Groups Copy page This endpoint returns a list of groups. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-integration.md # Get Integration Copy page This endpoint returns the metadata of an Integration identified by the `integrationId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the integration data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-integrations.md # List Integrations Copy page This endpoint returns the list of the Integrations that belongs to the given Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-me.md # Get authenticated user details Copy page ## Responses[​](#responses "Direct link to Responses") * 200 * 429 Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-organization-auditlogs.md # List Audit log items for Organization Copy page This endpoint returns the list of Audit log items for a given Organization and the result can be optionally filtered by Product and/or Config and/or Environment. If neither `fromUtcDateTime` nor `toUtcDateTime` is set, the audit logs for the **last 7 days** will be returned. The distance between `fromUtcDateTime` and `toUtcDateTime` cannot exceed **30 days**. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-organization-limitations.md # Get Organization limitations Copy page This endpoint returns the limitations of an Organization identified by the `organizationId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 429 Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-organization-members-v-2.md # List Organization Members Copy page This endpoint returns the list of Members that belongs to the given Organization, identified by the `organizationId` parameter. The results may vary based on the access level of the user who calls the endpoint: * When it's called with Organization Admin privileges, the result will contain each member in the Organization. * When it's called without Organization Admin privileges, the result will contain each Organization Admin along with members of those products where the caller has `Team members and permission groups` (`canManageMembers`) permission. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-organization-members.md # List Organization Members Copy page deprecated This endpoint has been deprecated and may be replaced or removed in future versions of the API. This endpoint returns the list of Members that belongs to the given Organization, identified by the `organizationId` parameter. The results may vary based on the access level of the user who calls the endpoint: * When it's called with Organization Admin privileges, the result will contain each member in the Organization. * When it's called without Organization Admin privileges, the result will contain each Organization Admin along with members of those products where the caller has `Team members and permission groups` (`canManageMembers`) permission. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-organizations.md # List Organizations Copy page This endpoint returns the list of the Organizations that belongs to the user. ## Responses[​](#responses "Direct link to Responses") * 200 * 429 Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-pending-invitations-org.md # List Pending Invitations in Organization Copy page This endpoint returns the list of pending invitations within the given Organization identified by the `organizationId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-pending-invitations.md # List Pending Invitations in Product Copy page This endpoint returns the list of pending invitations within the given Product identified by the `productId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-permission-group.md # Get Permission Group Copy page This endpoint returns the metadata of a Permission Group identified by the `permissionGroupId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the permission group data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-permission-groups.md # List Permission Groups Copy page This endpoint returns the list of the Permission Groups that belongs to the given Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-predefined-variations.md # Get predefined variations (Beta) Copy page This endpoint returns the predefined variations along with their usages in the Environments for a Feature Flag or Setting identified by the `settingId` parameter. **Beta feature:** The feature is currently in closed beta state and cannot be used. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When the update was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-product-members.md # List Product Members Copy page This endpoint returns the list of Members that belongs to the given Product, identified by the `productId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-product-preferences.md # Get Product Preferences Copy page This endpoint returns the preferences of a Product identified by the `productId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the product preferences data is returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-product.md # Get Product Copy page This endpoint returns the metadata of a Product identified by the `productId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the product data is returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-products.md # List Products Copy page This endpoint returns the list of the Products that belongs to the user. ## Responses[​](#responses "Direct link to Responses") * 200 * 429 Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-proxy-profile-sdk-keys.md # Get selected SDK keys Copy page This endpoint returns the list of SDK keys selected for a Proxy Profile identified by the `proxyProfileId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the SDK keys selected for the Proxy Profile are returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-proxy-profile.md # Get Proxy Profile Copy page This endpoint returns a Proxy Profile identified by the `proxyProfileId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the Proxy Profile is returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-proxy-profiles.md # List Proxy Profiles Copy page This endpoint returns the list of Proxy profiles for the given Organization identified by the `organizationId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-references-for-feature-flag-or-setting.md # Get References for Feature Flag or Setting Copy page ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/get-resource-type.md # Get Resource Type Copy page This endpoint returns a resource type. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 401 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/get-resource-types.md # Get Resource Types Copy page This endpoint returns the supported resource types. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 401 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/get-schema.md # Get Schema Copy page This endpoint returns a schema. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 401 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/get-schemas.md # Get Schemas Copy page This endpoint returns the supported schema list. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 401 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-sdk-keys.md # Get SDK Key Copy page This endpoint returns the SDK Key for your Config in a specified Environment. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-segment.md # Get Segment Copy page This endpoint returns the metadata of a Segment identified by the `segmentId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the config data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-segments.md # List Segments Copy page This endpoint returns the list of the Segments that belongs to the given Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/get-service-provider-config.md # Get Service Provider Config Copy page This endpoint returns the service provider config. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 401 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-setting-value-by-sdkkey-v-2.md # Get value Copy page This endpoint returns the value of a Feature Flag or Setting in a specified Environment identified by the [SDK key](https://app.configcat.com/sdkkey) passed in the `X-CONFIGCAT-SDKKEY` header. The most important fields in the response are the `defaultValue`, `targetingRules`. The `defaultValue` represents what the clients will get when the evaluation requests of our SDKs are not matching to any of the defined Targeting Rules, or when there are no additional rules to evaluate. The `targetingRules` represents the current Targeting Rule configuration of the actual Feature Flag or Setting in an **ordered** collection, which means the order of the returned rules is matching to the evaluation order. You can read more about these rules [here](https://configcat.com/docs/targeting/targeting-overview.md). The `percentageEvaluationAttribute` represents the custom [User Object](https://configcat.com/docs/targeting/user-object.md) attribute that must be used at the [percentage evaluation](https://configcat.com/docs/targeting/percentage-options.md) of the Feature Flag or Setting. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-setting-value-by-sdkkey.md # Get value Copy page This endpoint returns the value of a Feature Flag or Setting in a specified Environment identified by the [SDK key](https://app.configcat.com/sdkkey) passed in the `X-CONFIGCAT-SDKKEY` header. The most important attributes in the response are the `value`, `rolloutRules` and `percentageRules`. The `value` represents what the clients will get when the evaluation requests of our SDKs are not matching to any of the defined Targeting or Percentage Rules, or when there are no additional rules to evaluate. The `rolloutRules` and `percentageRules` attributes are representing the current Targeting and Percentage Rules configuration of the actual Feature Flag or Setting in an **ordered** collection, which means the order of the returned rules is matching to the evaluation order. You can read more about these rules [here](https://configcat.com/docs/targeting/targeting-overview.md). ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-setting-value-v-2.md # Get value Copy page This endpoint returns the value of a Feature Flag or Setting in a specified Environment identified by the `environmentId` parameter. The most important fields in the response are the `defaultValue`, `targetingRules`, and `percentageEvaluationAttribute`. The `defaultValue` represents what the clients will get when the evaluation requests of our SDKs are not matching to any of the defined Targeting Rules, or when there are no additional rules to evaluate. The `targetingRules` represents the current Targeting Rule configuration of the actual Feature Flag or Setting in an **ordered** collection, which means the order of the returned rules is matching to the evaluation order. You can read more about these rules [here](https://configcat.com/docs/targeting/targeting-overview.md). The `percentageEvaluationAttribute` represents the custom [User Object](https://configcat.com/docs/targeting/user-object.md) attribute that must be used for [percentage evaluation](https://configcat.com/docs/targeting/percentage-options.md) of the Feature Flag or Setting. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the setting value data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-setting-value.md # Get value Copy page This endpoint returns the value of a Feature Flag or Setting in a specified Environment identified by the `environmentId` parameter. The most important attributes in the response are the `value`, `rolloutRules` and `percentageRules`. The `value` represents what the clients will get when the evaluation requests of our SDKs are not matching to any of the defined Targeting or Percentage Rules, or when there are no additional rules to evaluate. The `rolloutRules` and `percentageRules` attributes are representing the current Targeting and Percentage Rules configuration of the actual Feature Flag or Setting in an **ordered** collection, which means the order of the returned rules is matching to the evaluation order. You can read more about these rules [here](https://configcat.com/docs/targeting/targeting-overview.md). ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the setting value data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-setting-values-v-2.md # Get values Copy page This endpoint returns all Feature Flag and Setting values of a Config identified by the `configId` parameter in a specified Environment identified by the `environmentId` parameter. The most important fields in the response are the `defaultValue`, `targetingRules`. The `defaultValue` represents what the clients will get when the evaluation requests of our SDKs are not matching to any of the defined Targeting Rules, or when there are no additional rules to evaluate. The `targetingRules` represents the current Targeting Rule configuration of the actual Feature Flag or Setting in an **ordered** collection, which means the order of the returned rules is matching to the evaluation order. You can read more about these rules [here](https://configcat.com/docs/targeting/targeting-overview.md). The `percentageEvaluationAttribute` represents the custom [User Object](https://configcat.com/docs/targeting/user-object.md) attribute that must be used for [percentage evaluation](https://configcat.com/docs/targeting/percentage-options.md) of the Feature Flag or Setting. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the setting values returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-setting-values.md # Get values Copy page This endpoint returns the value of a specified Config's Feature Flags or Settings identified by the `configId` parameter in a specified Environment identified by the `environmentId` parameter. The most important attributes in the response are the `value`, `rolloutRules` and `percentageRules`. The `value` represents what the clients will get when the evaluation requests of our SDKs are not matching to any of the defined Targeting or Percentage Rules, or when there are no additional rules to evaluate. The `rolloutRules` and `percentageRules` attributes are representing the current Targeting and Percentage Rules configuration of the actual Feature Flag or Setting in an **ordered** collection, which means the order of the returned rules is matching to the evaluation order. You can read more about these rules [here](https://configcat.com/docs/targeting/targeting-overview.md). ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the setting values returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-setting.md # Get Flag Copy page This endpoint returns the metadata attributes of a Feature Flag or Setting identified by the `settingId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the setting data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-settings-by-tag.md # List Settings by Tag Copy page This endpoint returns the list of the Settings that has the specified Tag, identified by the `tagId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the settings data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-settings.md # List Flags Copy page This endpoint returns the list of the Feature Flags and Settings defined in a specified Config, identified by the `configId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-staleflags.md # List Zombie (stale) flags for Product Copy page This endpoint returns the list of Zombie (stale) flags for a given Product and the result can be optionally filtered by various parameters. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-tag.md # Get Tag Copy page This endpoint returns the metadata of a Tag identified by the `tagId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the tag data returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-tags.md # List Tags Copy page This endpoint returns the list of the Tags in a specified Product, identified by the `productId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 429 Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/get-user.md # Get User Copy page This endpoint returns a user. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/scim/get-users.md # Get Users Copy page This endpoint returns a list of users. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 401 * 404 * 429 Unauthorized. In case of the SCIM token is invalid. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-webhook-signing-keys.md # Get Webhook Signing Keys Copy page This endpoint returns the signing keys of a Webhook identified by the `webhookId`. Signing keys are used for ensuring the Webhook requests you receive are actually sent by ConfigCat. [Here](https://configcat.com/docs/advanced/notifications-webhooks.md#verifying-webhook-requests) you can read more about Webhook request verification. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the webhook signing keys are returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-webhook.md # Get Webhook Copy page This endpoint returns the metadata of a Webhook identified by the `webhookId`. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the webhook data is returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/get-webhooks.md # List Webhooks Copy page This endpoint returns the list of the Webhooks that belongs to the given Product identified by the `productId` parameter, which can be obtained from the [List Products](https://configcat.com/docs/api/reference/get-products.md) endpoint. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 429 Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/getting-started.md # Getting Started Copy page This page is an overview and a short guide on how to get started. **ConfigCat** is a cloud-based service that lets you release features without code deployments. You can use it with many similar techniques, such as feature flags/toggles, canary releases, soft launches, A-B testing, remote configuration management, and phased rollouts. Configure your application and features even after deployment. ## The birth of a Feature Flag[​](#the-birth-of-a-feature-flag "Direct link to The birth of a Feature Flag") First, **add a feature flag** on the *ConfigCat Dashboard*, and then you can **connect your application** to the ConfigCat service to access your feature flag. ### Create a feature flag on the *ConfigCat Dashboard*[​](#create-a-feature-flag-on-the-configcat-dashboard "Direct link to create-a-feature-flag-on-the-configcat-dashboard") 1. [Log in](https://app.configcat.com) to the *Dashboard* 2. Click *ADD FEATURE FLAG* and give it a name. ![Add feature flag](/docs/assets/add-feature-flag_192dpi.png) ### Explore with Our Tutorial App[​](#explore-with-our-tutorial-app "Direct link to Explore with Our Tutorial App") Before diving into connecting your actual application, consider exploring our [Feature Flags Tutorial](https://tutorial.configcat.com/?lm=11). This interactive app provides a practical and engaging way to learn about ConfigCat and feature flags without needing to integrate immediately with your current projects. It's perfect for beginners to understand the functionalities and advantages of using feature flags effectively. ![Feature Flags Tutorial](/docs/assets/news/tutorial_192dpi.png) [Start the Feature Flags Tutorial](https://tutorial.configcat.com/?lm=12) ### Connect your application[​](#connect-your-application "Direct link to Connect your application") There are ready-to-use code snippets for `Browser (JavaScript)`, `Angular`, `React`, `Node.js`, `Deno`, `Bun`, `Cloudflare Worker`, `.NET (C#)`, `Java`, `Go`, `PHP`, `Python`, `Android (Java)`, `iOS (Swift)`, `Dart / Flutter`, `Kotlin Multiplatform`, `Ruby`, `Elixir`, `C++`, `Rust`, `Unreal Engine` on the [ConfigCat Dashboard](https://app.configcat.com), just scroll down to the **SDK Key and steps to connect your application** section. All the ConfigCat SDKs are open-source and available on [GitHub](https://github.com/configcat). See the detailed [Docs on how to use the ConfigCat SDKs.](https://configcat.com/docs/sdk-reference/overview.md) Here's a short example to demonstrate the concept: ```js // 0. If necessary, install the ConfigCat SDK package for the platform you use. // E.g. `npm install @configcat/sdk` // 1. Import the ConfigCat SDK package. import * as configcat from '@configcat/sdk'; // 2. Get a client object for the SDK Key of your config. const client = configcat.getClient('#YOUR-SDK-KEY#'); // 3. Evaluate a feature flag using the client object. const value = await client.getValueAsync('isMyFeatureEnabled', false); // 4. Based on the value of the feature flag decide whether or not to enable the related feature. if (value) { do_the_new_thing(); } else { do_the_old_thing(); } ``` --- # Source: https://configcat.com/docs/advanced/code-references/github-action.md # GitHub Action - Scan your source code for feature flags Copy page This section describes how to use ConfigCat's [Scan Repository GitHub Action](https://github.com/marketplace/actions/configcat-scan-repository) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. You can find more information about GitHub Actions [here](https://github.com/features/actions). ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in your repository's [GitHub Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![Github Action secrets](/docs/assets/cli/scan/github_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Create a new Actions workflow in your GitHub repository under the `.github/workflows` folder, and put the following snippet into it. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml on: [push] name: Code references jobs: scan-repo: runs-on: ubuntu-latest name: Scan repository for code references steps: - name: Checkout uses: actions/checkout@v3 - name: Scan & upload uses: configcat/scan-repository@v2 with: api-user: ${{ secrets.CONFIGCAT_API_USER }} api-pass: ${{ secrets.CONFIGCAT_API_PASS }} config-id: PASTE-YOUR-CONFIG-ID-HERE # line-count: 5 # optional # timeout: 1800 # optional # sub-folder: src # optional # exclude-keys: > # optional # flag_key_to_exclude_1 # flag_key_to_exclude_2 # alias-patterns: (\w+) = :CC_KEY,const (\w+) = feature_flags\.enabled\(:CC_KEY\) #optional # usage-patterns: feature_flags\.enabled\(:CC_KEY\) # optional, comma delimited flag key usage patterns # verbose: true # optional ``` 4. Commit & push your action. The above example configures a workflow that executes the scan and code references upload on every git `push` event. Scan reports are uploaded for each branch of your repository that triggers the workflow. ## Available Options[​](#available-options "Direct link to Available Options") | Parameter | Description | Required | Default | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------- | | `config-id` | ID of the ConfigCat config to scan against. | ☑ | | | `api-user` | [ConfigCat Management API basic authentication username](https://app.configcat.com/my-account/public-api-credentials). | ☑ | | | `api-pass` | [ConfigCat Management API basic authentication password](https://app.configcat.com/my-account/public-api-credentials). | ☑ | | | `api-host` | ConfigCat Management API host. | | `api.configcat.com` | | `line-count` | Context line count before and after the reference line. (min: 1, max: 10) | | 4 | | `timeout` | Scan timeout in seconds (default: 1800, min: 60). If the scan does not finish within this time, it is aborted. No partial results are returned. The command exits with a timeout error. | | 1800 | | `sub-folder` | Sub-folder to scan, relative to the repository root folder. | | | | `exclude-keys` | List of feature flag keys that must be excluded from the scan report. | | | | `alias-patterns` | Comma delimited list of custom regex patterns used to search for additional aliases. | | | | `usage-patterns` | Comma delimited list of custom regex patterns that describe additional feature flag key usages. | | | | `verbose` | Turns on detailed logging. | | false | --- # Source: https://configcat.com/docs/integrations/github-cli.md # Install the ConfigCat CLI in GitHub Actions Copy page This section describes how to install and use the ConfigCat CLI in GitHub Action workflows. ### Prerequisites[​](#prerequisites "Direct link to Prerequisites") * To let the CLI access the ConfigCat Public Management API, you have to create a new [API credential](https://app.configcat.com/my-account/public-api-credentials). Store the credential in your repository's [GitHub Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![Github Action secrets](/docs/assets/cli/scan/github_secrets.png) ### Example[​](#example "Direct link to Example") The following example shows how you can install the ConfigCat CLI with ConfigCat's [CLI Github Actions](https://github.com/configcat/cli-actions) in your workflow. ```yaml name: Workflow with ConfigCat CLI on: push jobs: example-job: runs-on: ubuntu-latest env: CONFIGCAT_API_USER: ${{ secrets.CONFIGCAT_API_USER }} CONFIGCAT_API_PASS: ${{ secrets.CONFIGCAT_API_PASS }} steps: - uses: configcat/cli-actions@v1 # Using the CLI in other steps - name: Update feature flag value run: configcat flag-v2 value update --flag-id --environment-id --flag-value true ``` info The action doesn't execute the `setup` command. It's recommended to set the `CONFIGCAT_API_USER` and `CONFIGCAT_API_PASS` environment variables on a job level, so each subsequent step that uses a ConfigCat CLI command can access them. --- # Source: https://configcat.com/docs/integrations/github-eval.md # Evaluate feature flags in GitHub Actions Copy page ConfigCat's [CLI GitHub Actions](https://github.com/configcat/cli-actions) has the ability to evaluate feature flags in GitHub Action workflows. This feature lets you use your feature flag values or create conditional steps in your workflow. ### Prerequisites[​](#prerequisites "Direct link to Prerequisites") * An SDK key for the ConfigCat config/environment pair that contains the feature flags you want to evaluate. ### Example[​](#example "Direct link to Example") The following example shows how you can evaluate ConfigCat feature flags and use the evaluated results in subsequent steps. ```yaml name: Evaluate ConfigCat feature flags on: push jobs: example-job: runs-on: ubuntu-latest steps: - name: Evaluate feature flags id: flags uses: configcat/cli-actions/eval-flag@v1 with: sdk-key: ${{ secrets.CONFIGCAT_SDK_KEY }} flag-keys: | flag1 flag2 user-attributes: | id:1234 - name: Step depending on flag1 if: steps.flags.outputs.flag1 == 'true' run: echo "flag1 is true" - name: Step depending on flag2 if: steps.flags.outputs.flag2 == 'true' run: echo "flag2 is true" ``` The results of the flag evaluations are stored in the step outputs named with each flag's key. ### Available Options[​](#available-options "Direct link to Available Options") | Parameter | Description | Required | Default | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ---------------------- | | `sdk-key` | SDK key identifying the config to download, also loaded from the `CONFIGCAT_SDK_KEY` environment variable | | | | `flag-keys` | List of feature flag keys to evaluate. Multiple values must be in separate lines. | ☑ | | | `user-attributes` | List of user attributes used for evaluation. Multiple values must be in separate lines in the following format: `:`. Dedicated User Object attributes are mapped like the following: Identifier => id, Email => email, Country => country. | | | | `base-url` | The CDN base url from where the CLI will download the config JSON. | | ConfigCat CDN servers. | | `data-governance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. Possible values: `eu`, `global`. | | `global` | | `verbose` | Turns on detailed logging. | | false | --- # Source: https://configcat.com/docs/integrations/github.md # Scan your code for feature flag usages Copy page ConfigCat's [Scan Repository GitHub Action](https://github.com/marketplace/actions/configcat-scan-repository) has the ability to scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. This feature makes the elimination of the technical debt easier, as it can show which repositories reference your feature flags and settings in one centralized place on your [Dashboard](https://app.configcat.com). [Here](https://configcat.com/docs/advanced/code-references/overview.md) you can find more details about how this feature works. This section describes how to use ConfigCat's [Scan Repository GitHub Action](https://github.com/marketplace/actions/configcat-scan-repository) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. You can find more information about GitHub Actions [here](https://github.com/features/actions). ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in your repository's [GitHub Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![Github Action secrets](/docs/assets/cli/scan/github_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Create a new Actions workflow in your GitHub repository under the `.github/workflows` folder, and put the following snippet into it. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml on: [push] name: Code references jobs: scan-repo: runs-on: ubuntu-latest name: Scan repository for code references steps: - name: Checkout uses: actions/checkout@v3 - name: Scan & upload uses: configcat/scan-repository@v2 with: api-user: ${{ secrets.CONFIGCAT_API_USER }} api-pass: ${{ secrets.CONFIGCAT_API_PASS }} config-id: PASTE-YOUR-CONFIG-ID-HERE # line-count: 5 # optional # timeout: 1800 # optional # sub-folder: src # optional # exclude-keys: > # optional # flag_key_to_exclude_1 # flag_key_to_exclude_2 # alias-patterns: (\w+) = :CC_KEY,const (\w+) = feature_flags\.enabled\(:CC_KEY\) #optional # usage-patterns: feature_flags\.enabled\(:CC_KEY\) # optional, comma delimited flag key usage patterns # verbose: true # optional ``` 4. Commit & push your action. The above example configures a workflow that executes the scan and code references upload on every git `push` event. Scan reports are uploaded for each branch of your repository that triggers the workflow. ## Available Options[​](#available-options "Direct link to Available Options") | Parameter | Description | Required | Default | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------- | | `config-id` | ID of the ConfigCat config to scan against. | ☑ | | | `api-user` | [ConfigCat Management API basic authentication username](https://app.configcat.com/my-account/public-api-credentials). | ☑ | | | `api-pass` | [ConfigCat Management API basic authentication password](https://app.configcat.com/my-account/public-api-credentials). | ☑ | | | `api-host` | ConfigCat Management API host. | | `api.configcat.com` | | `line-count` | Context line count before and after the reference line. (min: 1, max: 10) | | 4 | | `timeout` | Scan timeout in seconds (default: 1800, min: 60). If the scan does not finish within this time, it is aborted. No partial results are returned. The command exits with a timeout error. | | 1800 | | `sub-folder` | Sub-folder to scan, relative to the repository root folder. | | | | `exclude-keys` | List of feature flag keys that must be excluded from the scan report. | | | | `alias-patterns` | Comma delimited list of custom regex patterns used to search for additional aliases. | | | | `usage-patterns` | Comma delimited list of custom regex patterns that describe additional feature flag key usages. | | | | `verbose` | Turns on detailed logging. | | false | --- # Source: https://configcat.com/docs/advanced/code-references/gitlab-ci.md # GitLab - Scan your source code for feature flags Copy page This section describes how to use the [ConfigCat CLI](https://configcat.com/docs/advanced/cli.md) in [GitLab CI/CD](https://docs.gitlab.com/ee/ci/) to automatically scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. ## Setup[​](#setup "Direct link to Setup") 1. Create a new [ConfigCat Management API credential](https://app.configcat.com/my-account/public-api-credentials) and store its values in GitLab's [CI/CD Variables](https://docs.gitlab.com/ee/ci/variables/) with the following names: `CONFIGCAT_API_USER`, `CONFIGCAT_API_PASS`. ![GitLab secrets](/docs/assets/cli/scan/gl_secrets.png) 2. Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). 3. Create a new or open your existing `.gitlab-ci.yml` file, and put the following job into it. Don't forget to replace the `PASTE-YOUR-CONFIG-ID-HERE` value with your actual Config ID. ```yaml configcat-scan-repository: stage: deploy # the job will run in the deploy phase, but you can choose from any other phases you have image: name: configcat/cli:2.4.2 entrypoint: [''] script: - configcat scan $CI_PROJECT_DIR --config-id=PASTE-YOUR-CONFIG-ID-HERE --repo=${CI_PROJECT_NAME} --branch=${CI_COMMIT_REF_NAME} --file-url-template=https://gitlab.com/${CI_PROJECT_PATH}/blob/{commitHash}/{filePath}#L{lineNumber} --commit-url-template=https://gitlab.com/${CI_PROJECT_PATH}/commit/{commitHash} --runner="ConfigCat GitLab Job" --upload --non-interactive ``` 4. Commit & push your changes. Scan reports are uploaded for each branch of your repository that triggers the job. --- # Source: https://configcat.com/docs/glossary.md # Glossary of Terms Copy page An alphabetical list of terms used around feature management and software development in general in the context of ConfigCat. ## A[​](#a "Direct link to A") #### [A/B Testing](https://configcat.com/blog/2022/05/02/what-is-ab-testing/)[​](#ab-testing "Direct link to ab-testing") A/B testing is a method of comparing two versions of a product or feature to determine which one performs better. A/B testing is a form of controlled experimentation. #### [Alpha Testing](https://configcat.com/docs/glossary/alpha-testing.md)[​](#alpha-testing "Direct link to alpha-testing") Alpha testing examines a product's functionality and compliance with the business requirements through the initial end-to-end testing. ## B[​](#b "Direct link to B") #### [Beta Testing](https://configcat.com/docs/glossary/beta-testing.md)[​](#beta-testing "Direct link to beta-testing") Testing in the beta phase allows users to discover any issues or bugs before a general release by using a product in a real-world environment. #### [Blue/Green Deployment](https://configcat.com/docs/glossary/blue-green-deployment.md)[​](#bluegreen-deployment "Direct link to bluegreen-deployment") Blue/Green deployments offer near-zero downtime and rollback capabilities. The concept of a blue/green deployment involves switching traffic between two identical environments running different versions of your application. ## C[​](#c "Direct link to C") #### [Canary Release](https://configcat.com/canary-testing)[​](#canary-release "Direct link to canary-release") A Canary Release is a type of progressive delivery where a small percentage of users are exposed to a new feature. If the feature works as expected, the percentage of users exposed to the feature is increased. If the feature does not work as expected, the feature is rolled back. #### [Canary Testing](https://configcat.com/canary-testing/)[​](#canary-testing "Direct link to canary-testing") Canary testing is a software deployment technique where updates or new features are rolled out to a small, carefully selected subset of users before being released to the entire user base, to test and ensure their effectiveness and safety. #### [CI/CD Pipeline](https://configcat.com/docs/glossary/ci-cd-pipeline.md)[​](#cicd-pipeline "Direct link to cicd-pipeline") A CI/CD (Continuous Integration and Continuous Deployment) pipeline is a set of steps that must be followed to deliver a new software version to customers. #### [Continuous Delivery](https://configcat.com/blog/2022/06/13/decoupling-feature-releases-from-deployment/)[​](#continuous-delivery "Direct link to continuous-delivery") A continuous delivery process enables changes - including new features, configuration changes, bug fixes and experiments - to be released into production in a safe and timely manner while maintaining sustainability. #### [Continuous Deployment](https://configcat.com/blog/2022/06/13/decoupling-feature-releases-from-deployment/)[​](#continuous-deployment "Direct link to continuous-deployment") Continuous Deployment is a process where any code changes brought to an application are released automatically into the production environment. #### [Continuous Integration](https://configcat.com/docs/glossary/continuous-integration.md)[​](#continuous-integration "Direct link to continuous-integration") Continuous Integration refers to the regular merging of code changes into a central repository, followed by automated builds and tests. ## D[​](#d "Direct link to D") #### [Dark Launch](https://configcat.com/blog/2022/06/13/decoupling-feature-releases-from-deployment/#feature-release-with-dark-launch)[​](#dark-launch "Direct link to dark-launch") A dark launch involves releasing a feature to a subset of users before a full release to test reactions. #### [Developer Advocate](https://configcat.com/blog/2023/07/11/role-of-developer-advocates/)[​](#developer-advocate "Direct link to developer-advocate") A Developer Advocate is a person whose job is to help developers be successful with a platform or a technology and to speak (or write) on their behalf. #### [DevOps Engineer](https://configcat.com/docs/glossary/devops-engineer.md)[​](#devops-engineer "Direct link to devops-engineer") The DevOps Engineer is responsible for the development and maintenance of the infrastructure and the deployment of the software. The DevOps Engineer is also responsible for the monitoring and maintenance of the software and the infrastructure. ## E[​](#e "Direct link to E") ## F[​](#f "Direct link to F") #### [Fake Door Testing](https://configcat.com/fake-door-testing/)[​](#fake-door-testing "Direct link to fake-door-testing") Fake Door Testing is a technique used to assess the market demand for a product prior to investing in its development. #### [Feature Branch](https://configcat.com/feature-branch/)[​](#feature-branch "Direct link to feature-branch") A feature branch is a copy of the main codebase where an individual or team of software developers can work on a new feature until it is complete. #### [Feature Flag](https://configcat.com/featureflags/)[​](#feature-flag "Direct link to feature-flag") A feature flag is a toggle used to activate or deactivate specific features you may have in your application without redeploying code. #### [Feature Testing](https://configcat.com/docs/glossary/feature-testing.md)[​](#feature-testing "Direct link to feature-testing") An experiment to determine which version of a feature offers the best user experience is called a Feature Test. #### [Feature Flag Framework](https://configcat.com/feature-flag-framework-explained/)[​](#feature-flag-framework "Direct link to feature-flag-framework") A feature flag framework is a system that allows developers to enable or disable specific functionalities of an application, enabling testing, gradual rollouts, and easy adjustments without redeploying the whole software. #### [Feature Flagging Tools](https://configcat.com/feature-flagging-tools/)[​](#feature-flagging-tools "Direct link to feature-flagging-tools") Feature flagging tools are software utilities that enable developers to control the visibility and operational state of individual features in a software product, allowing for selective exposure and A/B testing without requiring system-wide updates or redeployments. #### [Feature Flags as a Service](https://configcat.com/feature-flag-as-a-service/)[​](#feature-flags-as-a-service "Direct link to feature-flags-as-a-service") Providing feature flags as a service involves delivering (under a subscription model) a cloud solution for managing software features, enhancing development efficiency, risk control, and user experience. #### [Feature Toggles](https://configcat.com/feature-toggles/)[​](#feature-toggles "Direct link to feature-toggles") Feature toggles, also known as feature flags, are a software development technique that allows the enabling or disabling of specific functionalities within an application, facilitating testing, incremental rollouts, and feature control without redeploying the software. #### [Feature Toggle Management](https://configcat.com/feature-toggle-management/)[​](#feature-toggle-management "Direct link to feature-toggle-management") Feature toggle management refers to the process of controlling and coordinating the use of feature flags or toggles in software development, enabling developers to switch on or off certain functionalities for testing, deployment, or user experience customization. ## G[​](#g "Direct link to G") ## H[​](#h "Direct link to H") ## I[​](#i "Direct link to I") ## J[​](#j "Direct link to J") ## K[​](#k "Direct link to K") #### [Kill Switch](https://configcat.com/blog/2022/03/24/how-kantan-successfully-uses-configcat-in-its-ci-pipeline/#retiring-feature-flags-or-keeping-them-as-emergency-kill-switches)[​](#kill-switch "Direct link to kill-switch") A kill switch is a mechanism that can be used to quickly disable a feature or an entire application in case of an emergency. ## L[​](#l "Direct link to L") ## M[​](#m "Direct link to M") #### [Multi-Armed Bandit](https://configcat.com/docs/glossary/multi-armed-bandit.md)[​](#multi-armed-bandit "Direct link to multi-armed-bandit") The Multi-Armed Bandit (MAB) is a machine learning framework that involves an agent making selections, referred to as "arms," with the goal of maximizing long-term cumulative rewards. ## N[​](#n "Direct link to N") ## O[​](#o "Direct link to O") ## P[​](#p "Direct link to P") #### [Product Lifecycle Manager](https://configcat.com/docs/glossary/product-lifecycle-manager.md)[​](#product-lifecycle-manager "Direct link to product-lifecycle-manager") The role of a product lifecycle manager is to supervise the project team and ensure timely completion of each stage in the lifecycle of a project. #### [Platform Engineering](https://configcat.com/platform-engineering/)[​](#platform-engineering "Direct link to platform-engineering") Platform engineering is the design and maintenance of the foundational infrastructure and tools that support software development teams in building, deploying, and operating applications at scale. It combines elements of systems and software engineering with automation to provide standardized environments and CI/CD pipelines, enabling developers to focus on code while minimizing infrastructure complexity. #### [Progressive Delivery](https://configcat.com/blog/2022/01/14/progressive-delivery/)[​](#progressive-delivery "Direct link to progressive-delivery") A progressive delivery approach to DevOps combines the principles of Continuous Integration and Continuous Delivery (CI/CD) with modern software development practices, facilitating faster code deployment, reducing risk, and improving user experiences. ## Q[​](#q "Direct link to Q") ## R[​](#r "Direct link to R") #### [Rails Feature Flags](https://configcat.com/rails-feature-flag/)[​](#rails-feature-flags "Direct link to rails-feature-flags") Rails feature flags are conditional coding elements used in Ruby on Rails applications that enable or disable specific features dynamically, facilitating controlled release, A/B testing, and gradual rollout of software functionalities. #### [React Feature Flags](https://configcat.com/react-feature-flag/)[​](#react-feature-flags "Direct link to react-feature-flags") React feature flags are conditional codes used in React.js applications to enable or disable certain features dynamically, allowing for controlled release, testing, and customization of software functionalities. #### [Release Manager](https://configcat.com/docs/glossary/release-manager.md)[​](#release-manager "Direct link to release-manager") A release manager is an IT professional responsible for defining and executing the software release process within a company, ensuring smooth deployment and high-quality releases. #### [Remote Configuration](https://configcat.com/docs/glossary/remote-configuration.md)[​](#remote-configuration "Direct link to remote-configuration") Remote configuration is a software development technique that allows you to modify certain features of an app remotely without having to deploy a new version of the app. #### [Ring Deployment](https://configcat.com/ring-deployment/)[​](#ring-deployment "Direct link to ring-deployment") Ring deployment is a form of gradual rollout where new features are released gradually to different groups of users to mitigate risk. ## S[​](#s "Direct link to S") #### [Site Reliability Engineer](https://configcat.com/site-reliability-engineers/)[​](#site-reliability-engineer "Direct link to site-reliability-engineer") A site reliability engineer (SRE) is a professional in the field of information technology who uses automation tools to monitor the reliability of software in a live production environment. #### [Smoke Testing](https://configcat.com/docs/glossary/smoke-testing.md)[​](#smoke-testing "Direct link to smoke-testing") Smoke testing is a type of testing done early in the software development process to confirm that the most critical features of an application are functioning correctly. #### [Soak Testing](https://configcat.com/soak-testing/)[​](#soak-testing "Direct link to soak-testing") Soak testing is a type of non-functional testing that assesses a software application's performance under a high volume of load over an extended period of time. #### [Software Development Life Cycle](https://configcat.com/software-development-lifecycle/)[​](#software-development-life-cycle "Direct link to software-development-life-cycle") The Software Development Life Cycle (SDLC) is a systematic approach aimed at producing high-quality, low-cost software efficiently and within a shorter timeframe. #### [Software as a Service](https://configcat.com/feature-flag-saas/)[​](#software-as-a-service "Direct link to software-as-a-service") Software as a Service (SaaS) is a cloud-based delivery model where applications are hosted and maintained by a service provider and accessed by users over the internet, typically on a subscription basis. #### [Staging Environment](https://configcat.com/docs/glossary/what-is-a-staging-environment.md)[​](#staging-environment "Direct link to staging-environment") A staging environment is a dry run for your code under the closest possible parameters to its real-world application. It is a near-perfect replica of the servers, infrastructure, architecture, and application of the actual production environment your code will run in. The key difference is that it is completely walled off from the front-facing actual environment. ## T[​](#t "Direct link to T") #### [Testing in Production](https://configcat.com/testing-in-production/)[​](#testing-in-production "Direct link to testing-in-production") Testing in production is the practice of evaluating software in its live environment, with real users and real-world conditions. Unlike traditional testing in controlled settings, this approach exposes the software to actual usage scenarios, uncovering issues that may be missed otherwise. However, it requires vigilant monitoring and quick problem resolution to minimize user impact. #### [Type I and Type II Errors](https://configcat.com/docs/glossary/type-i-and-type-ii-errors.md)[​](#type-i-and-type-ii-errors "Direct link to type-i-and-type-ii-errors") A Type I error occurs when the null hypothesis is incorrectly rejected, even though it is actually true. A Type II error occurs when the null hypothesis is wrongly not rejected while it is actually false. #### [Trunk-Based Development](https://configcat.com/trunk-based-development/)[​](#trunk-based-development "Direct link to trunk-based-development") Trunk-based development is a version control technique where developers regularly merge small updates into a central "trunk" or main branch. ## U[​](#u "Direct link to U") #### [User Acceptance Testing](https://configcat.com/user-acceptance-testing/)[​](#user-acceptance-testing "Direct link to user-acceptance-testing") User Acceptance Testing (UAT) is a stage in software development where the software is tested in a simulated real-world environment by its intended users or business representatives. ## V[​](#v "Direct link to V") #### [Version Control](https://configcat.com/docs/glossary/version-control.md)[​](#version-control "Direct link to version-control") Version control, also referred to as source control or revision control, is a crucial software development practice that tracks and manages changes to code and other files, and is closely linked to source code management. ## W[​](#w "Direct link to W") ## X[​](#x "Direct link to X") ## Y[​](#y "Direct link to Y") ## Z[​](#z "Direct link to Z") --- # Source: https://configcat.com/docs/sdk-reference/openfeature/go.md # Source: https://configcat.com/docs/sdk-reference/go.md # Go SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/go-sdk.svg?style=social)](https://github.com/configcat/go-sdk/stargazers) [![Build Status](https://github.com/configcat/go-sdk/actions/workflows/go-ci.yml/badge.svg?branch=v9)](https://github.com/configcat/go-sdk/actions/workflows/go-ci.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/configcat/go-sdk/v9)](https://goreportcard.com/report/github.com/configcat/go-sdk/v9) [![GoDoc](https://godoc.org/github.com/configcat/go-sdk?status.svg)](https://pkg.go.dev/github.com/configcat/go-sdk/v9) [![Sonar Coverage](https://img.shields.io/sonar/coverage/configcat_go-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_go-sdk) [![Sonar Quality Gate](https://img.shields.io/sonar/quality_gate/configcat_go-sdk?logo=sonarcloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_go-sdk) [ConfigCat Go SDK on GitHub](https://github.com/configcat/go-sdk) ## Getting Started[​](#getting-started "Direct link to Getting Started") ### 1. Get the SDK with `go`[​](#1-get-the-sdk-with-go "Direct link to 1-get-the-sdk-with-go") ```bash go get github.com/configcat/go-sdk/v9 ``` ### 2. Import the ConfigCat package[​](#2-import-the-configcat-package "Direct link to 2. Import the ConfigCat package") ```go import "github.com/configcat/go-sdk/v9" ``` ### 3. Create the *ConfigCat* client with your *SDK Key*[​](#3-create-the-configcat-client-with-your-sdk-key "Direct link to 3-create-the-configcat-client-with-your-sdk-key") ```go client := configcat.NewClient("#YOUR-SDK-KEY#") ``` ### 4. Get your setting value[​](#4-get-your-setting-value "Direct link to 4. Get your setting value") ```go isMyAwesomeFeatureEnabled := client.GetBoolValue("isMyAwesomeFeatureEnabled", false, nil) if isMyAwesomeFeatureEnabled { doTheNewThing() } else { doTheOldThing() } ``` ### 5. Stop *ConfigCat* client[​](#5-stop-configcat-client "Direct link to 5-stop-configcat-client") You can safely shut down the client instance and release all associated resources on application exit. ```go client.Close() ``` ## Creating the *ConfigCat Client*[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `configcat.NewClient()` returns a client with default options. | Arguments | Description | | --------- | ----------------------------------------------------------------------------------------- | | `sdkKey` | SDK Key to access your feature flags and settings. Get it from the *ConfigCat Dashboard*. | ### Custom client options[​](#custom-client-options "Direct link to Custom client options") `configcat.NewCustomClient(options)` returns a customized client. The `options` parameter is a structure which contains the optional properties. Available optional properties: | Properties | Type | Description | | ------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `SDKKey` | `string` | SDK Key to access your feature flags and settings. Get it from the *ConfigCat Dashboard*. | | `DataGovernance` | `configcat.DataGovernance` | Defaults to `Global`. Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `Global`, `EuOnly`. | | `BaseUrl` | `string` | Sets the CDN base url (forward proxy, dedicated subscription) from where the sdk will download the configurations. | | `Cache` | `ConfigCache` | Sets a custom cache implementation for the client. [See below](#custom-cache). | | `NoWaitForRefresh` | `bool` | Defaults to `false`. When it's `true` the typed get methods (`Get[TYPE]Value()`) will never wait for a configuration refresh to complete before returning. When it's `false` and `PollingMode` is `AutoPoll`, the first request may block, when `PollingMode` is `Lazy`, any request may block. | | `HttpTimeout` | `time.Duration` | Sets the maximum wait time for a HTTP response. [More about the HTTP timeout](#http-timeout) | | `Transport` | `http.RoundTripper` | Sets the transport options for the underlying HTTP calls. | | `Logger` | `configcat.Logger` | Sets the `Logger` implementation used by the SDK for logging. [More about logging](#logging) | | `LogLevel` | `configcat.LogLevel` | Sets the logging verbosity. [More about logging](#logging) | | `PollingMode` | `configcat.PollingMode` | Defaults to `AutoPoll`. Sets the polling mode for the client. [More about polling modes](#polling-modes). | | `PollInterval` | `time.Duration` | Sets after how much time a configuration is considered stale. When `PollingMode` is `AutoPoll` this value is used as the polling rate. | | `FlagOverrides` | `*configcat.FlagOverrides` | Sets the local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | `DefaultUser` | `configcat.User` | Sets the default user. [More about default user](#default-user). | | `Offline` | `bool` | Defaults to `false`. Indicates whether the SDK should be initialized in offline mode. [More about offline mode](#online--offline-mode). | | `Hooks` | `*configcat.Hooks` | Used to subscribe events that the SDK sends in specific scenarios. [More about hooks](#hooks). | Then you can pass it to the `NewCustomClient()` method: ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", PollingMode: configcat.Manual, Logger: configcat.DefaultLogger(configcat.LogLevelInfo)}) ``` caution We strongly recommend you to use the *ConfigCat Client* as a Singleton object in your application. If you want to use multiple SDK Keys in the same application, create only one *ConfigCat Client* per SDK Key. ## Anatomy of `Get[TYPE]Value()`[​](#anatomy-of-gettypevalue "Direct link to anatomy-of-gettypevalue") All feature flag evaluator methods share the same signature, they only differ in their served value type. `GetBoolValue()` is for evaluating feature flags, `GetIntValue()` and `GetFloatValue()` are for numeric and `GetStringValue()` is for textual settings. | Parameters | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `key` | Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | This value will be returned in case of an error. | | `user` | *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```go boolValue := client.GetBoolValue( "keyOfMyBoolSetting", // Setting Key false, // Default value &configcat.UserData{Identifier: "#UNIQUE-USER-IDENTIFIER#"} // User Object ) ``` ```go intValue := client.GetIntValue( "keyOfMyIntSetting", // Setting Key 0, // Default value &configcat.UserData{Identifier: "#UNIQUE-USER-IDENTIFIER#"} // User Object ) ``` ## Anatomy of `Get[TYPE]ValueDetails()`[​](#anatomy-of-gettypevaluedetails "Direct link to anatomy-of-gettypevaluedetails") `GetValueDetails()` is similar to `GetValue()` but instead of returning the evaluated value only, it gives more detailed information about the evaluation result. | Parameters | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `key` | Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | This value will be returned in case of an error. | | `user` | *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```go details := client.GetBoolValueDetails( "keyOfMyBoolSetting", // Setting Key false, // Default value &configcat.UserData{Identifier: "#UNIQUE-USER-IDENTIFIER#"} // User Object ) ``` ```go details := client.GetIntValueDetails( "keyOfMyIntSetting", // Setting Key 0, // Default value &configcat.UserData{Identifier: "#UNIQUE-USER-IDENTIFIER#"} // User Object ) ``` The `details` result contains the following information: | Field | Type | Description | | ------------------------------ | ------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `Value` | `bool` / `string` / `int` / `float64` | The evaluated value of the feature flag or setting. | | `Data.Key` | `string` | The key of the evaluated feature flag or setting. | | `Data.IsDefaultValue` | `bool` | True when the default value passed to `Get[TYPE]ValueDetails()` is returned due to an error. | | `Data.Error` | `error` | In case of an error, this field contains the error message. | | `Data.User` | `User` | The User Object that was used for evaluation. | | `Data.MatchedPercentageOption` | `*PercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `Data.MatchedTargetingRule` | `*TargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `Data.FetchTime` | `time.Time` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. ```go user = &configcat.UserData{Identifier: "#UNIQUE-USER-IDENTIFIER#"} ``` ```go user = &configcat.UserData{Identifier: "john@example.com"} ``` ### Customized User Object creation[​](#customized-user-object-creation "Direct link to Customized User Object creation") | Arguments | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `Identifier` | Unique identifier of a user in your application. Can be any value, even an email address. | | `Email` | Optional parameter for easier Targeting Rule definitions. | | `Country` | Optional parameter for easier Targeting Rule definitions. | | `Custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. e.g. User role, Subscription type. | ```go custom := map[string]interface{} custom["SubscriptionType"] = "Pro" custom["UserRole"] = "Admin" user := &configcat.UserData{Identifier: "#UNIQUE-USER-IDENTIFIER#", Email: "john@example.com", Company: "United Kingdom", Custom: custom} ``` The `Custom` dictionary also allows attribute values other than `string` values: ```go registeredAt, _ := time.Parse(time.DateTime, "2023-11-22 12:34:56") custom := map[string]interface{} custom["Rating"] = 4.5 custom["RegisteredAt"] = registeredAt custom["Roles"] = []string{"Role1","Role2"} user := &configcat.UserData{Identifier: "#UNIQUE-USER-IDENTIFIER#", Custom: custom} ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (`EQUALS`, `IS_ONE_OF`, etc.) * accept `string` or `[]byte` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (`IS_ONE_OF_SEMVER`, `LESS_THAN_SEMVER`, `GREATER_THAN_SEMVER`, etc.) * accept `string` or `[]byte` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (`EQUALS_NUMBER`, `LESS_THAN_NUMBER`, `GREATER_THAN_OR_EQUAL_NUMBER`, etc.) * accept `float64` values and all other numeric values which can safely be converted to `float64`, * accept `string` or `[]byte` values containing a properly formatted, valid `float64` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (`BEFORE_DATETIME` / `AFTER_DATETIME`) * accept `time.Time` values, which are automatically converted to a second-based Unix timestamp (`time.Time` values with naive timezone are considered to be in UTC), * accept `float64` values representing a second-based Unix timestamp and all other numeric values which can safely be converted to `float64`, * accept `string` or `[]byte` values containing a properly formatted, valid `float64` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (`ARRAY_CONTAINS_ANY_OF` / `ARRAY_NOT_CONTAINS_ANY_OF`) * accept arrays of `string` (`[]string`), * accept `string` or `[]byte` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Other options to create a User Object[​](#other-options-to-create-a-user-object "Direct link to Other options to create a User Object") 1. Using a simple `map[string]interface{}`. In this case the passed map is used for looking up the user attributes. 2. Using a custom `struct`. The *ConfigCat SDK* uses reflection to determine what attributes are available on the passed type. You can either implement the `UserAttributes` interface - which's `GetAttribute(string) interface{}` method will be used to retrieve the attributes - or use a pointer to a `struct` which's public fields are treated as user attributes. If a field's type is `map[string]interface{}`, the map is used to look up any custom attribute not found directly in the struct. There should be at most one of these fields. Otherwise, a field type must be a numeric type, a `string`, a `[]byte`, a `[]string` or a `time.Time`. ### Default user[​](#default-user "Direct link to Default user") There's an option to set a default User Object that will be used at feature flag and setting evaluation. It can be useful when your application has a single user only, or rarely switches users. You can set the default User Object on SDK initialization: ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", DefaultUser: &configcat.UserData{Identifier: "#UNIQUE-USER-IDENTIFIER#"}}) ``` Whenever the `Get[TYPE]Value()`, `Get[TYPE]ValueDetails()`, `GetAllValues()`, or `GetAllValueDetails()` methods are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", DefaultUser: &configcat.UserData{Identifier: "john@example.com"}}) // The default user will be used at the evaluation process. value := client.GetBoolValue("keyOfMyBoolSetting", false, nil) ``` When the `user` parameter is specified on the requesting method, it takes precedence over the default user. ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", DefaultUser: &configcat.UserData{Identifier: "john@example.com"}}) otherUser = &configcat.UserData{Identifier: "brian@example.com"} // otherUser will be used at the evaluation process. value := client.GetBoolValue("keyOfMyBoolSetting", false, otherUser) ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `GetValue()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle.
[More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the the `PollInterval` option parameter of the *ConfigCat Client* to change the polling interval. ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", PollingMode: configcat.AutoPoll, PollInterval: time.Second * 120 /* polling interval in seconds */}) ``` ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `GetBoolValue()`, `GetIntValue()`, `GetFloatValue()` or `GetStringValue()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case, when the `NoWaitForRefresh` option is `false` the new setting value will be returned right after the cache update. When it's set to `true` the setting value retrievals will not wait for the downloads and they will return immediately with the previous setting value. Use the `PollInterval` option parameter of the *ConfigCat Client* to set the cache TTL. ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", PollingMode: configcat.Lazy, PollInterval: time.Second * 120 /* cache TTL in seconds */}) ``` ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `Refresh()` is your application's responsibility. ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", PollingMode: configcat.Manual}) client.Refresh() ``` > The setting value retrieval methods will return `defaultValue` if the cache is empty. Call `Refresh()` to update the cache. ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `OnConfigChanged()`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `OnFlagEvaluated(EvaluationDetails)`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`Get[TYPE]ValueDetails()`](#anatomy-of-gettypevaluedetails). * `OnError(error)`: This event is emitted when an error occurs within the client. You can subscribe to these events on SDK initialization: ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", Hooks: &configcat.Hooks{OnFlagEvaluated: func(details *configcat.EvaluationDetails) { /* handle the event */ }}}) ``` ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases when you'd want to prevent the SDK from making HTTP calls, you can put it in offline mode: ```go client.SetOffline() ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To put the SDK back in online mode, you can do the following: ```go client.SetOnline() ``` > With `client.IsOffline()` you can check whether the SDK is in offline mode. ## `GetAllKeys()`[​](#getallkeys "Direct link to getallkeys") You can get the keys for all available feature flags and settings by calling the `GetAllKeys()` method of the *ConfigCat Client*. ```go client := configcat.NewClient("#YOUR-SDK-KEY#") keys := client.GetAllKeys() ``` ## `GetAllValues()`[​](#getallvalues "Direct link to getallvalues") Evaluates and returns the values of all feature flags and settings. Passing a User Object is optional. ```go client := configcat.NewClient("#YOUR-SDK-KEY#") settingValues := client.GetAllValues(nil) // invoke with User Object user := &configcat.UserData{Identifier: "#UNIQUE-USER-IDENTIFIER#"} settingValuesTargeting := client.GetAllValues(user) ``` ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can load your feature flag & setting overrides from a file or from a simple `map[string]interface{}` structure. ### JSON File[​](#json-file "Direct link to JSON File") The SDK can load your feature flag & setting overrides from a file. ```go client := configcat.NewCustomClient(configcat.Config{ SDKKey: "localhost", FlagOverrides: &configcat.FlagOverrides{ FilePath: "path/to/local_flags.json", Behavior: configcat.LocalOnly, }, }) ``` #### JSON File Structure[​](#json-file-structure "Direct link to JSON File Structure") The SDK supports 2 types of JSON structures to describe feature flags & settings. ##### 1. Simple (key-value) structure[​](#1-simple-key-value-structure "Direct link to 1. Simple (key-value) structure") ```json { "flags": { "enabledFeature": true, "disabledFeature": false, "intSetting": 5, "doubleSetting": 3.14, "stringSetting": "test" } } ``` ##### 2. Complex (full-featured) structure[​](#2-complex-full-featured-structure "Direct link to 2. Complex (full-featured) structure") This is the same format that the SDK downloads from the ConfigCat CDN. It allows the usage of all features that are available on the ConfigCat Dashboard. You can download your current config JSON from ConfigCat's CDN and use it as a baseline. A convenient way to get the config JSON for a specific SDK Key is to install the [ConfigCat CLI](https://github.com/configcat/cli) tool and execute the following command: ```bash configcat config-json get -f v6 -p {YOUR-SDK-KEY} > config.json ``` (Depending on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings, you may need to add the `--eu` switch.) Alternatively, you can download the config JSON manually, based on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings: * GLOBAL: `https://cdn-global.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` * EU: `https://cdn-eu.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` ```json { "p": { // hash salt, required only when confidential text comparator(s) are used "s": "80xCU/SlDz1lCiWFaxIBjyJeJecWjq46T4eu6GtozkM=" }, "s": [ // array of segments { "n": "Beta Users", // segment name "r": [ // array of User Conditions (there is a logical AND relation between the elements) { "a": "Email", // comparison attribute "c": 0, // comparator (see below) "l": [ // comparison value (see below) "john@example.com", "jane@example.com" ] } ] } ], "f": { // key-value map of feature flags & settings "isFeatureEnabled": { // key of a particular flag / setting "t": 0, // setting type, possible values: // 0 -> on/off setting (feature flag) // 1 -> text setting // 2 -> whole number setting // 3 -> decimal number setting "r": [ // array of Targeting Rules (there is a logical OR relation between the elements) { "c": [ // array of conditions (there is a logical AND relation between the elements) { "u": { // User Condition "a": "Email", // comparison attribute "c": 2, // comparator, possible values and required comparison value types: // 0 -> IS ONE OF (cleartext) + string array comparison value ("l") // 1 -> IS NOT ONE OF (cleartext) + string array comparison value ("l") // 2 -> CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 3 -> NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 4 -> IS ONE OF (semver) + semver string array comparison value ("l") // 5 -> IS NOT ONE OF (semver) + semver string array comparison value ("l") // 6 -> < (semver) + semver string comparison value ("s") // 7 -> <= (semver + semver string comparison value ("s") // 8 -> > (semver) + semver string comparison value ("s") // 9 -> >= (semver + semver string comparison value ("s") // 10 -> = (number) + number comparison value ("d") // 11 -> <> (number + number comparison value ("d") // 12 -> < (number) + number comparison value ("d") // 13 -> <= (number + number comparison value ("d") // 14 -> > (number) + number comparison value ("d") // 15 -> >= (number) + number comparison value ("d") // 16 -> IS ONE OF (hashed) + string array comparison value ("l") // 17 -> IS NOT ONE OF (hashed) + string array comparison value ("l") // 18 -> BEFORE (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 19 -> AFTER (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 20 -> EQUALS (hashed) + string comparison value ("s") // 21 -> NOT EQUALS (hashed) + string comparison value ("s") // 22 -> STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 23 -> NOT STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 24 -> ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 25 -> NOT ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 26 -> ARRAY CONTAINS ANY OF (hashed) + string array comparison value ("l") // 27 -> ARRAY NOT CONTAINS ANY OF (hashed) + string array comparison value ("l") // 28 -> EQUALS (cleartext) + string comparison value ("s") // 29 -> NOT EQUALS (cleartext) + string comparison value ("s") // 30 -> STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 31 -> NOT STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 32 -> ENDS WITH ANY OF (cleartext) + string array comparison value ("l") // 33 -> NOT ENDS WITH ANY OF (cleartext + string array comparison value ("l") // 34 -> ARRAY CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 35 -> ARRAY NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") "l": [ // comparison value - depending on the comparator, another type of value may need // to be specified (see above): // "s": string // "d": number "@example.com" ] } }, { "p": { // Flag Condition (Prerequisite) "f": "mainIntFlag", // key of prerequisite flag "c": 0, // comparator, possible values: 0 -> EQUALS, 1 -> NOT EQUALS "v": { // comparison value (value's type must match the prerequisite flag's type) "i": 42 } } }, { "s": { // Segment Condition "s": 0, // segment index, a valid index into the top-level segment array ("s") "c": 1 // comparator, possible values: 0 -> IS IN SEGMENT, 1 -> IS NOT IN SEGMENT } } ], "s": { // alternatively, an array of Percentage Options ("p", see below) can also be specified "v": { // the value served when the rule is selected during evaluation "b": true }, "i": "bcfb84a7" } } ], "p": [ // array of Percentage Options { "p": 10, // % value "v": { // the value served when the Percentage Option is selected during evaluation "b": true }, "i": "bcfb84a7" }, { "p": 90, "v": { "b": false }, "i": "bddac6ae" } ], "v": { // fallback value, served when none of the Targeting Rules match, // no Percentage Options are defined or evaluation of these is not possible "b": false // depending on the setting type, another type of value may need to be specified: // text setting -> "s": string // whole number setting -> "i": number // decimal number setting -> "d": number }, "i": "430bded3" // variation id (for analytical purposes) } } } ``` For a more comprehensive specification of the config JSON v6 format, you may refer to [this JSON schema document](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ### Map[​](#map "Direct link to Map") You can set up the SDK to load your feature flag & setting overrides from a `map[string]interface{}`. ```go client := configcat.NewCustomClient(configcat.Config{ SDKKey: "localhost", FlagOverrides: &configcat.FlagOverrides{ Values: map[string]interface{}{ "enabledFeature": true, "disabledFeature": false, "intSetting": 5, "doubleSetting": 3.14, "stringSetting": "test", }, Behavior: configcat.LocalOnly, }, }) ``` ## Snapshots[​](#snapshots "Direct link to Snapshots") A `Snapshot` represents an immutable state of the given User's current setting values. Because of the immutability they are suitable for sharing between components that rely more on a consistent data state rather than maintaining their own states with individual get setting value calls. Snapshot creation: ```go snapshot := client.Snapshot(user) ``` You can define setting descriptors that could be also shared between those components and used for evaluation: ```go boolSettingDescriptor := configcat.Bool("keyOfMyBoolSetting" /* Setting Key */, false /* Default value */) ``` Then you can use the descriptor to retrieve the setting's value from a snapshot: ```go boolValue := boolSettingDescriptor.Get(snapshot) ``` ## Custom Cache[​](#custom-cache "Direct link to Custom Cache") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`ConfigCache`](https://github.com/configcat/go-sdk/blob/v9/configcat_client.go#L106) interface. ```go type CustomCache struct { } func (cache *CustomCache) Get(ctx context.Context, key string) ([]byte, error) { // here you have to return with the cached value } func (cache *CustomCache) Set(ctx context.Context, key string, value []byte) error { // here you have to store the new value in the cache } ``` Then use your custom cache implementation: ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", Cache: CustomCache{}}) ``` info The Go SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Force refresh[​](#force-refresh "Direct link to Force refresh") Call the `Refresh()` method on the client to download the latest config JSON and update the cache. You can also use the `RefreshIfOlder()` variant when you want to add expiration time windows for local cache updates. ## HTTP Proxy[​](#http-proxy "Direct link to HTTP Proxy") You can use the `Transport` config option to set up http transport related (like proxy) settings for the http client used by the SDK: ```go proxyURL, _ := url.Parse("") client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", Transport: &http.Transport{ Proxy: http.ProxyURL(proxyURL), } }) ``` ## HTTP Timeout[​](#http-timeout "Direct link to HTTP Timeout") You can set the maximum wait time for a ConfigCat HTTP response. ```go client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", HTTPTimeout: time.Second * 10 }) ``` ## Logging[​](#logging "Direct link to Logging") The default logger implementation used by the SDK is based on the `log` package, but you have the option to override it with your logger via the `Logger` config option. It only has to satisfy the [Logger](https://github.com/configcat/go-sdk/blob/v9/logger.go) interface: ```go type Logger interface { Debugf(format string, args ...interface{}) Infof(format string, args ...interface{}) Warnf(format string, args ...interface{}) Errorf(format string, args ...interface{}) } ``` ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```go import { "github.com/configcat/go-sdk/v9" } client := configcat.NewCustomClient(configcat.Config{ SDKKey: "#YOUR-SDK-KEY#", LogLevel: configcat.LogLevelInfo}) ``` Available log levels: | Level | Description | | --------------- | ------------------------------------------------------- | | `LogLevelNone` | Turns off logging. | | `LogLevelError` | Only error level events are logged. | | `LogLevelWarn` | Default, Errors and Warnings are logged. | | `LogLevelInfo` | Errors, Warnings and feature flag evaluation is logged. | | `LogLevelDebug` | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash [ConfigCat] 2024/01/08 13:27:56 INFO: [5000] Evaluating 'isPOCFeatureEnabled' for User '&configcat.UserData{Identifier:"##SOME-USER-IDENTIFICATION##", Email:"configcat@example.com", Country:"", Custom:map[string]interface{}(nil)}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] => false, skipping the remaining AND conditions THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] => true THEN 'true' => MATCH, applying rule Returning 'true'. ``` ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [Sample Console App](https://github.com/configcat/go-sdk/tree/master/samples/console) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat Go SDK's repository on GitHub](https://github.com/configcat/go-sdk) --- # Source: https://configcat.com/docs/integrations/google-analytics.md # Google Analytics - Send feature flag analytics to Google Analytics Copy page ## Sending Feature Flag Evaluation Analytics to Google Analytics[​](#sending-feature-flag-evaluation-analytics-to-google-analytics "Direct link to Sending Feature Flag Evaluation Analytics to Google Analytics") Integrate your feature flag evaluations with [Google Analytics experiments](https://developers.google.com/analytics/devguides/collection/ga4/integration) to gain advanced insights into how your features are used and to assess the outcomes of A/B tests. ### Setup Instructions[​](#setup-instructions "Direct link to Setup Instructions") 1. **Install SDKs:** Add both the ConfigCat SDK and the Google Analytics SDK to your application. 2. **Configure SDKs:** * **ConfigCat SDK:** Initialize with your ConfigCat SDK key. * **Google Analytics SDK:** Set up with your Google Analytics measurement ID. 3. **Integrate Feature Flag Evaluations:** * During the initialization of the ConfigCat SDK, subscribe to the `flagEvaluated` hook. * Send feature flag evaluation data to Google Analytics using the `experience_impression` event name. Include the following parameter: * `exp_variant_string`: Construct this string to include the tool name (`configcat`), the feature flag's key, and its value. For example: `configcat-isMyAwesomeFeatureEnabled-true`. Code samples: * JavaScript, SSR * React * Other languages ```js const configCatClient = configcat.getClient("#YOUR_SDK_KEY", PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', evaluationDetails => { const variant = "configcat-" + evaluationDetails.key + "-" + evaluationDetails.value; gtag('event', 'experience_impression', { 'exp_variant_string': variant, 'variation_id': evaluationDetails.variationId }); }), }); ``` ```tsx hooks.on('flagEvaluated', evaluationDetails => { const variant = "configcat-" + evaluationDetails.key + "-" + evaluationDetails.value; gtag('event', 'experience_impression', { 'exp_variant_string': variant, 'variation_id': evaluationDetails.variationId }); }), }} > ``` While our documentation primarily provides code examples for JavaScript-based SDKs, you can integrate with other languages by utilizing the [Send Measurement Protocol events to Google Analytics](https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events?client_type=gtag) endpoint. Here's how to set it up: 1. **Subscribe to the FlagEvaluated hook** in the ConfigCat SDK. 2. **Send an event to Google Analytics** using the `experience_impression` event name. Include the following event properties: * `exp_variant_string`: Format this string as `configcat--`. For example, `configcat-isMyAwesomeFeatureEnabled-true`. * `variant_id`: The evaluated feature flag's value or the variationId from the FlagEvaluated hook's EvaluationDetails. * `user_id` (optional): If tracking in a backend component and utilizing the user\_id feature in Google Analytics, include this property to identify your user. Use the Identifier property from the User object in the FlagEvaluated hook, or another value that best describes your user. note For Text feature flags with lengthy values (e.g., JSON), send the `variationId` instead of the `value` as the `exp_variant_string` to Google Analytics. The `variationId` is a hashed version of the feature flag value, accessible on the ConfigCat Dashboard by enabling the *Show VariationIDs to support A/B testing* setting. Learn more [here](https://app.configcat.com/product/preferences). 4. **Deploy your application** and wait for feature flag evaluations to occur. This process might take 1-2 days for the `experience_impression` events to populate in Google Analytics. 5. **Define an audience** in Google Analytics using the `exp_variant_string` parameter with the same values you used in your events (e.g. `configcat-isMyAwesomeFeatureEnabled-true`) by following the guide [here](https://support.google.com/analytics/answer/9267572). This allows you to leverage feature flag evaluation events effectively. ### Example audiences reports[​](#example-audiences-reports "Direct link to Example audiences reports") ![Google Analytics Audience report](/docs/assets/googleanalytics/audiences.png) ### Useful resources[​](#useful-resources "Direct link to Useful resources") * [A/B Testing with ConfigCat and Google Analytics - Blog post](https://configcat.com/blog/2024/09/20/ab-testing-configcat-google-analytics/) * [A/B Testing with ConfigCat and Google Analytics - Sample app](https://github.com/configcat-labs/configcat-google-analytics-integration-sample) * [Creating Audiences in Google Analytics - Google documentation](https://support.google.com/analytics/answer/9267572) --- # Source: https://configcat.com/docs/advanced/team-management/saml/identity-providers/google.md # Google Identity Provider Copy page Connect ConfigCat with Google via SAML. ## Introduction[​](#introduction "Direct link to Introduction") Each SSO Identity Provider requires specific information to configure a SAML integration. The following guide will walk you through how you can connect ConfigCat with Google as a SAML Identity Provider. ## 1. Create a SAML Application in Google[​](#1-create-a-saml-application-in-google "Direct link to 1. Create a SAML Application in Google") * Log in to [Google Admin console](https://admin.google.com/), select `Apps` from the side menu, then select `Web and mobile apps`. ![Google applications](/docs/assets/saml/google/applications.png) * Click `Add App`, then select `Add custom SAML app`. ![Google add SAML app](/docs/assets/saml/google/add_saml_app.png) * Enter a descriptive `App name`, then click `CONTINUE`. ![Google SAML app name](/docs/assets/saml/google/app_name.png) The next step will guide you on how to configure ConfigCat with appearing information. ## 2. Configure ConfigCat with SAML Details from Google[​](#2-configure-configcat-with-saml-details-from-google "Direct link to 2. Configure ConfigCat with SAML Details from Google") * Copy the value of `SSO URL` and `Certificate` fields and save them for further use. ![Google SSO url](/docs/assets/saml/google/meta_url_cert.png) * Open your organization's authentication settings on the [ConfigCat Dashboard](https://app.configcat.com/organization/authentication). ![ConfigCat authentication settings](/docs/assets/saml/dashboard/authentication.png) * Click `ADD SAML IDENTITY PROVIDER`. ![ConfigCat Add Identity Provider](/docs/assets/saml/dashboard/add_idp.png) * Give a name for your Identity Provider, and click `Create`. ![ConfigCat Name Identity Provider](/docs/assets/saml/dashboard/google_name.png) * Select the `3. Set up ConfigCat` step, click `Manual Configuration`, then paste the copied values into the appearing fields. ![ConfigCat manual configuration](/docs/assets/saml/google/cc_manual_new.png) * Click `CONTINUE` on the Google App configuration. ![Google SSO app configuration](/docs/assets/saml/google/meta_continue.png) The next step will guide you on how to configure the Google App with details provided by ConfigCat. ## 3. Configure the Google Application with Service Provider Details from ConfigCat[​](#3-configure-the-google-application-with-service-provider-details-from-configcat "Direct link to 3. Configure the Google Application with Service Provider Details from ConfigCat") * Select `2. Set up your Identity Provider` step on the ConfigCat configuration dialog, and copy the following values to the Google App. * `Entity ID` -> `Entity ID` * `Assertion Consumer Service` -> `ACS URL` ![Google acs url](/docs/assets/saml/dashboard/acs_entity_id_2.png) * Make sure the `Signed response` option is checked. * Select `EMAIL` as `Name ID format`. * Select `Basic Information > Primary email` as `Name ID`. * Click `CONTINUE`. ![Google meta data](/docs/assets/saml/google/google_acs_eid.png) * Click `FINISH`. ![Google attribute mapping](/docs/assets/saml/google/attribute_mapping.png) ## 4. Select Trusted Domains on the SAML Configuration Dialog[​](#4-select-trusted-domains-on-the-saml-configuration-dialog "Direct link to 4. Select Trusted Domains on the SAML Configuration Dialog") * Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) * Click `Save`. ## 5. Give Users Access to the Application[​](#5-give-users-access-to-the-application "Direct link to 5. Give Users Access to the Application") * Click on `View details` under the `User access` section. ![Google user access](/docs/assets/saml/google/user_access.png) * Select `ON for everyone`, then click `SAVE`. ![Google ON for everyone](/docs/assets/saml/google/on_for_everyone.png) ## 6. Sign In[​](#6-sign-in "Direct link to 6. Sign In") * Go to the [ConfigCat Log In](https://app.configcat.com) page, and click `COMPANY ACCOUNT - SAML`. ![ConfigCat SAML login](/docs/assets/saml/dashboard/saml_login.png) * Sign in with your company email address used in Google. ![ConfigCat SAML company login](/docs/assets/saml/dashboard/company_email.png) * ConfigCat will redirect you to Google's sign in page. Type your credentials, and sign in. ![Google SSO login](/docs/assets/saml/google/login.png) * You should be redirected to ConfigCat signed in with your company account. ## 7. Next Steps[​](#7-next-steps "Direct link to 7. Next Steps") * Configure the [auto-assignment of users](https://configcat.com/docs/advanced/team-management/auto-assign-users.md). --- # Source: https://configcat.com/docs/api/category/scim/groups.md ## [📄️ Get Groups](https://configcat.com/docs/api/scim/get-groups.md) [This endpoint returns a list of groups.](https://configcat.com/docs/api/scim/get-groups.md) --- # Source: https://configcat.com/docs/advanced/proxy/grpc.md # gRPC Copy page The ConfigCat Proxy can communicate over [gRPC](https://grpc.io), an open-source, high-performance RPC framework with client support in several languages. To establish gRPC connections, you'll need the protobuf and the gRPC [service definition](https://github.com/configcat/configcat-proxy/blob/main/grpc/proto/flag_service.proto). It's required to generate clients with [`protoc`](https://protobuf.dev/downloads/) for your [desired platform](https://protobuf.dev/reference/). flag\_service.proto ```protobuf syntax = "proto3"; option go_package = "github.com/configcat/configcat-proxy/grpc/proto"; package configcat; import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; // Service that contains feature flag evaluation procedures. service FlagService { // Stream for getting notified when a feature flag's value changes. rpc EvalFlagStream(EvalRequest) returns (stream EvalResponse) {} // Stream for getting notified when any feature flag's value changes. rpc EvalAllFlagsStream(EvalRequest) returns (stream EvalAllResponse) {} // Evaluates a feature flag. rpc EvalFlag(EvalRequest) returns (EvalResponse) {} // Evaluates each feature flag. rpc EvalAllFlags(EvalRequest) returns (EvalAllResponse) {} // Requests the keys of each feature flag. rpc GetKeys(KeysRequest) returns (KeysResponse) {} // Commands the underlying SDK to refresh its evaluation data. rpc Refresh(RefreshRequest) returns (google.protobuf.Empty) {} } // Feature flag evaluation request message. message EvalRequest { // The SDK identifier. Deprecated, the field `target` should be used instead for SDK identification. string sdk_id = 1 [ deprecated = true ]; // The feature flag's key to evaluate. string key = 2; // The user object. map user = 3; // The evaluation request's target. Target target = 4; } // Feature flag evaluation response message. message EvalResponse { // The evaluated value. oneof value { int32 int_value = 1; double double_value = 2; string string_value = 3; bool bool_value = 4; } // The variation ID. string variation_id = 5; } // Response message that contains the evaluation result of each feature flag. message EvalAllResponse { // The evaluated value of each feature flag. map values = 1; } // Request message for getting each available feature flag's key. message KeysRequest { // The SDK identifier. Deprecated, the field `target` should be used instead for SDK identification. string sdk_id = 1 [ deprecated = true ]; // The request's target. Target target = 2; } // Response message that contains each available feature flag's key. message KeysResponse { // The keys of each feature flag. repeated string keys = 1; } // Request message for the given SDK to refresh its evaluation data. message RefreshRequest { // The SDK identifier. Deprecated, the field `target` should be used instead for SDK identification. string sdk_id = 1 [ deprecated = true ]; // The request's target. Target target = 2; } // Defines the possible values that can be set in the `user` map. message UserValue { oneof value { double number_value = 1; string string_value = 2; google.protobuf.Timestamp time_value = 3; StringList string_list_value = 4; } } // Identifies the target of evaluation requests by either an SDK Id or an SDK Key. message Target { oneof identifier { // The SDK Id. string sdk_id = 1; // The SDK key. string sdk_key = 2; } } // Represents a list of strings. message StringList { repeated string values = 1; } ``` info In order to secure the gRPC communication with the Proxy, set up [TLS](https://configcat.com/docs/advanced/proxy/proxy-overview.md#tls). ## Client Usage[​](#client-usage "Direct link to Client Usage") The following example uses a generated Go client, but gRPC clients generated for other languages are working as well. example.go ```go conn, err := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ // Any TLS options }))) if err != nil { panic(err) } defer func() { _ = conn.Close() }() client := proto.NewFlagServiceClient(conn) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() resp, err := client.EvalFlag(ctx, &proto.EvalRequest{ Target: &proto.Target{Identifier: &proto.Target_SdkKey{SdkKey: "#YOUR-SDK-KEY#"}}, // Or with SDK identifier // Target: &proto.Target{Identifier: &proto.Target_SdkId{SdkId: "#SDK-IDENTIFIER#"}}, Key: "", User: map[string]*proto.UserValue{"Identifier": {Value: &proto.UserValue_StringValue{StringValue: ""}}}, }) if err != nil { panic(err) } fmt.Printf("Evaluation result: %v", resp.GetBoolValue()) ``` ## Health Check[​](#health-check "Direct link to Health Check") The Proxy exposes health information over a [standardized health RPC service](https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto). Clients can set `""` as the `service` parameter (or skip specifying it) to get the health status of the gRPC server. Exposing the health check service is configurable and turned on by default. For more details about gRPC health checking, check out the [official documentation](https://grpc.io/docs/guides/health-checking/). ## Server Reflection[​](#server-reflection "Direct link to Server Reflection") The Proxy can expose its protobuf-defined feature flag evaluation API over a [standardized reflection RPC service](https://github.com/grpc/grpc-proto/blob/master/grpc/reflection/v1/reflection.proto), including all types referenced by the request and response messages. Exposing the reflection service is configurable and turned off by default. For more details about gRPC server reflection, check out the [official documentation](https://grpc.io/docs/guides/reflection/). ## Available Options[​](#available-options "Direct link to Available Options") The following gRPC related options are available: * YAML * Environment variables options.yml ```yaml grpc: enabled: port: 50051 server_reflection_enabled: health_check_enabled: keep_alive: max_connection_idle: 15 max_connection_age: 30 max_connection_age_grace: 5 time: 5 timeout: 1 log: level: "" ``` ```shell CONFIGCAT_GRPC_ENABLED= CONFIGCAT_GRPC_PORT=50051 CONFIGCAT_GRPC_HEALTH_CHECK_ENABLED= CONFIGCAT_GRPC_SERVER_REFLECTION_ENABLED= CONFIGCAT_GRPC_KEEP_ALIVE_MAX_CONNECTION_IDLE=15 CONFIGCAT_GRPC_KEEP_ALIVE_MAX_CONNECTION_AGE=30 CONFIGCAT_GRPC_KEEP_ALIVE_MAX_CONNECTION_AGE_GRACE=5 CONFIGCAT_GRPC_KEEP_ALIVE_TIME=5 CONFIGCAT_GRPC_KEEP_ALIVE_TIMEOUT=1 CONFIGCAT_GRPC_LOG_LEVEL="" ``` Here's the explanation for each option: | Option | Default | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | - YAML
- Environment variable```yaml grpc: enabled: ``````shell CONFIGCAT_GRPC_ENABLED= ``` | `true` | Turns the ability to communicate with the Proxy through gRPC on/off. | | - YAML
- Environment variable```yaml grpc: port: 50051 ``````shell CONFIGCAT_GRPC_PORT=50051 ``` | `50051` | The port used for gRPC communication. | | - YAML
- Environment variable```yaml grpc: health_check_enabled: ``````shell CONFIGCAT_GRPC_HEALTH_CHECK_ENABLED= ``` | `true` | Turns the [gRPC health check service](https://grpc.io/docs/guides/health-checking/) on/off. | | - YAML
- Environment variable```yaml grpc: server_reflection_enabled: ``````shell CONFIGCAT_GRPC_SERVER_REFLECTION_ENABLED= ``` | `false` | Turns the [gRPC server reflection](https://grpc.io/docs/guides/reflection/) on/off. | | - YAML
- Environment variable```yaml grpc: keep_alive: max_connection_idle: 15 ``````shell CONFIGCAT_GRPC_KEEP_ALIVE_MAX_CONNECTION_IDLE=15 ``` | `INT_MAX (Infinite)` | Maximum time in seconds that a channel may have no outstanding rpcs, after which the server will close the connection. [More about the gRPC keep-alive](https://grpc.io/docs/guides/keepalive/). | | - YAML
- Environment variable```yaml grpc: keep_alive: max_connection_age: 30 ``````shell CONFIGCAT_GRPC_KEEP_ALIVE_MAX_CONNECTION_AGE=30 ``` | `INT_MAX (Infinite)` | Maximum time in seconds that a channel may exist. [More about the gRPC keep-alive](https://grpc.io/docs/guides/keepalive/). | | - YAML
- Environment variable```yaml grpc: keep_alive: max_connection_age_grace: 5 ``````shell CONFIGCAT_GRPC_KEEP_ALIVE_MAX_CONNECTION_AGE_GRACE=5 ``` | `INT_MAX (Infinite)` | Grace period in seconds after the channel reaches its max age. [More about the gRPC keep-alive](https://grpc.io/docs/guides/keepalive/). | | - YAML
- Environment variable```yaml grpc: keep_alive: time: 5 ``````shell CONFIGCAT_GRPC_KEEP_ALIVE_TIME=5 ``` | `7200` | The interval in seconds between PING frames. [More about the gRPC keep-alive](https://grpc.io/docs/guides/keepalive/). | | - YAML
- Environment variable```yaml grpc: keep_alive: timeout: 1 ``````shell CONFIGCAT_GRPC_KEEP_ALIVE_TIMEOUT=1 ``` | `20` | The timeout in seconds for a PING frame to be acknowledged. If sender does not receive an acknowledgment within this time, it will close the connection. [More about the gRPC keep-alive](https://grpc.io/docs/guides/keepalive/). | | - YAML
- Environment variable```yaml grpc: log: level: "" ``````shell CONFIGCAT_GRPC_LOG_LEVEL="" ``` | `warn` | The verbosity of the gRPC related logs.
Possible values: `error`, `warn`, `info` or `debug`.
When `debug` is set, the Proxy will log each RPC with additional details. | --- # Source: https://configcat.com/docs/index.md ### Basics Familiarize with ConfigCat basics. * [Getting started](https://configcat.com/docs/getting-started.md) * [Main Concepts](https://configcat.com/docs/main-concepts.md) * [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) * [What is a config JSON download?](https://configcat.com/docs/requests.md) * [Network Traffic](https://configcat.com/docs/network-traffic.md) * [Plans, Purchase & Billing](https://configcat.com/docs/purchase.md) * [Organization & Roles](https://configcat.com/docs/organization.md) * [News & Product Updates](https://configcat.com/docs/news.md) * [FAQ](https://configcat.com/docs/faq.md) * [Glossary](https://configcat.com/docs/glossary.md) --- # Source: https://configcat.com/docs/api/reference/integrations.md # Integrations Copy page With these endpoints you can manage your Integrations. * [Datadog](https://configcat.com/docs/integrations/datadog.md) * [Slack](https://configcat.com/docs/integrations/slack.md) * [Amplitude](https://configcat.com/docs/integrations/amplitude.md) * [MixPanel](https://configcat.com/docs/integrations/mixpanel.md) * [Segment](https://configcat.com/docs/integrations/segment.md) * PubNub (work in progress) ## [📄️ List Integrations](https://configcat.com/docs/api/reference/get-integrations.md) [This endpoint returns the list of the Integrations that belongs to the given Product identified by the](https://configcat.com/docs/api/reference/get-integrations.md) ## [📄️ Create Integration](https://configcat.com/docs/api/reference/create-integration.md) [This endpoint creates a new Integration in a specified Product](https://configcat.com/docs/api/reference/create-integration.md) ## [📄️ Get Integration](https://configcat.com/docs/api/reference/get-integration.md) [This endpoint returns the metadata of an Integration](https://configcat.com/docs/api/reference/get-integration.md) ## [📄️ Update Integration](https://configcat.com/docs/api/reference/update-integration.md) [This endpoint updates a Config identified by the \`integrationId\` parameter.](https://configcat.com/docs/api/reference/update-integration.md) ## [📄️ Delete Integration](https://configcat.com/docs/api/reference/delete-integration.md) [This endpoint removes a Integration identified by the \`integrationId\` parameter.](https://configcat.com/docs/api/reference/delete-integration.md) --- # Source: https://configcat.com/docs/integrations/intellij.md # JetBrains/IntelliJ Plugin - Manage your feature flags from JetBrains/IntelliJ IDEs Copy page [ConfigCat's JetBrains/IntelliJ IDE plugin](https://plugins.jetbrains.com/plugin/26096-configcat-feature-flags) to manage feature flags from IDEs. Connect your ConfigCat Product and Config to your JetBrains/IntelliJ IDE. Find your Feature Flag's usages in your code easily. This guide will help you install the JetBrains/IntelliJ IDE Plugin and familiarize you with its usage. ## Feature overview[​](#feature-overview "Direct link to Feature overview") * View your Feature Flags within the IDE. * Create Feature Flags within the IDE. * Open a Feature Flag on the ConfigCat Dashboard. * Find Feature Flag usages in your code. * Copy a Feature Flag's key to the clipboard. * View your Products & Configs. * Create Configs within the IDE. * Open a Config on ConfigCat Dashboard. Your browser does not support the video tag. ## Install plugin[​](#install-plugin "Direct link to Install plugin") ### Install within the IDE from Marketplace[​](#install-within-the-ide-from-marketplace "Direct link to Install within the IDE from Marketplace") 1. In your IDE, open the **File** > **Settings/Preferences** menu. 2. Go to the **Plugin** page and select the **Marketplace** tab. 3. Search for **ConfigCat Feature Flags**. 4. **Install** the plugin. 5. Configure the plugin ([see below](#configure-extension)). ### Install manually within the IDE[​](#install-manually-within-the-ide "Direct link to Install manually within the IDE") 1. Download the latest release from [GitHub](https://github.com/configcat/intellij-plugin/releases/latest) or from [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/26096-configcat-feature-flags). 2. In your IDE, open the **File** > **Settings/Preferences** menu. 3. Go to the **Plugin** page and open the **Gear Icon** menu. 4. Select the **Install plugin from disk...** option. 5. Configure the plugin ([see below](#configure-extension)). ### Compatible IDEs[​](#compatible-ides "Direct link to Compatible IDEs") The plugin is compatible with the following IDEs. Check the plugin [JetBrains Marketplace](https://plugins.jetbrains.com/plugin/26096-configcat-feature-flags) page for the full, detailed compatibility list. * Android Studio * Aqua * CLion * DataGrip * DataSpell * GoLand * IntelliJ IDEA (Community & Ultimate) * MPS * PhpStorm * PyCharm (Community & Professional) * Rider * RubyMine * RustRover * WebStorm * Writerside ## Configure extension[​](#configure-extension "Direct link to Configure extension") ### Authentication[​](#authentication "Direct link to Authentication") 1. Get your API credentials for [ConfigCat Public Management API](https://app.configcat.com/my-account/public-api-credentials). 2. In your IDE, open the **File** > **Settings/Preferences** menu. 3. Search for **ConfigCat Feature Flags** page. 4. Fill out the **Basic auth user name** and **Basic auth password** inputs. Your browser does not support the video tag. ### Advanced[​](#advanced "Direct link to Advanced") This section is for you if you use a dedicated hosted/[on-premise](https://configcat.com/on-premise/) ConfigCat instance. In that case, you can specify your custom ConfigCat URLs in the IDE. 1. In your IDE, open the **File** > **Settings/Preferences** menu. 2. Search for **ConfigCat Feature Flags** page. 3. Fill out the **Public Api Base URL** and **Dashboard Base URL** inputs. * `Public Api Base URL`: the base URL for the ConfigCat Public Management API. Defaults to: . * `Dashboard Base URL`: the base URL for ConfigCat Dashboard. Defaults to: . ## Usage of ConfigCat Feature Flags Plugin[​](#usage-of-configcat-feature-flags-plugin "Direct link to Usage of ConfigCat Feature Flags Plugin") The ConfigCat Feature Flags Tool Window can be opened by clicking the ConfigCat Feature Flags icon on the side of the IDE main window. ### Feature Flags & Settings tab[​](#feature-flags--settings-tab "Direct link to Feature Flags & Settings tab") After you successfully configured your ConfigCat account in the **Settings**, you can use the **Feature Flags & Settings** tab and: * View all of your Products, Configs and Feature Flags. * Create new Configs and Feature Flags. * Open your Configs and Feature Flags on the ConfigCat Dashboard. * Copy a Feature Flag's key to the clipboard. * Find your Feature Flag's usages in your code. Your browser does not support the video tag. #### Create a new Feature Flag[​](#create-a-new-feature-flag "Direct link to Create a new Feature Flag") 1. Select the Config in the tree where you want to create your new flag. 2. Click the **+** button on the action bar to open the **Create Flag** dialog. 3. Select the setting type. 4. Enter the new Feature Flag name. 5. Enter the new Feature Flag key. 6. Add a hint to your Feature Flag (optional). 7. Select **OK** to confirm the Flag creation. #### Copy a Feature Flag's key to the clipboard[​](#copy-a-feature-flags-key-to-the-clipboard "Direct link to Copy a Feature Flag's key to the clipboard") 1. Select the Feature Flag in the tree whose key you want to copy. 2. Click the **Copy** button on the action bar to copy the key to the clipboard. #### Open your Feature Flags on the ConfigCat Dashboard[​](#open-your-feature-flags-on-the-configcat-dashboard "Direct link to Open your Feature Flags on the ConfigCat Dashboard") 1. In the tree, select the Feature Flag you want to open in the Dashboard. 2. Click the **Open Config in ConfigCat Dashboard** button on the action bar to open the Feature Flag in the Dashboard. #### Find your Feature Flag's usages in your code[​](#find-your-feature-flags-usages-in-your-code "Direct link to Find your Feature Flag's usages in your code") 1. Select the Feature Flag in the tree you want to search. 2. Click the **Find Usage** button on the action bar. 3. See the search results in the opened dialog. #### Create a new Config under a product[​](#create-a-new-config-under-a-product "Direct link to Create a new Config under a product") 1. Select the Products in the tree where you want to create your new config. 2. Click the **+** button on the action bar to open the **Create Config** dialog. 3. Enter a name for the new config. 4. Add a hint to your config (optional). 5. Select **OK** to confirm the Config creation. #### Open your Configs on the ConfigCat Dashboard[​](#open-your-configs-on-the-configcat-dashboard "Direct link to Open your Configs on the ConfigCat Dashboard") 1. Select the Config which you want to open in the Dashboard. 2. Click the **Open Config in ConfigCat Dashboard** button on the action bar to open the Config in the Dashboard. info The actions are available by right click menu as well. ### Help & Feedback Tab[​](#help--feedback-tab "Direct link to Help & Feedback Tab") The Help & Feedback tab provides quick links to open ConfigCat's Documentation and Dashboard and allows you to report issues. --- # Source: https://configcat.com/docs/api/reference/invite-member.md # Invite Member Copy page This endpoint invites a Member into the given Product identified by the `productId` parameter. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When the invite was successful. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/sdk-reference/ios.md # Swift (iOS) SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/swift-sdk.svg?style=social)](https://github.com/configcat/swift-sdk/stargazers) [![Build Status](https://github.com/configcat/swift-sdk/actions/workflows/swift-ci.yml/badge.svg?branch=master)](https://github.com/configcat/swift-sdk/actions/workflows/swift-ci.yml) [![CocoaPods](https://img.shields.io/cocoapods/v/ConfigCat.svg)](https://cocoapods.org/pods/ConfigCat) [![Supported Platforms](https://img.shields.io/cocoapods/p/ConfigCat.svg?style=flat)](https://configcat.com/docs/sdk-reference/ios) [![Coverage Status](https://img.shields.io/sonar/coverage/configcat_swift-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_swift-sdk) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=configcat_swift-sdk\&metric=alert_status)](https://sonarcloud.io/dashboard?id=configcat_swift-sdk) [ConfigCat Swift SDK on GitHub](https://github.com/configcat/swift-sdk) ## Getting Started[​](#getting-started "Direct link to Getting Started") ### 1. Add the ConfigCat SDK to your project[​](#1-add-the-configcat-sdk-to-your-project "Direct link to 1. Add the ConfigCat SDK to your project") * CocoaPods * Carthage * Swift Package Manager Podfile ```ruby target '' do pod 'ConfigCat' end ``` Then, run the following command to install your dependencies: ```text pod install ``` Cartfile ```swift github "configcat/swift-sdk" ``` Then, run the carthage update command and then follow the Carthage integration steps to link the framework with your project. Add the SDK to your `Package.swift`. Package.swift ```swift dependencies: [ .package( url: "https://github.com/configcat/swift-sdk", from: "11.0.1" ) ] ``` ### 2. Import the ConfigCat SDK[​](#2-import-the-configcat-sdk "Direct link to 2. Import the ConfigCat SDK") * Swift * Objective-C ```swift import ConfigCat ``` ```objectivec @import ConfigCat; ``` ### 3. Create the *ConfigCat* client with your *SDK Key*[​](#3-create-the-configcat-client-with-your-sdk-key "Direct link to 3-create-the-configcat-client-with-your-sdk-key") * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" options:NULL]; ``` ### 4. Get your setting value[​](#4-get-your-setting-value "Direct link to 4. Get your setting value") * Swift * Objective-C ```swift client.getValue(for: "isMyAwesomeFeatureEnabled", defaultValue: false) { isMyAwesomeFeatureEnabled in if isMyAwesomeFeatureEnabled { doTheNewThing() } else { doTheOldThing() } } // Or with async/await let isMyAwesomeFeatureEnabled = await client.getValue(for: "isMyAwesomeFeatureEnabled", defaultValue: false) if isMyAwesomeFeatureEnabled { doTheNewThing() } else { doTheOldThing() } ``` ```objectivec [client getBoolValueFor:@"isMyAwesomeFeatureEnabled" defaultValue:false user:NULL completion:^(BOOL isMyAwesomeFeatureEnabled) { if (isMyAwesomeFeatureEnabled) { // do the new thing } else { // do the old thing } }]; ``` The *ConfigCat SDK* also offers a synchronous API for feature flag evaluation. Read more [here](#snapshots-and-non-blocking-synchronous-feature-flag-evaluation). ### 5. Close ConfigCat client​[​](#5-close-configcat-client "Direct link to 5. Close ConfigCat client​") You can safely shut down all clients at once or individually and release all associated resources on application exit. * Swift * Objective-C ```swift ConfigCatClient.closeAll() // closes all clients client.close() // closes the specific client ``` ```objectivec [ConfigCatClient closeAll]; // closes all clients [client close]; // closes the specific client ``` ## Supported platform versions[​](#supported-platform-versions "Direct link to Supported platform versions") The following device platform versions are supported: | Platform | Version | | -------- | -------- | | iOS | >= 12.0 | | watchOS | >= 4.0 | | tvOS | >= 12.0 | | macOS | >= 10.13 | | visionOS | >= 1.0 | ## Creating the *ConfigCat Client*[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `ConfigCatClient.get(sdkKey: )` returns a client with default options. ### Customizing the *ConfigCat Client*[​](#customizing-the-configcat-client "Direct link to customizing-the-configcat-client") To customize the SDK's behavior, you can pass an additional `(ConfigCatOptions) -> ()` parameter to the `get()` static factory method where the `ConfigCatOptions` class is used to set up the *ConfigCat Client*. * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.pollingMode = PollingModes.manualPoll() options.logLevel = .info } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.pollingMode = [PollingModes manualPoll]; options.logLevel = LogLevelInfo; }]; ``` These are the available options on the `ConfigCatOptions` class: | Arguments | Type | Description | | ---------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataGovernance` | `DataGovernance` | Optional, defaults to `global`. Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `global`, `euOnly`. | | `configCache` | `ConfigCache?` | Optional, sets a custom cache implementation for the client. [More about cache](#custom-cache). | | `pollingMode` | `PollingMode` | Optional, sets the polling mode for the client. [More about polling modes](#polling-modes). | | `sessionConfiguration` | `URLSessionConfiguration` | Optional, sets a custom `URLSessionConfiguration` used by the HTTP calls. | | `baseUrl` | `String` | Optional, sets the CDN base url (forward proxy, dedicated subscription) from where the sdk will download the config JSON. | | `flagOverrides` | `OverrideDataSource?` | Optional, sets the local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | `logLevel` | `LogLevel` | Optional, sets the internal log level. [More about logging.](#logging). | | `defaultUser` | `ConfigCatUser?` | Optional, sets the default user. [More about default user](#default-user). | | `logger` | `ConfigCatLogger` | Optional, sets the logger implementation used by the SDK. [More about logging](#logging) | | `offline` | `Bool` | Optional, defaults to `false`. Indicates whether the SDK should be initialized in offline mode. [More about offline mode](#online--offline-mode). | | `hooks` | `Hooks` | Optional, used to subscribe events that the SDK sends in specific scenarios. [More about hooks](#hooks). | caution We strongly recommend you to use the `ConfigCatClient` as a Singleton object in your application. The `ConfigCatClient.get(sdkKey: )` static factory method constructs singleton client instances for your SDK keys. These clients can be closed all at once with the `ConfigCatClient.closeAll()` method or individually with `client.close()`. ## Anatomy of `getValue()`[​](#anatomy-of-getvalue "Direct link to anatomy-of-getvalue") | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | | `completion` | **REQUIRED.** Callback function to call, when the result is ready. | * Swift * Objective-C ```swift client.getValue( for: "keyOfMySetting", // Setting Key defaultValue: false, // Default value user: ConfigCatUser(identifier: "#UNIQUE-USER-IDENTIFIER#") // Optional User Object ) { isMyAwesomeFeatureEnabled in if isMyAwesomeFeatureEnabled { doTheNewThing() } else { doTheOldThing() } } // Or with async/await let isMyAwesomeFeatureEnabled = await client.getValue( for: "keyOfMySetting", // Setting Key defaultValue: false, // Default value user: ConfigCatUser(identifier: "#UNIQUE-USER-IDENTIFIER#") // Optional User Object if isMyAwesomeFeatureEnabled { doTheNewThing() } else { doTheOldThing() } ``` ```objectivec ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"#UNIQUE-USER-IDENTIFIER#" email:NULL country:NULL custom:NULL]; [client getBoolValueFor:@"keyOfMySetting" // Setting Key defaultValue:false // Default value user:user // Optional User Object completion:^(BOOL isMyAwesomeFeatureEnabled) { if (isMyAwesomeFeatureEnabled) { // do the new thing } else { // do the old thing } }]; ``` caution *The following is only related to the SDK's generic-typed API which's only accessible from Swift.* It is important to provide an argument for the `defaultValue` parameter, specifically for the `Value` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | Type parameter `Value` | | -------------- | ---------------------- | | On/Off Toggle | `Bool` / `Bool?` | | Text | `String` / `String?` | | Whole Number | `Int` / `Int?` | | Decimal Number | `Double` / `Double?` | In addition to the types mentioned above, you also have the option to provide `Any` or `Any?` for the type parameter (or to use the `getAnyValue` method) regardless of the setting kind. If you provide any other type for the type parameter, or if you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. When relying on type inference, be mindful of potential type mismatch issues, especially with number types. For example, `await client.getValue(for: "keyOfMyDecimalSetting", defaultValue: 0)` will return `defaultValue` (`0`) instead of the actual value of the decimal setting because the compiler infers the type as `Int` instead of `Double`. To correctly evaluate a decimal setting, you should use: ```swift let value = await client.getValue(for: "keyOfMyDecimalSetting", defaultValue: 0.0); ``` ## Anatomy of `getValueDetails()`[​](#anatomy-of-getvaluedetails "Direct link to anatomy-of-getvaluedetails") `getValueDetails()` is similar to `getValue()` but instead of returning the evaluated value only, it gives more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | * Swift * Objective-C ```swift client.getValueDetails( for: "keyOfMySetting", // Setting Key defaultValue: false, // Default value user: ConfigCatUser(identifier: "#UNIQUE-USER-IDENTIFIER#") // Optional User Object ) { details in // Use the details result } // Or with async/await let details = await client.getValueDetails( for: "keyOfMySetting", // Setting Key defaultValue: false, // Default value user: ConfigCatUser(identifier: "#UNIQUE-USER-IDENTIFIER#") // Optional User Object ``` ```objectivec ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"#UNIQUE-USER-IDENTIFIER#" email:NULL country:NULL custom:NULL]; [client getBoolValueDetailsFor:@"keyOfMySetting" // Setting Key defaultValue:false // Default value user:user // Optional User Object completion:^(BoolEvaluationDetails* details) { // Use the details result }]; ``` caution *The following is only related to the SDK's generic-typed API which's only accessible from Swift.* It is important to provide an argument for the `defaultValue` parameter, specifically for the `Value` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The details result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------- | | `value` | `Bool` / `String` / `Int` / `Double` | The evaluated value of the feature flag or setting. | | `key` | `String` | The key of the evaluated feature flag or setting. | | `isDefaultValue` | `Bool` | True when the default value passed to `getValueDetails()` is returned due to an error. | | `error` | `String?` | In case of an error, this property contains the error message. | | `user` | `ConfigCatUser?` | The User Object that was used for evaluation. | | `matchedPercentageOption` | `PercentageOption?` | The Percentage Option (if any) that was used to select the evaluated value. | | `matchedTargetingRule` | `TargetingRule?` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `fetchTime` | `Date` | The last download time of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. * Swift * Objective-C ```swift let user = ConfigCatUser(identifier: "#UNIQUE-USER-IDENTIFIER#") ``` ```objectivec ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"#UNIQUE-USER-IDENTIFIER#" email:NULL country:NULL custom:NULL]; ``` * Swift * Objective-C ```swift let user = ConfigCatUser(identifier: "john@example.com") ``` ```objectivec ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"john@example.com" email:NULL country:NULL custom:NULL]; ``` | Arguments | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. e.g. User role, Subscription type. | * Swift * Objective-C ```swift let user = ConfigCatUser(identifier: "#UNIQUE-USER-IDENTIFIER#", email: "john@example.com", country: "United Kingdom", custom: ["SubscriptionType":"Pro", "UserRole":"Admin"]) ``` ```objectivec ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"#UNIQUE-USER-IDENTIFIER#" email:@"john@example.com" country:@"United Kingdom" custom:@{@"SubscriptionType": @"Pro", @"UserRole": @"Admin"}]; ``` The `custom` map also allows attribute values other than `String` values: * Swift * Objective-C ```swift let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" let registeredAt = dateFormatter.date(from:"2023-03-31T23:59:59.999Z")! let user = ConfigCatUser(identifier: "#UNIQUE-USER-IDENTIFIER#", email: "john@example.com", country: "United Kingdom", custom: ["Rating":4.5, "RegisteredAt":registeredAt, "Roles": ["Role1", "Role2"]]) ``` ```objectivec NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"]; NSDate *registeredAt = [dateFormatter dateFromString: @"2023-03-31T23:59:59.999Z"]; ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"#UNIQUE-USER-IDENTIFIER#" email:@"john@example.com" country:@"United Kingdom" custom:@{@"Rating": @4.5, @"RegisteredAt": registeredAt, @"Roles":@[@"Role1", @"Role2"]}]; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `String` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `String` values, * all other values are automatically converted to `String` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `String` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated targeting rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `Int`, `UInt`, `Double`, or `Float` values, * accept `String` values containing a properly formatted, valid `Double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated targeting rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `Int`, `UInt`, `Double`, or `Float` values representing a second-based Unix timestamp, * accept `String` values containing a properly formatted, valid `Double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated targeting rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `String`, * accept `String` values containing a valid JSON string which can be deserialized to an array of `String`, * all other values are considered invalid (a warning will be logged and the currently evaluated targeting rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") There's an option to set a default User Object that will be used at feature flag and setting evaluation. It can be useful when your application has a single user only, or rarely switches users. You can set the default User Object either on SDK initialization: * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.defaultUser = ConfigCatUser(identifier: "john@example.com") } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.defaultUser = [[ConfigCatUser alloc]initWithIdentifier:@"john@example.com" email:NULL country:NULL custom:NULL]; }]; ``` or with the `setDefaultUser()` method of the ConfigCat client. * Swift * Objective-C ```swift client.setDefaultUser(user: ConfigCatUser(identifier: "john@example.com")) ``` ```objectivec [client setDefaultUserWithUser:[[ConfigCatUser alloc]initWithIdentifier:@"john@example.com" email:NULL country:NULL custom:NULL]]; ``` Whenever the `getValue()`, `getValueDetails()`, `getAllValues()`, or `getAllVariationIds()` methods are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. * Swift * Objective-C ```swift let user = ConfigCatUser(identifier: "john@example.com") client.setDefaultUser(user) // The default user will be used at the evaluation process. let value = await client.getValue(for: "keyOfMySetting", defaultValue: false) ``` ```objectivec ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"john@example.com" email:NULL country:NULL custom:NULL]; [client setDefaultUserWithUser:user]; // The default user will be used at the evaluation process. [client getBoolValueFor:@"keyOfMySetting" defaultValue:false user:NULL completion:^(BOOL value) { // You can use the evaluation's result here. }]; ``` When the `user` parameter is specified on the requesting method, it takes precedence over the default user. * Swift * Objective-C ```swift et user = ConfigCatUser(identifier: "john@example.com") client.setDefaultUser(user) let otherUser = ConfigCatUser(identifier: "brian@example.com") // otherUser will be used at the evaluation process. let value = await client.getValue(for: 'keyOfMySetting', defaultValue: false, user: otherUser) ``` ```objectivec ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"john@example.com" email:NULL country:NULL custom:NULL]; [client setDefaultUserWithUser:user]; ConfigCatUser* otherUser = [[ConfigCatUser alloc]initWithIdentifier:@"brian@example.com" email:NULL country:NULL custom:NULL]; // otherUser will be used at the evaluation process. [client getBoolValueFor:@"keyOfMySetting" defaultValue:false user:otherUser completion:^(BOOL value) { // You can use the evaluation's result here. }]; ``` For deleting the default user, you can do the following: * Swift * Objective-C ```swift client.clearDefaultUser() ``` ```objectivec [client clearDefaultUser]; ``` ## `getAllKeys()`[​](#getallkeys "Direct link to getallkeys") You can get the keys for all available feature flags and settings by calling the `getAllKeys()` method of the `ConfigCatClient`. * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") // Completion callback client.getAllKeys() { keys in // use keys } // Async/await let keys = await client.getAllKeys() ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" options:NULL]; [client getAllKeysWithCompletion:^(NSArray* keys) { // use keys }]; ``` ## `getAllValues()`[​](#getallvalues "Direct link to getallvalues") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. | Parameters | Description | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") let user = ConfigCatUser(identifier: "#UNIQUE-USER-IDENTIFIER#") // Completion callback client.getAllValues( user: user// Optional User Object ) { allValues in // use allValues } // Async/await let allValues = await client.getAllValues( user: user // Optional User Object ) ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" options:NULL]; ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"#UNIQUE-USER-IDENTIFIER#" email:NULL country:NULL custom:NULL]; [client getAllValuesWithUser:user completion:^(NSDictionary* values) { // use values }]; ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValue()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle.
[More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the the `autoPollIntervalInSeconds` option parameter of the `PollingModes.autoPoll()` to change the polling interval. * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.pollingMode = PollingModes.autoPoll(autoPollIntervalInSeconds: 120 /* polling interval in seconds */) } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.pollingMode = [PollingModes autoPollWithAutoPollIntervalInSeconds:120 maxInitWaitTimeInSeconds:5]; }]; ``` Available options: | Option Parameter | Description | Default | | --------------------------- | ---------------------------------------------------------------------------------------------------- | ------- | | `autoPollIntervalInSeconds` | Polling interval. | 60 | | `maxInitWaitTimeInSeconds` | Maximum waiting time between the client initialization and the first config acquisition in secconds. | 5 | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValue()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValue()` will return the setting value after the cache is updated. Use the `cacheRefreshIntervalInSeconds` option parameter of the `PollingModes.lazyLoad()` to set cache lifetime. * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.pollingMode = PollingModes.lazyLoad(cacheRefreshIntervalInSeconds: 120 /* the cache will expire in 120 seconds */) } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.pollingMode = [PollingModes lazyLoadWithCacheRefreshIntervalInSeconds:120]; }]; ``` Available options: | Option Parameter | Description | Default | | ------------------------------- | ----------- | ------- | | `cacheRefreshIntervalInSeconds` | Cache TTL. | 60 | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `refresh()` is your application's responsibility. * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.pollingMode = PollingModes.manualPoll() } // Completion callback client.forceRefresh() { _ in // The client uses the latest config JSON } // Async/await await client.forceRefresh() ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.pollingMode = [PollingModes manualPoll]; }]; [client forceRefreshWithCompletion:^(RefreshResult* result) { // The client uses the latest config JSON }]; ``` > `getValue()` returns `defaultValue` if the cache is empty. Call `refresh()` to update the cache. ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `onReady(ClientCacheState)`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeInSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `ClientCacheState` argument. * `onConfigChanged((Config, ConfigCatClientSnapshot))`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `onFlagEvaluated(EvaluationDetails)`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetails()`](#anatomy-of-getvaluedetails). * `onError(String)`: This event is emitted when an error occurs within the client. You can subscribe to these events either on SDK initialization: * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.hooks.addOnFlagEvaluated { details in /* handle the event */ } } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { [options.hooks addOnFlagEvaluatedWithHandler:^(EvaluationDetails* details) { /* handle the event */ }]; }]; ``` or with the `hooks` property of the ConfigCat client: * Swift * Objective-C ```swift client.hooks.addOnFlagEvaluated { details in /* handle the event */ } ``` ```objectivec [client.hooks addOnFlagEvaluatedWithHandler:^(EvaluationDetails* details) { /* handle the event */ }]; ``` ## Snapshots and non-blocking synchronous feature flag evaluation[​](#snapshots-and-non-blocking-synchronous-feature-flag-evaluation "Direct link to Snapshots and non-blocking synchronous feature flag evaluation") The *ConfigCat* client doesn't directly provide synchronous methods for evaluating feature flags and settings because such synchronous methods could block the executing thread for longer periods of time (e.g. when downloading config data from the ConfigCat CDN servers), which could lead to an unresponsive application. However, there can be circumstances where synchronous evaluation is preferable, thus, since `v10.0.0`, the Swift SDK provides a way to synchronously evaluate feature flags and settings as a non-blocking operation, via *snapshots*. * Swift * Objective-C Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.pollingMode = PollingModes.autoPoll() } // Wait for the client to initialize. await client.waitForReady() let snapshot = client.snapshot() let user = ConfigCatUser(identifier: "#UNIQUE-USER-IDENTIFIER#") for key in snapshot.getAllKeys() { let value: Any? = snapshot.getValue(for: key, defaultValue: nil, user: user) print("\(key): \(String(describing: value))") } ``` Subscribing to the `onReady` hook gives you a snapshot of the captured initialized state of the *ConfigCat* client (including the latest downloaded config data) that you can use to synchronously evaluate feature flags and settings: ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { [options.hooks addOnReadyWithSnapshotHandler:^(ConfigCatClientSnapshot* snapshot) { ConfigCatUser* user = [[ConfigCatUser alloc]initWithIdentifier:@"#UNIQUE-USER-IDENTIFIER#" email:NULL country:NULL custom:NULL]; for (NSString* key in [snapshot getAllKeys]) { id def = NULL; id value = [snapshot getAnyValueFor:key defaultValue:def user:user]; NSLog(@"%@: %@", key, value); } }]; }]; ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefresh`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTimeInSeconds` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. (In Objective-C, `waitForReady` is not available. As an alternative, you can subscribe to the `onReady` hook and wait for the first event.) caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. * Swift * Objective-C ```swift let clientCacheState = await client.waitForReady() if (clientCacheState == .noFlagData) { // Handle initialization failure (see below). } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { [options.hooks addOnReadyWithSnapshotHandler:^(ConfigCatClientSnapshot* snapshot) { if ([snapshot cacheState] == ClientCacheStateNoFlagData) { // Handle initialization failure (see below). } }]; }]; ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `onConfigChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases when you'd want to prevent the SDK from making HTTP calls, you can put it in offline mode: * Swift * Objective-C ```swift client.setOffline() ``` ```objectivec [client setOffline]; ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To put the SDK back in online mode, you can do the following: * Swift * Objective-C ```swift client.setOnline() ``` ```objectivec [client setOnline]; ``` > With `client.isOffline` you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.localOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.localOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.remoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `[String: Any]` dictionary. * Swift * Objective-C ```swift let dictionary:[String: Any] = [ "enabledFeature": true, "disabledFeature": false, "intSetting": 5, "doubleSetting": 3.14, "stringSetting": "test" ] let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.flagOverrides = LocalDictionaryDataSource(source: dictionary, behaviour: .localOnly) } ``` ```objectivec NSDictionary* dictionary = @{ @"enabledFeature": @true, @"disabledFeature": @false, @"intSetting": @5, @"doubleSetting": @3.14, @"stringSetting": @"test" }; ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.flagOverrides = [[LocalDictionaryDataSource alloc]initWithSource:dictionary behaviour:OverrideBehaviourLocalOnly]; }]; ``` ## Cache[​](#cache "Direct link to Cache") The SDK uses `UserDefaults` as the default cache to store the downloaded `config JSON`. If you want to turn off the default behavior, you can set the SDK's cache to `nil` or to your own cache implementation. * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.configCache = nil } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.configCache = NULL; }]; ``` ### Custom cache[​](#custom-cache "Direct link to Custom cache") You have the option to inject your custom cache implementation into the client. All you have to do is to conform the `ConfigCache` protocol: * Swift * Objective-C ```swift @import ConfigCat public class MyCustomCache: ConfigCache { public func read(key: String) throws -> String { // here you have to return with the cached value } public func write(key: String, value: String) throws { // here you have to store the new value in the cache } } ``` MyCustomCache.h ```objectivec @import Foundation; @import ConfigCat; @interface MyCustomCache: NSObject @end ``` MyCustomCache.m ```objectivec #import "MyCustomCache.h" @implementation MyCustomCache - (NSString *)readFor:(NSString *)key error:(NSError * __autoreleasing *)error { // here you have to return with the cached value } - (BOOL)writeFor:(NSString *)key value:(NSString *)value error:(NSError * __autoreleasing *)error { // here you have to store the new value in the cache } @end ``` Then you can use your custom cache implementation at the SDK's initialization: * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.configCache = MyCustomCache() } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.configCache = [MyCustomCache alloc]; }]; ``` info The Swift SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Force refresh[​](#force-refresh "Direct link to Force refresh") Call the `forceRefresh()` method on the client to download the latest config JSON and update the cache. ## Using ConfigCat behind a proxy[​](#using-configcat-behind-a-proxy "Direct link to Using ConfigCat behind a proxy") Provide your own network credentials (username/password), and proxy server settings (proxy server/port) by adding a *ProxyDictionary* to the ConfigCat's `URLSessionConfiguration`. * Swift * Objective-C ```swift let proxyHost = "127.0.0.1" let proxyPort = 8080 let proxyUser = "user" let proxyPassword = "password" let sessionConfiguration = URLSessionConfiguration.default sessionConfiguration.connectionProxyDictionary = [ kCFNetworkProxiesHTTPEnable: true, kCFNetworkProxiesHTTPProxy: proxyHost, kCFNetworkProxiesHTTPPort: proxyPort, kCFNetworkProxiesHTTPSEnable: true, kCFNetworkProxiesHTTPSProxy: proxyHost, kCFNetworkProxiesHTTPSPort: proxyPort, kCFProxyUsernameKey: proxyUser, // Optional kCFProxyPasswordKey: proxyPassword // Optional ] let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.sessionConfiguration = sessionConfiguration } ``` ```objectivec NSString* proxyHost = @"127.0.0.1"; NSNumber* proxyPort = @8080; NSString* proxyUser = @"user"; NSString* proxyPassword = @"password"; NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfiguration.connectionProxyDictionary = @{ (NSString *)kCFNetworkProxiesHTTPEnable: @true, (NSString *)kCFNetworkProxiesHTTPProxy: proxyHost, (NSString *)kCFNetworkProxiesHTTPPort: proxyPort, (NSString *)kCFNetworkProxiesHTTPSEnable: @true, (NSString *)kCFNetworkProxiesHTTPSProxy: proxyHost, (NSString *)kCFNetworkProxiesHTTPSPort: proxyPort, (NSString *)kCFProxyUsernameKey: proxyUser, // Optional (NSString *)kCFProxyPasswordKey: proxyPassword // Optional }; ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.sessionConfiguration = sessionConfiguration; }]; ``` ## Changing the default HTTP timeout[​](#changing-the-default-http-timeout "Direct link to Changing the default HTTP timeout") Set the maximum wait time for a ConfigCat HTTP response by changing the *timeoutIntervalForRequest* of the ConfigCat's `URLSessionConfiguration`. The default *timeoutIntervalForRequest* is 60 seconds. * Swift * Objective-C ```swift let sessionConfiguration = URLSessionConfiguration.default sessionConfiguration.timeoutIntervalForRequest = 10 // Timeout in seconds let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.sessionConfiguration = sessionConfiguration } ``` ```objectivec NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfiguration.timeoutIntervalForRequest = 10; // Timeout in seconds ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.sessionConfiguration = sessionConfiguration; }]; ``` ## Logging[​](#logging "Direct link to Logging") The default logger used by the SDK is using the *Unified Logging System*. For more information about *Unified Logging* please visit [Apple's developer page](https://developer.apple.com/documentation/os/logging) or check [Session 721 - Unified Logging and Activity Tracing](https://developer.apple.com/videos/play/wwdc2016/721) from WWDC 2016. You can override the default logger with your custom implementation via the `logger` client option. The custom implementation must conform the `ConfigCatLogger` protocol. * Swift * Objective-C ```swift @import ConfigCat class MyCustomLogger: ConfigCatLogger { func debug(message: String) { // write the debug logs } func info(message: String) { // write the info logs } func warning(message: String) { // write the warning logs } func error(message: String) { // write the error logs } } ``` MyCustomLogger.h ```objectivec @import Foundation; @import ConfigCat; @interface MyCustomLogger: NSObject @end ``` MyCustomLogger.m ```objectivec #import "MyCustomLogger.h" @implementation MyCustomLogger - (void)debugWithMessage:(NSString * _Nonnull)message { // write the debug logs } - (void)infoWithMessage:(NSString * _Nonnull)message { // write the info logs } - (void)warningWithMessage:(NSString * _Nonnull)message { // write the warning logs } - (void)errorWithMessage:(NSString * _Nonnull)message { // write the error logs } @end ``` Then you can use your custom logger implementation at the SDK's initialization: * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.logger = MyCustomLogger() } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.logger = [MyCustomLogger alloc]; }]; ``` ### Log level[​](#log-level "Direct link to Log level") You can change the verbosity of the logs by setting the `logLevel` option. * Swift * Objective-C ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.logLevel = .info } ``` ```objectivec ConfigCatClient* client = [ConfigCatClient getWithSdkKey:@"#YOUR-SDK-KEY#" configurator:^(ConfigCatOptions* options) { options.logLevel = ConfigCatLogLevelInfo; }]; ``` Available log levels: * Swift * Objective-C | Level | Description | | ---------- | --------------------------------------------------------------------------------------- | | `.nolog` | Turn the ConfigCat logging off. | | `.error` | Only error level events are logged. | | `.warning` | Default. Errors and Warnings are logged. | | `.info` | Errors, Warnings and feature flag evaluation is logged. | | `.debug` | All of the above plus debug info is logged. Debug logs can be different for other SDKs. | | Level | Description | | -------------------------- | --------------------------------------------------------------------------------------- | | `ConfigCatLogLevelNolog` | Turn the ConfigCat logging off. | | `ConfigCatLogLevelError` | Only error level events are logged. | | `ConfigCatLogLevelWarning` | Default. Errors and Warnings are logged. | | `ConfigCatLogLevelInfo` | Errors, Warnings and feature flag evaluation is logged. | | `ConfigCatLogLevelDebug` | All of the above plus debug info is logged. Debug logs can be different for other SDKs. | Info level logging helps to inspect the feature flag evaluation process.
Example log entries: ```bash [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"","version":"1.0.0","Email":"configcat@example.com","Country":"CountryID"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the ConfigCat SDK that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Sample App[​](#sample-app "Direct link to Sample App") Check out our Sample Application how they use the ConfigCat SDK * [iOS with auto polling and change listener](https://github.com/configcat/swift-sdk/tree/master/samples/ios) --- # Source: https://configcat.com/docs/sdk-reference/openfeature/java.md # Source: https://configcat.com/docs/sdk-reference/java.md # Java SDK reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/java-sdk.svg?style=social)](https://github.com/configcat/java-sdk/stargazers) [![Java CI](https://github.com/configcat/java-sdk/actions/workflows/java-ci.yml/badge.svg?branch=master)](https://github.com/configcat/java-sdk/actions/workflows/java-ci.yml) [![Maven Central](https://img.shields.io/maven-central/v/com.configcat/configcat-java-client)](https://central.sonatype.com/artifact/com.configcat/configcat-java-client) [![Javadocs](https://javadoc.io/badge/com.configcat/configcat-java-client.svg)](https://javadoc.io/doc/com.configcat/configcat-java-client) [![Coverage Status](https://img.shields.io/sonar/coverage/configcat_java-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_java-sdk) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=configcat_java-sdk\&metric=alert_status)](https://sonarcloud.io/dashboard?id=configcat_java-sdk) [ConfigCat Java SDK on GitHub](https://github.com/configcat/java-sdk) ## Getting Started[​](#getting-started "Direct link to Getting Started") ### 1. Add the ConfigCat SDK to your project[​](#1-add-the-configcat-sdk-to-your-project "Direct link to 1. Add the ConfigCat SDK to your project") * Gradle * Maven build.gradle ```groovy dependencies { implementation 'com.configcat:configcat-java-client:9.+' } ``` pom.xml ```xml com.configcat configcat-java-client [9.0.0,) ``` ### 2. Import the ConfigCat SDK[​](#2-import-the-configcat-sdk "Direct link to 2. Import the ConfigCat SDK") ```java import com.configcat.*; ``` ### 3. Create and get the *ConfigCat* client for your *SDK Key*[​](#3-create-and-get-the-configcat-client-for-your-sdk-key "Direct link to 3-create-and-get-the-configcat-client-for-your-sdk-key") ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); ``` ### 4. Get your setting value[​](#4-get-your-setting-value "Direct link to 4. Get your setting value") ```java boolean isMyAwesomeFeatureEnabled = client.getValue(Boolean.class, "isMyAwesomeFeatureEnabled", false); if (isMyAwesomeFeatureEnabled) { doTheNewThing(); } else { doTheOldThing(); } ``` ### 5. Stop *ConfigCat* client[​](#5-stop-configcat-client "Direct link to 5-stop-configcat-client") You can safely shut down the client instance and release all associated resources on application exit. ```java client.close(); ``` You can close all singleton client instances and release all associated resources on application exit. ```java ConfigCatClient.closeAll(); ``` ## Java compatibility[​](#java-compatibility "Direct link to Java compatibility") The ConfigCat Java SDK is compatible with Java 8 and higher. ## Creating the *ConfigCat Client*[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `ConfigCatClient.get()` returns a client with default options. ### Customizing the *ConfigCat Client*[​](#customizing-the-configcat-client "Direct link to customizing-the-configcat-client") To customize the SDK's behavior, you can pass an additional `Consumer` parameter to the `get()` static factory method where the `Options` class is used to set up the *ConfigCat Client*. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.pollingMode(PollingModes.autoPoll()); options.logLevel(LogLevel.INFO); }); ``` These are the available options on the `Options` class: | Option | Description | | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataGovernance(DataGovernance)` | Optional, defaults to `Global`. Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `Global`, `EuOnly`. | | `baseUrl(string)` | Optional, sets the CDN base url (forward proxy, dedicated subscription) from where the sdk will download the configurations. | | `httpClient(OkHttpClient)` | Optional, sets the underlying `OkHttpClient` used to download the feature flags and settings over HTTP. [More about the HTTP Client](#httpclient). | | `cache(ConfigCache)` | Optional, sets a custom cache implementation for the client. [More about cache](#custom-cache). | | `pollingMode(PollingMode)` | Optional, sets the polling mode for the client. [More about polling modes](#polling-modes). | | `logLevel(LogLevel)` | Optional, defaults to `WARNING`. Sets the internal log level. [More about logging](#logging). | | `logFilter(LogFilterFunction)` | Optional, sets a custom log filter. [More about log filtering](#log-filtering). | | `flagOverrides(OverrideDataSourceBuilder, OverrideBehaviour)` | Optional, sets the local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | `defaultUser(User)` | Optional, sets default user. [More about default user](#default-user). | | `offline(boolean)` | Optional, defaults to `false`. Indicates whether the SDK should be initialized in offline mode. [More about offline mode](#online--offline-mode). | | `hooks()` | Optional, used to subscribe events that the SDK sends in specific scenarios. [More about hooks](#hooks). | caution We strongly recommend you to use the `ConfigCatClient` as a Singleton object in your application. The `ConfigCatClient.get("#YOUR-SDK-KEY#")` static factory method constructs singleton client instances for your SDK keys. These clients can be closed all at once with the `ConfigCatClient.closeAll()` method or individually with `client.close()`. ## Anatomy of `getValue()`[​](#anatomy-of-getvalue "Direct link to anatomy-of-getvalue") | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `classOfT` | **REQUIRED.** The type of the setting. | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | ```java boolean value = client.getValue( Boolean.class, // Setting type "keyOfMySetting", // Setting Key User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"), // Optional User Object false // Default value ); ``` caution It is important to provide an argument for the `classOfT` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | Type parameter `T` | | -------------- | --------------------- | | On/Off Toggle | `boolean` / `Boolean` | | Text | `String` | | Whole Number | `int` / `Integer` | | Decimal Number | `double` / `Double` | It's important to note that providing any other type for the type parameter will result in an `IllegalArgumentException`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `classOfT` | **REQUIRED.** The type of the setting. | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | ```java client.getValueAsync( Boolean.class, // Setting type "keyOfMySetting", // Setting Key User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"), // Optional User Object false // Default value ).thenAccept(isMyAwesomeFeatureEnabled -> { if (isMyAwesomeFeatureEnabled) { doTheNewThing(); } else { doTheOldThing(); } }); ``` caution It is important to provide an argument for the `classOfT` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. ## Anatomy of `getValueDetails()`[​](#anatomy-of-getvaluedetails "Direct link to anatomy-of-getvaluedetails") `getValueDetails()` is similar to `getValue()` but instead of returning the evaluated value only, it gives more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `classOfT` | **REQUIRED.** The type of the setting. | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | ```java EvaluationDetails details = client.getValueDetails( Boolean.class, // Setting type "keyOfMySetting", // Setting Key User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"), // Optional User Object false // Default value ); // Or asynchronously client.getValueDetailsAsync( Boolean.class, // Setting type "keyOfMySetting", // Setting Key User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"), // Optional User Object false // Default value ).thenAccept(details -> { // Use the details result }); ``` caution It is important to provide an argument for the `classOfT` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The details result contains the following information: | Property | Type | Description | | -------------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `getValue()` | `boolean` / `String` / `int` / `double` | The evaluated value of the feature flag or setting. | | `getKey()` | `String` | The key of the evaluated feature flag or setting. | | `isDefaultValue()` | `boolean` | True when the default value passed to `getValueDetails()` is returned due to an error. | | `getError()` | `String` | In case of an error, this property contains the error message. | | `getUser()` | `User` | The User Object that was used for evaluation. | | `getMatchedPercentageOption()` | `PercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `getMatchedTargetingRule()` | `TargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `getFetchTimeUnixMilliseconds()` | `long` | The last download time of the current config in unix milliseconds format. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. ```java User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"); ``` ```java User user = User.newBuilder().build("john@example.com"); ``` | Builder options | Description | | --------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier()` | **REQUIRED.** Unique identifier of a user in your application. Can be any value, even an email address. | | `email()` | Optional parameter for easier Targeting Rule definitions. | | `country()` | Optional parameter for easier Targeting Rule definitions. | | `custom()` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. e.g. User role, Subscription type. | ```java java.util.Map customAttributes = new java.util.HashMap(); customAttributes.put("SubscriptionType", "Pro"); customAttributes.put("UserRole", "Admin"); User user = User.newBuilder() .email("john@example.com") .country("United Kingdom") .custom(customAttributes) .build("#UNIQUE-USER-IDENTIFIER#"); ``` The `Custom` dictionary also allows attribute values other than `String` values: ```java java.util.Map customAttributes = new java.util.HashMap(); customAttributes.put("Rating", 4.5); customAttributes.put("RegisteredAt", new Date("2023-11-22 12:34:56 +00:00")); customAttributes.put("Roles", new String[]{"Role1", "Role2"}); User user = User.newBuilder() .email("john@example.com") .country("United Kingdom") .custom(customAttributes) .build("#UNIQUE-USER-IDENTIFIER#"); ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `String` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `String` values, * all other values are automatically converted to `String` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `String` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `Double` values and all other numeric values which can safely be converted to `Double`, * accept `String` values containing a properly formatted, valid `Double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` or `Instant` values, which are automatically converted to a second-based Unix timestamp, * accept `Double` values representing a second-based Unix timestamp and all other numeric values which can safely be converted to `Double`, * accept `String` values containing a properly formatted, valid `Double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays and list of `String`, * accept `String` values containing a valid JSON string which can be deserialized to an array of `String`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default User[​](#default-user "Direct link to Default User") There's an option to set a default User Object that will be used at feature flag and setting evaluation. It can be useful when your application has a single user only, or rarely switches users. You can set the default User Object either with the ConfigCatClient builder: ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.mode(PollingModes.manualPoll()); options.baseUrl(server.url("/").toString()); options.defaultUser(User.newBuilder().build("john@example.com")); }); ``` or with the `setDefaultUser()` method of the ConfigCat client. ```java client.setDefaultUser(User.newBuilder().build("john@example.com")); ``` Whenever the `getValue()`, `getValueDetails()`, `getAllValues()`, or `getAllValueDetails()` methods are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```java client.setDefaultUser(User.newBuilder().build("john@example.com")); // The default user will be used at the evaluation process. boolean value = client.getValue(Boolean.class, "keyOfMySetting", false); ``` When the `user` parameter is specified on the requesting method, it takes precedence over the default user. ```java client.setDefaultUser(User.newBuilder().build("john@example.com")); User otherUser = User.newBuilder().build("user"); // otherUser will be used at the evaluation process. boolean value = client.getValue(Boolean.class, "keyOfMySetting", false, otherUser); ``` For deleting the default user, you can do the following: ```java client.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValue()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle.
[More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the the `autoPollIntervalInSeconds` option parameter of the `PollingModes.autoPoll()` to change the polling interval. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.pollingMode(PollingModes.autoPoll(60 /* polling interval in seconds */)); }); ``` Available options: | Option Parameter | Description | Default | | --------------------------- | --------------------------------------------------------------------------------------------------- | ------- | | `autoPollIntervalInSeconds` | Polling interval. | 60 | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5 | ### Lazy Loading[​](#lazy-loading "Direct link to Lazy Loading") When calling `getValue()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValue()` will return the setting value after the cache is updated. Use the `cacheRefreshIntervalInSeconds` option parameter of the `PollingModes.lazyLoad()` to set cache lifetime. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.pollingMode(PollingModes.lazyLoad(60 /* the cache will expire in 120 seconds */)); }); ``` Available options: | Option Parameter | Description | Default | | ------------------------------- | ----------- | ------- | | `cacheRefreshIntervalInSeconds` | Cache TTL. | 60 | ### Manual Polling[​](#manual-polling "Direct link to Manual Polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefresh()` is your application's responsibility. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options ->{ options.pollingMode(PollingModes.manualPoll()); }); client.forceRefresh(); ``` > `getValue()` returns `defaultValue` if the cache is empty. Call `forceRefresh()` to update the cache. ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `onClientReady(ClientCacheState)`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after instantiation. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `ClientCacheState` argument. * `onConfigChanged(Map)`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `onFlagEvaluated(EvaluationDetails)`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetails()`](#anatomy-of-getvaluedetails). * `onError(String)`: This event is emitted when an error occurs within the client. You can subscribe to these events either on SDK initialization: ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.hooks().addOnFlagEvaluated(details -> { /* handle the event */ }); }); ``` or with the `getHooks()` property of the ConfigCat client: ```java client.getHooks().addOnFlagEvaluated(details -> { /* handle the event */ }); ``` ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases when you'd want to prevent the SDK from making HTTP calls, you can put it in offline mode: ```java client.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To put the SDK back in online mode, you can do the following: ```java client.setOnline(); ``` > With `client.isOffline()` you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LOCAL_ONLY`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LOCAL_OVER_REMOTE`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.REMOTE_OVER_LOCAL`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can load your feature flag & setting overrides from a file or from a simple `Map` structure. ### JSON File[​](#json-file "Direct link to JSON File") The SDK can load your feature flag & setting overrides from a file or classpath resource. You can also specify whether the file should be reloaded when it gets modified. #### File[​](#file "Direct link to File") ```java ConfigCatClient client = ConfigCatClient.get("localhost", options -> { options.flagOverrides(OverrideDataSourceBuilder.localFile( "path/to/the/local_flags.json", // path to the file true // reload the file when it gets modified ), OverrideBehaviour.LOCAL_ONLY ); }); ``` #### Classpath Resource[​](#classpath-resource "Direct link to Classpath Resource") ```java ConfigCatClient client = ConfigCatClient.get("localhost", options -> { options.flagOverrides(OverrideDataSourceBuilder.classPathResource( "local_flags.json", // name of the resource true // reload the resource when it gets modified ), OverrideBehaviour.LOCAL_ONLY ); }); ``` #### JSON File Structure[​](#json-file-structure "Direct link to JSON File Structure") The SDK supports 2 types of JSON structures to describe feature flags & settings. ##### 1. Simple (key-value) structure[​](#1-simple-key-value-structure "Direct link to 1. Simple (key-value) structure") ```json { "flags": { "enabledFeature": true, "disabledFeature": false, "intSetting": 5, "doubleSetting": 3.14, "stringSetting": "test" } } ``` ##### 2. Complex (full-featured) structure[​](#2-complex-full-featured-structure "Direct link to 2. Complex (full-featured) structure") This is the same format that the SDK downloads from the ConfigCat CDN. It allows the usage of all features that are available on the ConfigCat Dashboard. You can download your current config JSON from ConfigCat's CDN and use it as a baseline. A convenient way to get the config JSON for a specific SDK Key is to install the [ConfigCat CLI](https://github.com/configcat/cli) tool and execute the following command: ```bash configcat config-json get -f v6 -p {YOUR-SDK-KEY} > config.json ``` (Depending on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings, you may need to add the `--eu` switch.) Alternatively, you can download the config JSON manually, based on your [Data Governance](https://configcat.com/docs/advanced/data-governance.md) settings: * GLOBAL: `https://cdn-global.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` * EU: `https://cdn-eu.configcat.com/configuration-files/{YOUR-SDK-KEY}/config_v6.json` ```json { "p": { // hash salt, required only when confidential text comparator(s) are used "s": "80xCU/SlDz1lCiWFaxIBjyJeJecWjq46T4eu6GtozkM=" }, "s": [ // array of segments { "n": "Beta Users", // segment name "r": [ // array of User Conditions (there is a logical AND relation between the elements) { "a": "Email", // comparison attribute "c": 0, // comparator (see below) "l": [ // comparison value (see below) "john@example.com", "jane@example.com" ] } ] } ], "f": { // key-value map of feature flags & settings "isFeatureEnabled": { // key of a particular flag / setting "t": 0, // setting type, possible values: // 0 -> on/off setting (feature flag) // 1 -> text setting // 2 -> whole number setting // 3 -> decimal number setting "r": [ // array of Targeting Rules (there is a logical OR relation between the elements) { "c": [ // array of conditions (there is a logical AND relation between the elements) { "u": { // User Condition "a": "Email", // comparison attribute "c": 2, // comparator, possible values and required comparison value types: // 0 -> IS ONE OF (cleartext) + string array comparison value ("l") // 1 -> IS NOT ONE OF (cleartext) + string array comparison value ("l") // 2 -> CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 3 -> NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 4 -> IS ONE OF (semver) + semver string array comparison value ("l") // 5 -> IS NOT ONE OF (semver) + semver string array comparison value ("l") // 6 -> < (semver) + semver string comparison value ("s") // 7 -> <= (semver + semver string comparison value ("s") // 8 -> > (semver) + semver string comparison value ("s") // 9 -> >= (semver + semver string comparison value ("s") // 10 -> = (number) + number comparison value ("d") // 11 -> <> (number + number comparison value ("d") // 12 -> < (number) + number comparison value ("d") // 13 -> <= (number + number comparison value ("d") // 14 -> > (number) + number comparison value ("d") // 15 -> >= (number) + number comparison value ("d") // 16 -> IS ONE OF (hashed) + string array comparison value ("l") // 17 -> IS NOT ONE OF (hashed) + string array comparison value ("l") // 18 -> BEFORE (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 19 -> AFTER (UTC datetime) + second-based Unix timestamp number comparison value ("d") // 20 -> EQUALS (hashed) + string comparison value ("s") // 21 -> NOT EQUALS (hashed) + string comparison value ("s") // 22 -> STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 23 -> NOT STARTS WITH ANY OF (hashed) + string array comparison value ("l") // 24 -> ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 25 -> NOT ENDS WITH ANY OF (hashed) + string array comparison value ("l") // 26 -> ARRAY CONTAINS ANY OF (hashed) + string array comparison value ("l") // 27 -> ARRAY NOT CONTAINS ANY OF (hashed) + string array comparison value ("l") // 28 -> EQUALS (cleartext) + string comparison value ("s") // 29 -> NOT EQUALS (cleartext) + string comparison value ("s") // 30 -> STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 31 -> NOT STARTS WITH ANY OF (cleartext) + string array comparison value ("l") // 32 -> ENDS WITH ANY OF (cleartext) + string array comparison value ("l") // 33 -> NOT ENDS WITH ANY OF (cleartext + string array comparison value ("l") // 34 -> ARRAY CONTAINS ANY OF (cleartext) + string array comparison value ("l") // 35 -> ARRAY NOT CONTAINS ANY OF (cleartext) + string array comparison value ("l") "l": [ // comparison value - depending on the comparator, another type of value may need // to be specified (see above): // "s": string // "d": number "@example.com" ] } }, { "p": { // Flag Condition (Prerequisite) "f": "mainIntFlag", // key of prerequisite flag "c": 0, // comparator, possible values: 0 -> EQUALS, 1 -> NOT EQUALS "v": { // comparison value (value's type must match the prerequisite flag's type) "i": 42 } } }, { "s": { // Segment Condition "s": 0, // segment index, a valid index into the top-level segment array ("s") "c": 1 // comparator, possible values: 0 -> IS IN SEGMENT, 1 -> IS NOT IN SEGMENT } } ], "s": { // alternatively, an array of Percentage Options ("p", see below) can also be specified "v": { // the value served when the rule is selected during evaluation "b": true }, "i": "bcfb84a7" } } ], "p": [ // array of Percentage Options { "p": 10, // % value "v": { // the value served when the Percentage Option is selected during evaluation "b": true }, "i": "bcfb84a7" }, { "p": 90, "v": { "b": false }, "i": "bddac6ae" } ], "v": { // fallback value, served when none of the Targeting Rules match, // no Percentage Options are defined or evaluation of these is not possible "b": false // depending on the setting type, another type of value may need to be specified: // text setting -> "s": string // whole number setting -> "i": number // decimal number setting -> "d": number }, "i": "430bded3" // variation id (for analytical purposes) } } } ``` For a more comprehensive specification of the config JSON v6 format, you may refer to [this JSON schema document](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ### Map[​](#map "Direct link to Map") You can set up the SDK to load your feature flag & setting overrides from a `Map`. ```java Map map = new HashMap<>(); map.put("enabledFeature", true); map.put("disabledFeature", false); map.put("intSetting", 5); map.put("doubleSetting", 3.14); map.put("stringSetting", "test"); ConfigCatClient client = ConfigCatClient.get("localhost", options -> { options.flagOverrides(OverrideDataSourceBuilder.map(map), OverrideBehaviour.LOCAL_ONLY) }); ``` ## `getAllKeys()`, `getAllKeysAsync()`[​](#getallkeys-getallkeysasync "Direct link to getallkeys-getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeys()` or `getAllKeysAsync()` method. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); java.util.Collection keys = client.getAllKeys(); ``` ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); client.getAllKeysAsync().thenAccept(keys -> { }); ``` ## `getAllValues()`, `getAllValuesAsync()`[​](#getallvalues-getallvaluesasync "Direct link to getallvalues-getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a User Object is optional. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); Map settingValues = client.getAllValues(); // invoke with User Object User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#") Map settingValuesTargeting = client.getAllValues(user); ``` ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); client.getAllValuesAsync().thenAccept(settingValues -> { }); // invoke with User Object User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#") client.getAllValuesAsync(user).thenAccept(settingValuesTargeting -> { }); ``` ## `getAllValueDetails()`, `getAllValueDetailsAsync()`[​](#getallvaluedetails-getallvaluedetailsasync "Direct link to getallvaluedetails-getallvaluedetailsasync") Evaluates and returns the detailed values of all feature flags and settings. Passing a User Object is optional. ```java User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"); ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); List> allValueDetails = client.getAllValueDetails(user); ``` ```java User user = User.newBuilder().build("#UNIQUE-USER-IDENTIFIER#"); ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#"); client.getAllValueDetailsAsync(user).thenAccept(allValueDetails -> { }); ``` ## Custom Cache[​](#custom-cache "Direct link to Custom Cache") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can subclass the [`ConfigCache`](https://github.com/configcat/java-sdk/blob/master/src/main/java/com/configcat/ConfigCache.java) abstract class and call the `cache` method with your implementation in the setup callback of `ConfigCatClient.get`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```java public class MyCustomCache extends ConfigCache { @Override public String read(String key) { // here you have to return with the cached value } @Override public void write(String key, String value) { // here you have to store the new value in the cache } } ``` Then use your custom cache implementation: ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.cache(new MyCustomCache()) // inject your custom cache }); ``` info The Java SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## HttpClient[​](#httpclient "Direct link to HttpClient") The ConfigCat SDK internally uses an [OkHttpClient](https://github.com/square/okhttp) instance to download the latest configuration over HTTP. You have the option to override the internal Http client with your customized one. ### HTTP Proxy[​](#http-proxy "Direct link to HTTP Proxy") If your application runs behind a proxy you can do the following: ```java import java.net.InetSocketAddress; import java.net.Proxy; Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxyHost", proxyPort)); ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.httpClient(new OkHttpClient.Builder() .proxy(proxy) .build()) }); ``` ### HTTP Timeout[​](#http-timeout "Direct link to HTTP Timeout") You can set the maximum wait time for a ConfigCat HTTP response by using OkHttpClient's timeouts. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.httpClient(new OkHttpClient.Builder() .readTimeout(2, TimeUnit.SECONDS) // set the read timeout to 2 seconds .build()) }); ``` OkHttpClient's default timeout is 10 seconds. > As the ConfigCatClient SDK maintains the whole lifetime of the internal http client, it's being closed simultaneously with the ConfigCatClient, refrain from closing the http client manually. ## Force refresh[​](#force-refresh "Direct link to Force refresh") Call the `forceRefresh()` method on the client to download the latest config JSON and update the cache. ## Logging[​](#logging "Direct link to Logging") The SDK uses the facade of [slf4j](https://www.slf4j.org) for logging, so you can use any of the slf4j implementation packages. You can change the verbosity of the logs by passing a `LogLevel` parameter to the ConfigCatClientBuilder's `logLevel` function. ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.logLevel(LogLevel.INFO); }); ``` Available log levels: | Level | Description | | --------- | --------------------------------------------------------------------------------------- | | `NO_LOG` | Turn the logging off. | | `ERROR` | Only error level events are logged. | | `WARNING` | Default. Errors and Warnings are logged. | | `INFO` | Errors, Warnings and feature flag evaluation is logged. | | `DEBUG` | All of the above plus debug info is logged. Debug logs can be different for other SDKs. | Info level logging helps to inspect how a feature flag was evaluated: ```bash INFO com.configcat.ConfigCatClient - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"","Email":"configcat@example.com","Country":"US","SubscriptionType":"Pro","Role":"Admin","version":"1.0.0"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'False' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'True' => MATCH, applying rule Returning 'True'. ``` ### Logging Implementation[​](#logging-implementation "Direct link to Logging Implementation") You have the flexibility to use any slf4j implementation for logging with ConfigCat. However, some logger implementations may not display debug level messages by default. In these cases, you simply need to adjust the logger configuration to receive all log messages from the ConfigCat SDK. Examples fo [slf4j-simple](https://github.com/configcat/java-sdk/blob/master/samples/console/src/main/resources/simplelogger.properties) and [logback](https://github.com/configcat/java-sdk/blob/master/samples/web/src/main/resources/logback.xml) are available under the [Sample Apps](#sample-apps) section. ### Log Filtering[​](#log-filtering "Direct link to Log Filtering") You can define a custom log filter by implementing the `LogFilterFunction` interface. The `apply` method will be called by the *ConfigCat SDK* each time a log event occurs (and the event passes the minimum log level specified by the `logLevel` option). That is, the `apply` method allows you to filter log events by `logLevel`, `eventId`, `message` or `exception`. The formatted message string can be obtained by calling `toString()` on the `message` parameter. If the `apply` method returns `true`, the event will be logged, otherwise it will be skipped. ```java // Filter out events with id 1001 from the log. LogFilterFunction filterLogFunction = ( LogLevel logLevel, int eventId, Object message, Throwable exception) -> eventId != 1001; ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> options.logFilter(filterLogFunction)); ``` caution Please make sure that your log filter logic doesn't perform heavy computation and doesn't block the executing thread. A complex or incorrectly implemented log filter can degrade the performance of the SDK. ## Sample Apps[​](#sample-apps "Direct link to Sample Apps") Check out our Sample Applications how they use the ConfigCat SDK * [Simple Console Application](https://github.com/configcat/java-sdk/tree/master/samples/console) * [Spring Boot Web Application](https://github.com/configcat/java-sdk/tree/master/samples/web) ## Guides[​](#guides "Direct link to Guides") See [this](https://configcat.com/blog/2022/10/28/using-feature-flags-in-java/) guide on how to use ConfigCat's Java SDK. ## Look Under the Hood[​](#look-under-the-hood "Direct link to Look Under the Hood") * [ConfigCat Java SDK's repository on GitHub](https://github.com/configcat/java-sdk) * [ConfigCat Java SDK's javadoc page](https://javadoc.io/doc/com.configcat/configcat-java-client) * [ConfigCat Java SDK on Maven Central](https://search.maven.org/artifact/com.configcat/configcat-java-client) --- # Source: https://configcat.com/docs/integrations/jira.md # Jira Cloud Plugin - Manage feature flags from Jira Copy page The [ConfigCat Feature Flags Jira Cloud Plugin](https://marketplace.atlassian.com/1222421) allows you to connect your Jira Issues and feature flags. Create or link existing flags to your Jira issues without leaving your Jira instance. Turn features On/Off right from a linked Issue on your Jira board. You can also easily modify the linked flags to edit or add new Targeting or Percentage Rules. This guide will help you with the plugin installation and familiarise you with the plugin usage. info This integration is for Jira Cloud. It does not work on Jira Data Center or Jira Server instances. ## Installation[​](#installation "Direct link to Installation") 1. Add [ConfigCat Feature Flags](https://marketplace.atlassian.com/1222421) to your Jira Cloud instance. 2. Select **Configure**. 3. Copy your ConfigCat Public API credentials to the inputs. Read more about [ConfigCat Public API credentials here](https://app.configcat.com/my-account/public-api-credentials). 4. Click **Authorize**. info Every Jira user must authorize ConfigCat in Jira who wants to use the ConfigCat Feature Flags Plugin. Your browser does not support the video tag. ## Usage[​](#usage "Direct link to Usage") ### Linking existing feature flags[​](#linking-existing-feature-flags "Direct link to Linking existing feature flags") 1. Navigate to any Issue on your Jira board. 2. Open the **ConfigCat Feature Flag** issue context. 3. On the **Link existing** tab, select a ConfigCat Product, Config, Environment, and Feature Flag to be linked to your Issue. 4. When linked, you can manage the selected feature flag from this Issue. Your browser does not support the video tag. ### Creating new feature flags[​](#creating-new-feature-flags "Direct link to Creating new feature flags") 1. Navigate to any Issue on your Jira board. 2. Open the **ConfigCat Feature Flag** issue context. 3. On the **Create and Link** tab, select a ConfigCat Product and Config where you want to create the feature flag. 4. Set up your feature flag. 5. Select which environment you would like to link to this item. 6. When linked, you can manage the selected feature flag from this Issue. Your browser does not support the video tag. ### View and Edit linked feature flags[​](#view-and-edit-linked-feature-flags "Direct link to View and Edit linked feature flags") 1. Open an Issue on your Jira board with a linked feature flag. 2. See the linked feature flags in the **Feature Flag (ConfigCat)** issue section. 3. You can manage the selected feature flag from this Issue. 4. You can add new Targeting Rules or Percentage Options to Feature Flags. 5. You can add new Targeting Rules with User, Segment or Prerequisite Conditions with a large selection of Comparators. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) 6. You can remove Targeting Rules as well. Your browser does not support the video tag. ### Remove linked feature flags[​](#remove-linked-feature-flags "Direct link to Remove linked feature flags") 1. Open an Issue on your Jira board with a linked feature flag. 2. Remove the linked feature flag by opening the **More menu** and selecting the **Remove from Issue** option. Your browser does not support the video tag. ### View flag status in Releases[​](#view-flag-status-in-releases "Direct link to View flag status in Releases") 1. Open an Issue on your Jira board with a linked feature flag. 2. Check the **Releases** field values in the issue **Details** section to see the linked feature flags status in the Issue. 3. Click it for a more detailed dialog. Your browser does not support the video tag. 1. Open a version in the Jira project's Release Hub page to see the related issues feature flag status. 2. Click it for a more detailed dialog. Your browser does not support the video tag. info This plugin doesn't implement the **Releases - Create/Connect feature flag** action. Instead, you can create or link feature flags from the ConfigCat Feature Flags section below the Details section of the Issue. ### View linked issues in ConfigCat[​](#view-linked-issues-in-configcat "Direct link to View linked issues in ConfigCat") 1. View linked issues next to your Feature Flags in ConfigCat and jump to the Jira Issue directly. Your browser does not support the video tag. --- # Source: https://configcat.com/docs/sdk-reference/js-ssr.md # Legacy JavaScript (SSR) SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/js-ssr-sdk.svg?style=social)](https://github.com/configcat/js-ssr-sdk/stargazers) [![JS-SSR CI](https://github.com/configcat/js-ssr-sdk/actions/workflows/js-ssr-ci.yml/badge.svg?branch=master)](https://github.com/configcat/js-ssr-sdk/actions/workflows/js-ssr-ci.yml) [![codecov](https://codecov.io/gh/configcat/js-ssr-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/configcat/js-ssr-sdk) [![Known Vulnerabilities](https://snyk.io/test/github/configcat/js-ssr-sdk/badge.svg?targetFile=package.json)](https://snyk.io/test/github/configcat/js-ssr-sdk?targetFile=package.json) caution This SDK is superseded by the new [Browser (JavaScript) SDK](https://configcat.com/docs/sdk-reference/js/browser.md). This legacy SDK is in maintenance mode now, it will receive only critical security patches until **official support ends on August 31, 2026**. For guidance on migration, see [this section](#migration-to-the-new-sdk). info This SDK is for Server-Side Rendered JavaScript frameworks like [NuxtJS](https://nuxtjs.org). [ConfigCat JavaScript (SSR) SDK on GitHub](https://github.com/configcat/js-ssr-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install and import package[​](#1-install-and-import-package "Direct link to 1. Install and import package") *via NPM:* ```bash npm i configcat-js-ssr ``` ```js import * as configcat from 'configcat-js-ssr'; ``` ### 2. Create the *ConfigCat* client with your SDK Key[​](#2-create-the-configcat-client-with-your-sdk-key "Direct link to 2-create-the-configcat-client-with-your-sdk-key") ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); ``` ### 3. Get your setting value[​](#3-get-your-setting-value "Direct link to 3. Get your setting value") The async/await way: ```js const value = await configCatClient.getValueAsync( 'isMyAwesomeFeatureEnabled', false, ); if (value) { do_the_new_thing(); } else { do_the_old_thing(); } ``` (Please note that [top-level await in modules](https://exploringjs.com/js/book/ch_modules.html#top-level-await) is available only if your project is [set up to use the ECMAScript module system](https://nodejs.org/api/esm.html). Otherwise you will need either to use Promises or wrap your code in an async function as shown [here](https://github.com/configcat/node-sdk/blob/master/samples/console/index.js).) The Promise way: ```js configCatClient .getValueAsync('isMyAwesomeFeatureEnabled', false) .then((value) => { if (value) { do_the_new_thing(); } else { do_the_old_thing(); } }); ``` ### 4. Dispose the *ConfigCat* client[​](#4-dispose-the-configcat-client "Direct link to 4-dispose-the-configcat-client") You can safely dispose all clients at once or individually and release all associated resources on application exit. ```js configcat.disposeAllClients(); // disposes all clients // -or- configCatClient.dispose(); // disposes a specific client ``` ## Creating the *ConfigCat* Client[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `configcat.getClient('')` returns a client with default options. The `getClient` function has optional parameters, which can be used to adjust the behavior of the client. | Parameters | Description | Default | | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | | `sdkKey` | **REQUIRED.** SDK Key to access your feature flags and settings. Get it from the *ConfigCat Dashboard*. | - | | `pollingMode` | Optional. The polling mode to use to fetch the config data from the ConfigCat CDN. [More about polling modes](#polling-modes). | `PollingMode.AutoPoll` | | `options` | Optional. The options object. See the table below. | - | The available options depends on the chosen polling mode. However, there are some common options which can be set in the case of every polling mode: | Option Parameter | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `logger` | Custom [`IConfigCatLogger`](https://github.com/configcat/common-js/blob/master/src/ConfigCatLogger.ts) implementation for tracing. | [`ConfigCatConsoleLogger`](https://github.com/configcat/common-js/blob/master/src/ConfigCatLogger.ts) (with WARN level) | | `requestTimeoutMs` | The amount of milliseconds the SDK waits for a response from the ConfigCat servers before returning values from the cache. | 30000 | | `baseUrl` | Sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | | `dataGovernance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `DataGovernance.Global`, `DataGovernance.EuOnly`. | `DataGovernance.Global` | | `cache` | Custom [`IConfigCatCache`](https://github.com/configcat/common-js/blob/master/src/ConfigCatCache.ts) implementation for caching the downloaded config. | [`InMemoryConfigCache`](https://github.com/configcat/common-js/blob/master/src/ConfigCatCache.ts) | | `flagOverrides` | Local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | - | | `defaultUser` | Sets the default user. [More about default user](#default-user). | `undefined` (none) | | `offline` | Determines whether the client should be initialized to offline mode. [More about offline mode](#online--offline-mode). | `false` | Options also include a property named `setupHook`, which you can use to subscribe to the hooks (events) at the time of initialization. [More about hooks](#hooks). For example: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('clientReady', () => console.log('Client is ready!')), }, ); ``` info You can acquire singleton client instances for your SDK keys using the `configcat.getClient(sdkKey: "")` factory function. (However, please keep in mind that subsequent calls to `getClient()` with the *same SDK Key* return a *shared* client instance, which was set up by the first call.) You can close all open clients at once using the `configcat.disposeAllClients()` function or do it individually using the `configCatClient.dispose()` method. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") Returns a Promise with the value. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value new configcat.User('#UNIQUE-USER-IDENTIFIER#'), // Optional User Object ); ``` or ```js configCatClient .getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value new configcat.User('#UNIQUE-USER-IDENTIFIER#'), // Optional User Object ) .then((value) => { console.log(value); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | `typeof defaultValue` | | -------------- | --------------------- | | On/Off Toggle | `boolean` | | Text | `string` | | Whole Number | `number` | | Decimal Number | `number` | In addition to the types mentioned above, you also have the option to provide `null` or `undefined` for the `defaultValue` parameter regardless of the setting kind. However, if you do so, the return type of the `getValue` method will be * `boolean | string | number | null` when `defaultValue` is `null` or * `boolean | string | number | undefined` when `defaultValue` is `undefined`. This is because in these cases the exact return type cannot be determined at compile-time as the TypeScript compiler has no information about the setting type. It's important to note that providing any other type for the `defaultValue` parameter will result in a `TypeError`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueDetailsAsync()`[​](#anatomy-of-getvaluedetailsasync "Direct link to anatomy-of-getvaluedetailsasync") `getValueDetailsAsync()` is similar to `getValueAsync()` but instead of returning the evaluated value only, it provides more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const details = await configCatClient.getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value new configcat.User('#UNIQUE-USER-IDENTIFIER#'), // Optional User Object ); ``` or ```js configCatClient .getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value new configcat.User('#UNIQUE-USER-IDENTIFIER#'), // Optional User Object ) .then((details) => { console.log(details); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `key` | `string` | The key of the evaluated feature flag or setting. | | `value` | `boolean` / `string` / `number` | The evaluated value of the feature flag or setting. | | `user` | `User` | The User Object used for the evaluation. | | `isDefaultValue` | `boolean` | True when the default value passed to `getValueDetailsAsync()` is returned due to an error. | | `errorMessage` | `string` | In case of an error, this property contains the error message. | | `errorException` | `any` | In case of an error, this property contains the related exception object (if any). | | `matchedTargetingRule` | `ITargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matchedPercentageOption` | `IPercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `fetchTime` | `Date` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. For simple targeting: ```js let userObject = new configcat.User('#UNIQUE-USER-IDENTIFIER#'); ``` ```js let userObject = new configcat.User('john@example.com'); ``` | Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any `string` value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | For advanced targeting: ```js let userObject = new configcat.User( /* identifier: */ '#UNIQUE-USER-IDENTIFIER#', /* email: */ 'john@example.com', /* country: */ 'United Kingdom', /* custom: */ { SubscriptionType: 'Pro', UserRole: 'Admin', }, ); ``` The `custom` dictionary also allows attribute values other than `string` values: ```js let userObject = new configcat.User('#UNIQUE-USER-IDENTIFIER#'); userObject.custom = { Rating: 4.5, RegisteredAt: new Date('2023-11-22T12:34:56.000Z'), Roles: ['Role1', 'Role2'], }; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `string` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `number` values, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `number` values representing a second-based Unix timestamp, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `string`, * accept `string` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") It's possible to set a default User Object that will be used on feature flag and setting evaluation. It can be useful when your application has a single user only or rarely switches users. You can set the default User Object either on SDK initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { defaultUser: new configcat.User('john@example.com'), }, ); ``` ...or using the `setDefaultUser()` method of the `configCatClient` object: ```js configCatClient.setDefaultUser(new configcat.User('john@example.com')); ``` Whenever the evaluation methods like `getValueAsync()`, `getValueDetailsAsync()`, etc. are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```js const user = new configcat.User('john@example.com'); configCatClient.setDefaultUser(user); // The default user will be used in the evaluation process. const value = await configCatClient.getValueAsync('keyOfMyFeatureFlag', false); ``` When a `user` parameter is passed to the evaluation methods, it takes precedence over the default user. ```js const user = new configcat.User('john@example.com'); configCatClient.setDefaultUser(user); const otherUser = new configcat.User('brian@example.com'); // otherUser will be used in the evaluation process. const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', false, otherUser, ); ``` You can also remove the default user by doing the following: ```js configCatClient.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValueAsync()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. [More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `pollIntervalSeconds` option parameter to change the polling interval. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { pollIntervalSeconds: 95, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `pollIntervalSeconds` | Polling interval in seconds. | 60s | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5s | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValueAsync()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValueAsync()` will return the setting value after the cache is updated. Use `cacheTimeToLiveSeconds` option parameter to set cache lifetime. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.LazyLoad, { cacheTimeToLiveSeconds: 600, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------- | ------- | | `cacheTimeToLiveSeconds` | Cache TTL in seconds. | 60s | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefreshAsync()` is your application's responsibility. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); await configCatClient.forceRefreshAsync(); let value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` > `getValueAsync()` returns `defaultValue` if the cache is empty. Call `forceRefreshAsync()` to update the cache. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); let value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); // console: "my default value" await configCatClient.forceRefreshAsync(); value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `clientReady: [cacheState: ClientCacheState]`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `cacheState` argument. * `configChanged: [newConfig: IConfig]`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `flagEvaluated: [evaluationDetails: IEvaluationDetails]`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetailsAsync()`](#anatomy-of-getvaluedetailsasync). * `clientError: [message: string, exception?: any]`: This event is emitted when an error occurs within the client. You can subscribe to these events either on initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', () => { /* handle the event */ }), }, ); ``` ...or directly on the `ConfigCatClient` instance: ```js configCatClient.on('flagEvaluated', () => { /* handle the event */ }); ``` ## Snapshots and synchronous feature flag evaluation[​](#snapshots-and-synchronous-feature-flag-evaluation "Direct link to Snapshots and synchronous feature flag evaluation") On JavaScript platforms, the *ConfigCat* client provides only asynchronous methods for evaluating feature flags and settings because these operations may involve network communication (e.g. downloading config data from the ConfigCat CDN servers), which is necessarily an asynchronous operation in JavaScript. However, there can be circumstances where synchronous evaluation is preferable, thus, since v7.1.0, the JavaScript (SSR) SDK provides a way to synchronously evaluate feature flags and settings via *snapshots*. Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, ); // Wait for the client to initialize. await configCatClient.waitForReady(); const snapshot = configCatClient.snapshot(); const user = new configcat.User('#UNIQUE-USER-IDENTIFIER#'); for (const key of snapshot.getAllKeys()) { const value = snapshot.getValue(key, null, user); console.log(`${key}: ${value}`); } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefreshAsync`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTimeSeconds` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```js const clientCacheState = await configCatClient.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { // Handle initialization failure (see below). console.warn('ConfigCat client failed to obtain the config data during initialization.'); } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `configChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases where you want to prevent the SDK from making HTTP calls, you can switch it to offline mode: ```js configCatClient.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To switch the SDK back to online mode, do the following: ```js configCatClient.setOnline(); ``` Using the `configCatClient.isOffline` property you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `{ [key: string]: boolean | string | number }` map. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: configcat.createFlagOverridesFromMap( { enabledFeature: true, disabledFeature: false, intSetting: 5, doubleSetting: 3.14, stringSetting: 'test', }, configcat.OverrideBehaviour.LocalOnly, ), }, ); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: configcat.createConsoleLogger(configcat.LogLevel.Info), // Setting log level to Info }, ); ``` Available log levels: | Level | Description | | ----- | ------------------------------------------------------- | | Off | Nothing gets logged. | | Error | Only error level events are logged. | | Warn | Default. Errors and Warnings are logged. | | Info | Errors, Warnings and feature flag evaluation is logged. | | Debug | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash ConfigCat - INFO - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"#SOME-USER-ID#","Email":"configcat@example.com"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") The SDK provides a simple logger implementation that logs to [the debugging console](https://developer.mozilla.org/en-US/docs/Web/API/console) (`configcat.createConsoleLogger(...)`) but it also allows you to inject any custom implementation of `IConfigCatLogger`. ```ts class MyCustomLogger implements IConfigCatLogger { /** * Writes an event into the log. * @param level Event severity level. * @param eventId Event identifier. * @param message Message. * @param exception The exception object related to the message (if any). */ log( level: LogLevel, eventId: LogEventId, message: LogMessage, exception?: any, ): void { // insert your custom log logic } } ``` or ```js function MyCustomLogger() {} MyCustomLogger.prototype.log = function (level, eventId, message, exception) { // insert your custom log logic }; ``` then ```js // set the `MyCustomLogger` implementation on creating the client instance const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: new MyCustomLogger(), }, ); ``` ## `getAllKeysAsync()`[​](#getallkeysasync "Direct link to getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeysAsync()` method. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); const keys = await configCatClient.getAllKeysAsync(); console.log(keys); ``` ## `getAllValuesAsync()`[​](#getallvaluesasync "Direct link to getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValuesAsync(); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); // invoke with User Object const userObject = new configcat.User('john@example.com'); settingValues = await configCatClient.getAllValuesAsync(userObject); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); ``` ## `getAllValueDetailsAsync()`[​](#getallvaluedetailsasync "Direct link to getallvaluedetailsasync") Evaluates and returns the values along with evaluation details of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValueDetailsAsync(); settingValues.forEach((details) => console.log(details)); // invoke with User Object const userObject = new configcat.User('john@example.com'); settingValues = await configCatClient.getAllValueDetailsAsync(userObject); settingValues.forEach((details) => console.log(details)); ``` ## Using custom cache implementation[​](#using-custom-cache-implementation "Direct link to Using custom cache implementation") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`IConfigCatCache`](https://github.com/configcat/common-js/blob/master/src/ConfigCatCache.ts) interface and set the `cache` property in the options passed to `getClient`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```ts class MyCustomCache implements IConfigCatCache { set(key: string, value: string): Promise | void { // insert your cache write logic here } get( key: string, ): Promise | string | null | undefined { // insert your cache read logic here } } ``` or ```js function MyCustomCache() {} MyCustomCache.prototype.set = function (key, value) { // insert your cache write logic here }; MyCustomCache.prototype.get = function (key) { // insert your cache read logic here }; ``` then ```js // set the `MyCustomCache` implementation on creating the client instance const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { cache: new MyCustomCache(), }, ); ``` info The JavaScript (SSR) SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the *ConfigCat SDK* that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Browser compatibility[​](#browser-compatibility "Direct link to Browser compatibility") This SDK should be compatible with all modern browsers. The SDK is [tested](https://github.com/configcat/js-ssr-sdk/blob/master/.github/workflows/js-ssr-ci.yml) against the following browsers: * Chrome (stable, latest, beta) * Chromium (64.0.3282.0, 72.0.3626.0, 80.0.3987.0) * Firefox (latest, latest-beta, 84.0). These tests are running on each pull request, before each deploy, and on a daily basis. You can view a sample run [here](https://github.com/configcat/js-ssr-sdk/actions/runs/6400037904). ## Next.js/AWS lambda recommendation[​](#nextjsaws-lambda-recommendation "Direct link to Next.js/AWS lambda recommendation") If the SDK is running in a Next.js application that is hosted on Vercel (AWS lambda) or your application is hosted directly in AWS lambdas, it is recommended to use the SDK in Lazy loading or Manual polling mode instead of the default Auto polling mode. As AWS lamdbas try to minimize their uptime, the applications are terminated as soon as the sytem detects inactivity in the application. The Auto polling mode is using a background thread to acquire the setting values from the ConfigCat servers periodically and the AWS lambda does not detect it as a running application and terminates it. However, it can easily happen that there is an ongoing HTTP GET call towards our servers and this termination can cause errors. The most possible error message in this case is `Request timed out while trying to fetch config JSON.`. ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [NuxtJS](https://github.com/configcat/js-ssr-sdk/tree/master/samples/nuxt-ssr) ## Guides[​](#guides "Direct link to Guides") See the guides on how to use ConfigCat's JavaScript SSR SDK with the following libraries and frameworks: * [NuxtJS](https://configcat.com/blog/2022/07/01/how-to-use-feature-flags-in-nuxtjs/) * [NextJS](https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/) * [Remix](https://configcat.com/blog/2022/04/01/feature-flags-in-remix/) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat JavaScript (SSR) SDK on GitHub](https://github.com/configcat/js-ssr-sdk) * [ConfigCat JavaScript (SSR) SDK in NPM](https://www.npmjs.com/package/configcat-js-ssr) ## Migration to the new SDK[​](#migration-to-the-new-sdk "Direct link to Migration to the new SDK") The new SDK maintains strong backward compatibility, so migration is typically as simple as: 1. Replacing the old NPM package with the new one. ```bash npm uninstall configcat-js-ssr npm i @configcat/sdk ``` 2. Adjusting the `import` statements, i.e., replacing ```js import * as configcat from 'configcat-js-ssr'; ``` * with the following in client contexts: ```js import * as configcat from '@configcat/sdk/browser'; ``` * with the following in server contexts: ```js import * as configcat from '@configcat/sdk/node'; ``` * with the following if your code needs to run in both contexts: ```js import * as configcat from '@configcat/sdk'; ``` In the case of bundler compatibility or TypeScript issues, refer to [this documentation](https://configcat.com/docs/sdk-reference/js/browser.md#1-install-and-import-package). And usually, that's all there is to it! 🚀 If you encounter issues, please note these minor breaking changes which may require further adjustments: * The config model has been reworked. Interfaces like `IConfig`, `ITargetingRule`, `IPercentageOption` have been replaced with different types (`Config`, `TargetingRule`, `PercentageOption`, etc.) * The `IEvaluationDetails` interface has been deprecated in favor of the new, more accurate `EvaluationDetails` discriminated union type. Although the old type is structurally compatible with the new, it's recommended to use the new one for improved type narrowing. * The `RefreshResult` class has been replaced with a new, more accurate discriminated union type with the same name. In most cases, no further action is necessary on your part. However, you can no longer create instances of it using `new RefreshResult`, `RefreshResult.success()`, etc. For a more comprehensive list of breaking changes, see the [release notes](https://github.com/configcat/js-unified-sdk/releases/tag/v1.0.0). --- # Source: https://configcat.com/docs/sdk-reference/openfeature/js.md # Source: https://configcat.com/docs/sdk-reference/js.md # Legacy JavaScript SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/js-sdk.svg?style=social)](https://github.com/configcat/js-sdk/stargazers) [![JS CI](https://github.com/configcat/js-sdk/actions/workflows/js-ci.yml/badge.svg?branch=master)](https://github.com/configcat/js-sdk/actions/workflows/js-ci.yml) [![codecov](https://codecov.io/gh/configcat/js-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/configcat/js-sdk) [![Known Vulnerabilities](https://snyk.io/test/github/configcat/js-sdk/badge.svg?targetFile=package.json)](https://snyk.io/test/github/configcat/js-sdk?targetFile=package.json) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=configcat_js-sdk\&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=configcat_js-sdk) [![JSDELIVR](https://data.jsdelivr.com/v1/package/npm/configcat-js/badge)](https://www.jsdelivr.com/package/npm/configcat-js) caution This SDK is superseded by the new [Browser (JavaScript) SDK](https://configcat.com/docs/sdk-reference/js/browser.md). This legacy SDK is in maintenance mode now, it will receive only critical security patches until **official support ends on August 31, 2026**. For guidance on migration, see [this section](#migration-to-the-new-sdk). [ConfigCat JavaScript SDK on GitHub](https://github.com/configcat/js-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install and import package[​](#1-install-and-import-package "Direct link to 1. Install and import package") * NPM * CDN ```bash npm i configcat-js ``` ```js import * as configcat from 'configcat-js'; ``` ```html ``` ### 2. Create the *ConfigCat* client with your SDK Key[​](#2-create-the-configcat-client-with-your-sdk-key "Direct link to 2-create-the-configcat-client-with-your-sdk-key") ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); ``` ### 3. Get your setting value[​](#3-get-your-setting-value "Direct link to 3. Get your setting value") The async/await way: ```js const value = await configCatClient.getValueAsync( 'isMyAwesomeFeatureEnabled', false, ); if (value) { do_the_new_thing(); } else { do_the_old_thing(); } ``` (Please note that [top-level await in modules](https://exploringjs.com/js/book/ch_modules.html#top-level-await) may not be available [in older browsers](https://caniuse.com/mdn-javascript_operators_await_top_level). If you need to target such browser versions, you will need to use Promises or wrap your code in an async function or configure your build tools to downlevel this language feature.) The Promise way: ```js configCatClient .getValueAsync('isMyAwesomeFeatureEnabled', false) .then((value) => { if (value) { do_the_new_thing(); } else { do_the_old_thing(); } }); ``` ### 4. Dispose the *ConfigCat* client[​](#4-dispose-the-configcat-client "Direct link to 4-dispose-the-configcat-client") You can safely dispose all clients at once or individually and release all associated resources on application exit. ```js configcat.disposeAllClients(); // disposes all clients // -or- configCatClient.dispose(); // disposes a specific client ``` ## Working Demo on CodePen[​](#working-demo-on-codepen "Direct link to Working Demo on CodePen") See the Pen [ConfigCat Feature Flag Demo](https://codepen.io/configcat/pen/pozaLLV) on [CodePen](https://codepen.io). ## Creating the *ConfigCat* Client[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `configcat.getClient('')` returns a client with default options. The `getClient` function has optional parameters, which can be used to adjust the behavior of the client. | Parameters | Description | Default | | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | | `sdkKey` | **REQUIRED.** SDK Key to access your feature flags and settings. Get it from the *ConfigCat Dashboard*. | - | | `pollingMode` | Optional. The polling mode to use to fetch the config data from the ConfigCat CDN. [More about polling modes](#polling-modes). | `PollingMode.AutoPoll` | | `options` | Optional. The options object. See the table below. | - | The available options depends on the chosen polling mode. However, there are some common options which can be set in the case of every polling mode: | Option Parameter | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `logger` | Custom [`IConfigCatLogger`](https://github.com/configcat/common-js/blob/master/src/ConfigCatLogger.ts) implementation for tracing. | [`ConfigCatConsoleLogger`](https://github.com/configcat/common-js/blob/master/src/ConfigCatLogger.ts) (with WARN level) | | `requestTimeoutMs` | The amount of milliseconds the SDK waits for a response from the ConfigCat servers before returning values from the cache. | 30000 | | `baseUrl` | Sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | | `dataGovernance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `DataGovernance.Global`, `DataGovernance.EuOnly`. | `DataGovernance.Global` | | `cache` | Custom [`IConfigCatCache`](https://github.com/configcat/common-js/blob/master/src/ConfigCatCache.ts) implementation for caching the downloaded config. | [`InMemoryConfigCache`](https://github.com/configcat/common-js/blob/master/src/ConfigCatCache.ts) | | `flagOverrides` | Local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | - | | `defaultUser` | Sets the default user. [More about default user](#default-user). | `undefined` (none) | | `offline` | Determines whether the client should be initialized to offline mode. [More about offline mode](#online--offline-mode). | `false` | Options also include a property named `setupHook`, which you can use to subscribe to the hooks (events) at the time of initialization. [More about hooks](#hooks). For example: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('clientReady', () => console.log('Client is ready!')), }, ); ``` info You can acquire singleton client instances for your SDK keys using the `configcat.getClient(sdkKey: "")` factory function. (However, please keep in mind that subsequent calls to `getClient()` with the *same SDK Key* return a *shared* client instance, which was set up by the first call.) You can close all open clients at once using the `configcat.disposeAllClients()` function or do it individually using the `configCatClient.dispose()` method. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") Returns a Promise with the value. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value new configcat.User('#UNIQUE-USER-IDENTIFIER#'), // Optional User Object ); ``` or ```js configCatClient .getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value new configcat.User('#UNIQUE-USER-IDENTIFIER#'), // Optional User Object ) .then((value) => { console.log(value); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | `typeof defaultValue` | | -------------- | --------------------- | | On/Off Toggle | `boolean` | | Text | `string` | | Whole Number | `number` | | Decimal Number | `number` | In addition to the types mentioned above, you also have the option to provide `null` or `undefined` for the `defaultValue` parameter regardless of the setting kind. However, if you do so, the return type of the `getValue` method will be * `boolean | string | number | null` when `defaultValue` is `null` or * `boolean | string | number | undefined` when `defaultValue` is `undefined`. This is because in these cases the exact return type cannot be determined at compile-time as the TypeScript compiler has no information about the setting type. It's important to note that providing any other type for the `defaultValue` parameter will result in a `TypeError`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueDetailsAsync()`[​](#anatomy-of-getvaluedetailsasync "Direct link to anatomy-of-getvaluedetailsasync") `getValueDetailsAsync()` is similar to `getValueAsync()` but instead of returning the evaluated value only, it provides more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const details = await configCatClient.getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value new configcat.User('#UNIQUE-USER-IDENTIFIER#'), // Optional User Object ); ``` or ```js configCatClient .getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value new configcat.User('#UNIQUE-USER-IDENTIFIER#'), // Optional User Object ) .then((details) => { console.log(details); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `key` | `string` | The key of the evaluated feature flag or setting. | | `value` | `boolean` / `string` / `number` | The evaluated value of the feature flag or setting. | | `user` | `User` | The User Object used for the evaluation. | | `isDefaultValue` | `boolean` | True when the default value passed to `getValueDetailsAsync()` is returned due to an error. | | `errorMessage` | `string` | In case of an error, this property contains the error message. | | `errorException` | `any` | In case of an error, this property contains the related exception object (if any). | | `matchedTargetingRule` | `ITargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matchedPercentageOption` | `IPercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `fetchTime` | `Date` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. For simple targeting: ```js let userObject = new configcat.User('#UNIQUE-USER-IDENTIFIER#'); ``` ```js let userObject = new configcat.User('john@example.com'); ``` | Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any `string` value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | For advanced targeting: ```js let userObject = new configcat.User( /* identifier: */ '#UNIQUE-USER-IDENTIFIER#', /* email: */ 'john@example.com', /* country: */ 'United Kingdom', /* custom: */ { SubscriptionType: 'Pro', UserRole: 'Admin', }, ); ``` The `custom` dictionary also allows attribute values other than `string` values: ```js let userObject = new configcat.User('#UNIQUE-USER-IDENTIFIER#'); userObject.custom = { Rating: 4.5, RegisteredAt: new Date('2023-11-22T12:34:56.000Z'), Roles: ['Role1', 'Role2'], }; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `string` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `number` values, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `number` values representing a second-based Unix timestamp, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `string`, * accept `string` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") It's possible to set a default User Object that will be used on feature flag and setting evaluation. It can be useful when your application has a single user only or rarely switches users. You can set the default User Object either on SDK initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { defaultUser: new configcat.User('john@example.com'), }, ); ``` ...or using the `setDefaultUser()` method of the `configCatClient` object: ```js configCatClient.setDefaultUser(new configcat.User('john@example.com')); ``` Whenever the evaluation methods like `getValueAsync()`, `getValueDetailsAsync()`, etc. are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```js const user = new configcat.User('john@example.com'); configCatClient.setDefaultUser(user); // The default user will be used in the evaluation process. const value = await configCatClient.getValueAsync('keyOfMyFeatureFlag', false); ``` When a `user` parameter is passed to the evaluation methods, it takes precedence over the default user. ```js const user = new configcat.User('john@example.com'); configCatClient.setDefaultUser(user); const otherUser = new configcat.User('brian@example.com'); // otherUser will be used in the evaluation process. const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', false, otherUser, ); ``` You can also remove the default user by doing the following: ```js configCatClient.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValueAsync()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. [More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `pollIntervalSeconds` option parameter to change the polling interval. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { pollIntervalSeconds: 95, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `pollIntervalSeconds` | Polling interval in seconds. | 60s | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5s | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValueAsync()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValueAsync()` will return the setting value after the cache is updated. Use `cacheTimeToLiveSeconds` option parameter to set cache lifetime. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.LazyLoad, { cacheTimeToLiveSeconds: 600, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------- | ------- | | `cacheTimeToLiveSeconds` | Cache TTL in seconds. | 60s | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefreshAsync()` is your application's responsibility. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); await configCatClient.forceRefreshAsync(); let value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` > `getValueAsync()` returns `defaultValue` if the cache is empty. Call `forceRefreshAsync()` to update the cache. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); let value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); // console: "my default value" await configCatClient.forceRefreshAsync(); value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `clientReady: [cacheState: ClientCacheState]`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `cacheState` argument. * `configChanged: [newConfig: IConfig]`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `flagEvaluated: [evaluationDetails: IEvaluationDetails]`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetailsAsync()`](#anatomy-of-getvaluedetailsasync). * `clientError: [message: string, exception?: any]`: This event is emitted when an error occurs within the client. You can subscribe to these events either on initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', () => { /* handle the event */ }), }, ); ``` ...or directly on the `ConfigCatClient` instance: ```js configCatClient.on('flagEvaluated', () => { /* handle the event */ }); ``` ## Snapshots and synchronous feature flag evaluation[​](#snapshots-and-synchronous-feature-flag-evaluation "Direct link to Snapshots and synchronous feature flag evaluation") On JavaScript platforms, the *ConfigCat* client provides only asynchronous methods for evaluating feature flags and settings because these operations may involve network communication (e.g. downloading config data from the ConfigCat CDN servers), which is necessarily an asynchronous operation in JavaScript. However, there can be circumstances where synchronous evaluation is preferable, thus, since v8.1.0, the JavaScript SDK provides a way to synchronously evaluate feature flags and settings via *snapshots*. Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, ); // Wait for the client to initialize. await configCatClient.waitForReady(); const snapshot = configCatClient.snapshot(); const user = new configcat.User('#UNIQUE-USER-IDENTIFIER#'); for (const key of snapshot.getAllKeys()) { const value = snapshot.getValue(key, null, user); console.log(`${key}: ${value}`); } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefreshAsync`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTimeSeconds` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```js const clientCacheState = await configCatClient.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { // Handle initialization failure (see below). console.warn('ConfigCat client failed to obtain the config data during initialization.'); } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `configChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases where you want to prevent the SDK from making HTTP calls, you can switch it to offline mode: ```js configCatClient.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To switch the SDK back to online mode, do the following: ```js configCatClient.setOnline(); ``` Using the `configCatClient.isOffline` property you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `{ [key: string]: boolean | string | number }` map. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: configcat.createFlagOverridesFromMap( { enabledFeature: true, disabledFeature: false, intSetting: 5, doubleSetting: 3.14, stringSetting: 'test', }, configcat.OverrideBehaviour.LocalOnly, ), }, ); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: configcat.createConsoleLogger(configcat.LogLevel.Info), // Setting log level to Info }, ); ``` Available log levels: | Level | Description | | ----- | ------------------------------------------------------- | | Off | Nothing gets logged. | | Error | Only error level events are logged. | | Warn | Default. Errors and Warnings are logged. | | Info | Errors, Warnings and feature flag evaluation is logged. | | Debug | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash ConfigCat - INFO - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"#SOME-USER-ID#","Email":"configcat@example.com"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") The SDK provides a simple logger implementation that logs to [the debugging console](https://developer.mozilla.org/en-US/docs/Web/API/console) (`configcat.createConsoleLogger(...)`) but it also allows you to inject any custom implementation of `IConfigCatLogger`. ```ts class MyCustomLogger implements IConfigCatLogger { /** * Writes an event into the log. * @param level Event severity level. * @param eventId Event identifier. * @param message Message. * @param exception The exception object related to the message (if any). */ log( level: LogLevel, eventId: LogEventId, message: LogMessage, exception?: any, ): void { // insert your custom log logic } } ``` or ```js function MyCustomLogger() {} MyCustomLogger.prototype.log = function (level, eventId, message, exception) { // insert your custom log logic }; ``` then ```js // set the `MyCustomLogger` implementation on creating the client instance const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: new MyCustomLogger(), }, ); ``` ## `getAllKeysAsync()`[​](#getallkeysasync "Direct link to getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeysAsync()` method. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); const keys = await configCatClient.getAllKeysAsync(); console.log(keys); ``` ## `getAllValuesAsync()`[​](#getallvaluesasync "Direct link to getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValuesAsync(); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); // invoke with User Object const userObject = new configcat.User('john@example.com'); settingValues = await configCatClient.getAllValuesAsync(userObject); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); ``` ## `getAllValueDetailsAsync()`[​](#getallvaluedetailsasync "Direct link to getallvaluedetailsasync") Evaluates and returns the values along with evaluation details of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValueDetailsAsync(); settingValues.forEach((details) => console.log(details)); // invoke with User Object const userObject = new configcat.User('john@example.com'); settingValues = await configCatClient.getAllValueDetailsAsync(userObject); settingValues.forEach((details) => console.log(details)); ``` ## Using custom cache implementation[​](#using-custom-cache-implementation "Direct link to Using custom cache implementation") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`IConfigCatCache`](https://github.com/configcat/common-js/blob/master/src/ConfigCatCache.ts) interface and set the `cache` property in the options passed to `getClient`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```ts class MyCustomCache implements IConfigCatCache { set(key: string, value: string): Promise | void { // insert your cache write logic here } get( key: string, ): Promise | string | null | undefined { // insert your cache read logic here } } ``` or ```js function MyCustomCache() {} MyCustomCache.prototype.set = function (key, value) { // insert your cache write logic here }; MyCustomCache.prototype.get = function (key) { // insert your cache read logic here }; ``` then ```js // set the `MyCustomCache` implementation on creating the client instance const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { cache: new MyCustomCache(), }, ); ``` info The JavaScript SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the *ConfigCat SDK* that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Browser compatibility[​](#browser-compatibility "Direct link to Browser compatibility") This SDK should be compatible with all modern browsers. The SDK is [tested](https://github.com/configcat/js-sdk/blob/master/.github/workflows/js-ci.yml) against the following browsers: * Chrome (stable, latest, beta) * Chromium (64.0.3282.0, 72.0.3626.0, 80.0.3987.0) * Firefox (latest, latest-beta, 84.0). These tests are running on each pull request, before each deploy, and on a daily basis. You can view a sample run [here](https://github.com/configcat/js-sdk/actions/runs/6399980215). ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [Angular 2+](https://github.com/configcat/js-sdk/tree/master/samples/angular-sample) * [React](https://github.com/configcat/js-sdk/tree/master/samples/react-sample) * [Pure HTML + JS](https://github.com/configcat/js-sdk/tree/master/samples/html) ## Guides[​](#guides "Direct link to Guides") See the guides on how to use ConfigCat's JavaScript SDK with the following libraries and frameworks: * [React](https://configcat.com/blog/2021/12/13/feature-flags-in-react/) * [Angular](https://configcat.com/blog/2022/08/09/using-feature-flags-in-angular/) * [VueJS](https://configcat.com/blog/2022/01/28/how-to-use-feature-flag-in-vuejs/) * [Ionic](https://configcat.com/blog/2022/07/29/how-to-use-feature-flags-in-ionic-js/) * [Phaser](https://configcat.com/blog/2022/02/04/feature-flags-in-phaser/) * [Solid.js](https://configcat.com/blog/2022/11/11/how-to-use-feature-flags-in-solidjs/) * [melonJS](https://configcat.com/blog/2022/02/19/feature-flags-in-melonjs/) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat JavaScript SDK on GitHub](https://github.com/configcat/js-sdk) * [ConfigCat JavaScript SDK in NPM](https://www.npmjs.com/package/configcat-js) ## Migration to the new SDK[​](#migration-to-the-new-sdk "Direct link to Migration to the new SDK") The new SDK maintains strong backward compatibility, so migration is typically as simple as: 1. Replacing the old NPM package with the new one. ```bash npm uninstall configcat-js npm i @configcat/sdk ``` 2. Adjusting the `import` statements, i.e., replacing ```js import * as configcat from 'configcat-js'; ``` with ```js import * as configcat from '@configcat/sdk/browser'; ``` In the case of bundler compatibility or TypeScript issues, refer to [this documentation](https://configcat.com/docs/sdk-reference/js/browser.md#1-install-and-import-package). And usually, that's all there is to it! 🚀 If you encounter issues, please note these minor breaking changes which may require further adjustments: * The config model has been reworked. Interfaces like `IConfig`, `ITargetingRule`, `IPercentageOption` have been replaced with different types (`Config`, `TargetingRule`, `PercentageOption`, etc.) * The `IEvaluationDetails` interface has been deprecated in favor of the new, more accurate `EvaluationDetails` discriminated union type. Although the old type is structurally compatible with the new, it's recommended to use the new one for improved type narrowing. * The `RefreshResult` class has been replaced with a new, more accurate discriminated union type with the same name. In most cases, no further action is necessary on your part. However, you can no longer create instances of it using `new RefreshResult`, `RefreshResult.success()`, etc. For a more comprehensive list of breaking changes, see the [release notes](https://github.com/configcat/js-unified-sdk/releases/tag/v1.0.0). --- # Source: https://configcat.com/docs/sdk-reference/openfeature/kotlin.md # Source: https://configcat.com/docs/sdk-reference/kotlin.md # Kotlin Multiplatform SDK Reference Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/kotlin-sdk.svg?style=social)](https://github.com/configcat/kotlin-sdk/stargazers) [![Kotlin CI](https://github.com/configcat/kotlin-sdk/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/configcat/kotlin-sdk/actions/workflows/ci.yml) [![Maven Central](https://img.shields.io/maven-central/v/com.configcat/configcat-kotlin-client?label=maven%20central)](https://search.maven.org/artifact/com.configcat/configcat-kotlin-client/) [![Quality Gate Status](https://img.shields.io/sonar/quality_gate/configcat_kotlin-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_kotlin-sdk) [![SonarCloud Coverage](https://img.shields.io/sonar/coverage/configcat_kotlin-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_kotlin-sdk) * [ConfigCat Kotlin Multiplatform SDK on GitHub](https://github.com/configcat/kotlin-sdk) * [API Documentation](https://configcat.github.io/kotlin-sdk/) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install the ConfigCat SDK[​](#1-install-the-configcat-sdk "Direct link to 1. Install the ConfigCat SDK") build.bradle.kts ```kotlin val configcatVersion: String by project kotlin { sourceSets { val commonMain by getting { dependencies { implementation("com.configcat:configcat-kotlin-client:configcatVersion") } } } } ``` ### 2. Import the ConfigCat SDK[​](#2-import-the-configcat-sdk "Direct link to 2. Import the ConfigCat SDK") ```kotlin import com.configcat.* ``` ### 3. Create the ConfigCat client with your SDK Key[​](#3-create-the-configcat-client-with-your-sdk-key "Direct link to 3. Create the ConfigCat client with your SDK Key") ```kotlin import com.configcat.* suspend fun main() { val client = ConfigCatClient("#YOUR-SDK-KEY#") } ``` ### 4. Get your setting value[​](#4-get-your-setting-value "Direct link to 4. Get your setting value") ```kotlin import com.configcat.* suspend fun main() { val client = ConfigCatClient("#YOUR-SDK-KEY#") val isMyAwesomeFeatureEnabled = client.getValue("isMyAwesomeFeatureEnabled", false) if (isMyAwesomeFeatureEnabled) { doTheNewThing() } else { doTheOldThing() } } ``` The *ConfigCat SDK* also offers a synchronous API for feature flag evaluation. Read more [here](#snapshots-and-non-blocking-synchronous-feature-flag-evaluation). ### 5. Close the client on application exit[​](#5-close-the-client-on-application-exit "Direct link to 5. Close the client on application exit") You can safely shut down all clients at once or individually and release all associated resources on application exit. ```kotlin ConfigCatClient.closeAll() // closes all clients client.close() // closes a specific client ``` ## Setting up the *ConfigCat Client*[​](#setting-up-the-configcat-client "Direct link to setting-up-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `ConfigCatClient()` returns a client with default options. ### Customizing the *ConfigCat Client*[​](#customizing-the-configcat-client "Direct link to customizing-the-configcat-client") To customize the SDK's behavior, you can pass an additional `ConfigCatOptions.() -> Unit` parameter to the `ConfigCatClient()` method where the `ConfigCatOptions` class is used to set up the *ConfigCat Client*. ```kotlin import com.configcat.* import kotlin.time.Duration.Companion.seconds val client = ConfigCatClient("#YOUR-SDK-KEY#") { pollingMode = autoPoll() logLevel = LogLevel.INFO requestTimeout = 10.seconds } ``` These are the available options on the `ConfigCatOptions` class: | Properties | Type | Description | | ---------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dataGovernance` | `DataGovernance` | Optional, defaults to `DataGovernance.GLOBAL`. Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `DataGovernance.GLOBAL`, `DataGovernance.EU_ONLY`. | | `baseUrl` | `String` | Optional, sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | `requestTimeout` | `Duration` | Optional, defaults to `30s`. Sets the underlying HTTP client's request timeout. [More about HTTP Timeout](#http-timeout). | | `configCache` | `ConfigCache` | Optional, sets a custom cache implementation for the client. [More about cache](#custom-cache). | | `pollingMode` | `PollingMode` | Optional, sets the polling mode for the client. [More about polling modes](#polling-modes). | | `logger` | `Logger` | Optional, sets the internal logger. [More about logging](#logging). | | `logLevel` | `LogLevel` | Optional, defaults to `LogLevel.WARNING`. Sets the internal log level. [More about logging](#logging). | | `flagOverrides` | `(FlagOverrides.() -> Unit)?` | Optional, sets the local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | `httpEngine` | `HttpClientEngine?` | Optional, sets the underlying `Ktor` HTTP engine. [More about HTTP engines](#http-engine). | | `httpProxy` | `ProxyConfig?` | Optional, sets up the HTTP proxy for the underlying `Ktor` HTTP engine. [More about HTTP proxy](#http-proxy). | | `defaultUser` | `ConfigCatUser?` | Optional, sets the default user. [More about default user](#default-user). | | `offline` | `Bool` | Optional, defaults to `false`. Indicates whether the SDK should be initialized in offline mode. [More about offline mode](#online--offline-mode). | | `hooks` | `Hooks` | Optional, used to subscribe events that the SDK sends in specific scenarios. [More about hooks](#hooks). | caution We strongly recommend you to use the `ConfigCatClient` as a Singleton object in your application. The `ConfigCatClient(sdkKey: )` method constructs singleton client instances for your SDK keys. These clients can be closed all at once with the `ConfigCatClient.closeAll()` method or individually with `client.close()`. ## Anatomy of `getValue()`[​](#anatomy-of-getvalue "Direct link to anatomy-of-getvalue") | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```kotlin val value = client.getValue( key = "keyOfMySetting", defaultValue = false, user = ConfigCatUser(identifier = "#USER-IDENTIFIER#"), // Optional User Object ) ``` caution It is important to provide an argument for the `defaultValue` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | Type parameter `T` | | -------------- | ---------------------- | | On/Off Toggle | `Boolean` / `Boolean?` | | Text | `String` / `String?` | | Whole Number | `Integer` / `Integer?` | | Decimal Number | `Double` / `Double?` | In addition to the types mentioned above, you also have the option to use the `getAnyValue` method, where the `defaultValue` parameter can be any value (including `null`) regardless of the setting kind. It's important to note that providing any other type for the type parameter will result in an `IllegalArgumentException`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. When relying on type inference and not explicitly specifying the type parameter, be mindful of potential type mismatch issues, especially with number types. For example, `client.getValue("keyOfMyDecimalSetting", 0)` will return `defaultValue` (`0`) instead of the actual value of the decimal setting because the compiler infers the type as `Integer` instead of `Double`, that is, the call is equivalent to `client.getValue("keyOfMyDecimalSetting", 0)`, which is a type mismatch. To correctly evaluate a decimal setting, you should use: ```kotlin var value = client.getValue("keyOfMyDecimalSetting", 0.0); ``` ## Anatomy of `getValueDetails()`[​](#anatomy-of-getvaluedetails "Direct link to anatomy-of-getvaluedetails") `getValueDetails()` is similar to `getValue()` but instead of returning the evaluated value only, it gives more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** Setting-specific key. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```kotlin val details = client.getValueDetails( key = "keyOfMySetting", defaultValue = false, user = ConfigCatUser(identifier = "#USER-IDENTIFIER#"), // Optional User Object ) ``` caution It is important to provide an argument for the `defaultValue` parameter, specifically for the `T` generic type parameter, that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The details result contains the following information: | Field | Type | Description | | --------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `value` | `Boolean` / `String` / `Int` / `Double` | The evaluated value of the feature flag or setting. | | `key` | `String` | The key of the evaluated feature flag or setting. | | `isDefaultValue` | `Boolean` | True when the default value passed to `getValueDetails()` is returned due to an error. | | `error` | `String?` | In case of an error, this property contains the error message. | | `user` | `ConfigCatUser?` | The User Object that was used for evaluation. | | `matchedPercentageOption` | `PercentageOption?` | The Percentage Option (if any) that was used to select the evaluated value. | | `matchedTargetingRule` | `TargetingRule?` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `fetchTimeUnixMilliseconds` | `Long` | The last download time of the current config in unix milliseconds format. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. ```kotlin val user = ConfigCatUser(identifier = "#UNIQUE-USER-IDENTIFIER#") ``` ```kotlin val user = ConfigCatUser(identifier = "john@example.com") ``` ### Customized User Object creation[​](#customized-user-object-creation "Direct link to Customized User Object creation") | Argument | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------ | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional map for custom attributes of a user for advanced Targeting Rule definitions. e.g. User role, Subscription type. | ```kotlin val user = ConfigCatUser( identifier = "#UNIQUE-USER-IDENTIFIER#", email = "john@example.com", country = "United Kingdom", custom = mapOf( "SubscriptionType" to "Pro", "UserRole" to "Admin" ) ) ``` The `custom` map also allows attribute values other than `String` values: ```kotlin val user = ConfigCatUser( identifier = "#UNIQUE-USER-IDENTIFIER#", email = "john@example.com", country = "United Kingdom", custom = mapOf( "Rating" to 4.5, "RegisteredAt" to Instant.parse("2023-11-22T12:34:56.999Z"), "Roles" to arrayOf("Role1", "Role2") ) ) ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `String` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `String` values, * all other values are automatically converted to `String` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `String` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `Double` values and all other numeric values which can safely be converted to `Double`, * accept `String` values containing a properly formatted, valid `Double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `kotlin.time.Instant` values, which are automatically converted to a second-based Unix timestamp, * accept `Double` values representing a second-based Unix timestamp and all other numeric values which can safely be converted to `Double`, * accept `String` values containing a properly formatted, valid `Double` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept lists or array of `String`, * accept `String` values containing a valid JSON string which can be deserialized to an array of `String`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") There's an option to set a default User Object that will be used at feature flag and setting evaluation. It can be useful when your application has a single user only, or rarely switches users. You can set the default User Object either on SDK initialization: ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") { defaultUser = ConfigCatUser(identifier = "john@example.com") } ``` or with the `setDefaultUser()` method of the ConfigCat client. ```kotlin client.setDefaultUser(ConfigCatUser(identifier = "john@example.com")) ``` Whenever the `getValue()`, `getValueDetails()`, or `getAllValues()` methods are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```kotlin val user = ConfigCatUser(identifier = "john@example.com") client.setDefaultUser(user) // The default user will be used at the evaluation process. val value = client.getValue("keyOfMySetting", false) ``` When the `user` parameter is specified on the requesting method, it takes precedence over the default user. ```kotlin val user = ConfigCatUser(identifier = "john@example.com") client.setDefaultUser(user) val otherUser = ConfigCatUser(identifier = "brian@example.com") // otherUser will be used at the evaluation process. val value = client.getValue("keyOfMySetting", false, otherUser) ``` For deleting the default user, you can do the following: ```kotlin client.clearDefaultUser() ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValue()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle.
[More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the the `pollingInterval` option parameter of the `autoPoll()` to change the polling interval. ```kotlin import com.configcat.* import kotlin.time.Duration.Companion.seconds val client = ConfigCatClient("#YOUR-SDK-KEY#") { pollingMode = autoPoll { pollingInterval = 100.seconds } } ``` Available options: | Option Parameter | Description | Default | | ----------------- | --------------------------------------------------------------------------------------------------- | ------------ | | `pollingInterval` | Polling interval. | `60.seconds` | | `maxInitWaitTime` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | `5.seconds` | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValue()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValue()` will return the setting value after the cache is updated. Use the `cacheRefreshInterval` option parameter of the `lazyLoad()` to set cache lifetime. ```kotlin import com.configcat.* import kotlin.time.Duration.Companion.seconds val client = ConfigCatClient("#YOUR-SDK-KEY#") { pollingMode = lazyLoad { cacheRefreshInterval = 100.seconds } } ``` Available options: | Parameter | Description | Default | | ---------------------- | ----------- | ------------ | | `cacheRefreshInterval` | Cache TTL. | `60.seconds` | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefresh()` is your application's responsibility. ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") { pollingMode = manualPoll() } client.forceRefresh() ``` > `getValue()` returns `defaultValue` if the cache is empty. Call `forceRefresh()` to update the cache. ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `onClientReady(ClientCacheState)`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTime` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `ClientCacheState` argument. * `onConfigChanged(Map, ConfigCatClientSnapshot)`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `onFlagEvaluated(EvaluationDetails)`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetails()`](#anatomy-of-getvaluedetails). * `onError(String)`: This event is emitted when an error occurs within the client. You can subscribe to these events either on SDK initialization: ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") { hooks.addOnFlagEvaluated { details -> /* handle the event */ } } ``` or with the `hooks` property of the ConfigCat client: ```kotlin client.hooks.addOnFlagEvaluated { details -> /* handle the event */ } ``` ## Snapshots and non-blocking synchronous feature flag evaluation[​](#snapshots-and-non-blocking-synchronous-feature-flag-evaluation "Direct link to Snapshots and non-blocking synchronous feature flag evaluation") The *ConfigCat* client doesn't directly provide synchronous methods for evaluating feature flags and settings because such synchronous methods could block the executing thread for longer periods of time (e.g. when downloading config data from the ConfigCat CDN servers), which could lead to an unresponsive application. However, there can be circumstances where synchronous evaluation is preferable, thus, since `v4.2.0`, the Kotlin Multiplatform SDK provides a way to synchronously evaluate feature flags and settings as a non-blocking operation, via *snapshots*. Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") { pollingMode = autoPoll } // Wait for the client to initialize. client.waitForReady() val snapshot = client.snapshot() val user = ConfigCatUser(identifier = "#UNIQUE-USER-IDENTIFIER#") for (key in snapshot.getAllKeys()) { val value = snapshot.getAnyValue(key, null, user) println("$key: $value") } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefresh`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTime` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```kotlin val clientCacheState = client.waitForReady() if (clientCacheState == ClientCacheState.NO_FLAG_DATA) { // Handle initialization failure (see below). } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `onConfigChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases when you'd want to prevent the SDK from making HTTP calls, you can put it in offline mode: ```kotlin client.setOffline() ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To put the SDK back in online mode, you can do the following: ```kotlin client.setOnline() ``` > With `client.isOffline` you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehavior.LOCAL_ONLY`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehavior.LOCAL_OVER_REMOTE`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehavior.REMOTE_OVER_LOCAL`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. ### Map[​](#map "Direct link to Map") You can set up the SDK to load your feature flag & setting overrides from a `Map`. ```kotlin val client = ConfigCatClient("localhost") { flagOverrides = { behavior = OverrideBehavior.LOCAL_ONLY dataSource = OverrideDataSource.map( mapOf( "enabledFeature" to true, "disabledFeature" to false, "intSetting" to 5, "doubleSetting" to 3.14, "stringSetting" to "test" ) ) } } ``` ### Config[​](#config "Direct link to Config") You can set up the SDK to load your feature flag & setting overrides from a `Config`. ```kotlin val client = ConfigCatClient("localhost") { flagOverrides = { behavior = OverrideBehavior.LOCAL_ONLY dataSource = OverrideDataSource.config( config = Config( preferences = Preferences(baseUrl = "test", salt = "test-salt"), settings = mapOf( "noRuleOverride" to Setting( 1, "", null, null, SettingsValue(stringValue = "noRule"), "myVariationId" ), "ruleOverride" to Setting( 1, "", null, arrayOf( TargetingRule( conditions = arrayOf( Condition( UserCondition("Identifier", 2, stringArrayValue = arrayOf("@test1")), null, null ) ), null, ServedValue( SettingsValue(stringValue = "ruleMatch"), "ruleVariationId" ) ) ), SettingsValue(stringValue = "noMatch"), "myVariationId" ), "percentageOverride" to Setting( 1, "", arrayOf( PercentageOption(75, SettingsValue(stringValue = "A"), "percentageAVariationID"), PercentageOption(25, SettingsValue(stringValue = "B"), "percentageAVariationID") ), emptyArray(), SettingsValue(stringValue = "noMatch"), "myVariationId" ) ) ) ) } } ``` ## `getAllKeys()`[​](#getallkeys "Direct link to getallkeys") You can get the keys for all available feature flags and settings by calling the `getAllKeys()` method. ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") val keys = client.getAllKeys() ``` ## `getAllValues()`[​](#getallvalues "Direct link to getallvalues") Evaluates and returns the values of all feature flags and settings. Passing a User Object is optional. ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") val settingValues = client.getAllValues() // invoke with User Object val user = ConfigCatUser(identifier = "#UNIQUE-USER-IDENTIFIER#") val settingValuesTargeting = client.getAllValues(user) ``` ## Cache[​](#cache "Direct link to Cache") The SDK uses platform specific caching to store the downloaded `config JSON`.
These are the storage locations by platform: * **Android**: `SharedPreferences`. It has a dependency on `android.content.Context`, so it won't be enabled by default, but it can be explicitly set by providing an appropriate `Context`. ([Here](https://github.com/configcat/kotlin-sdk/blob/main/samples/android/app/src/main/java/com/example/configcat_android/MainActivity.kt#L23) is an example) * **iOS / macOS / tvOS / watchOS**: `NSUserDefaults`. * **JS (browser only)**: Browser `localStorage`. * On other platforms the SDK uses a memory-only cache. If you want to turn off the default behavior, you can set the SDK's cache to `null` or to your own cache implementation. ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") { configCache = null } ``` ### Custom Cache[​](#custom-cache "Direct link to Custom Cache") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`ConfigCache`](https://github.com/configcat/kotlin-sdk/blob/main/src/commonMain/kotlin/com/configcat/ConfigCache.kt) interface and set the `configCache` parameter in the setup callback of `ConfigCatClient`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```kotlin class MyCustomCache : ConfigCache { override suspend fun read(key: String): String? { // here you have to return with the cached value } override suspend fun write(key: String, value: String) { // here you have to store the new value in the cache } } ``` Then use your custom cache implementation: ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") { configCache = MyCustomCache() } ``` info The Kotlin SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## HTTP Engine[​](#http-engine "Direct link to HTTP Engine") The ConfigCat SDK internally uses [Ktor](https://ktor.io) to download the latest config JSON over HTTP. For each platform the SDK includes a specific [HTTP engine](https://ktor.io/docs/http-client-engines.html#limitations): * **Android / JVM**: `ktor-client-okhttp` * **macOS / iOS / tvOS / watchOS**: `ktor-client-darwin` * **JavaScript / Node.js**: `ktor-client-js` * **Windows / Linux**: It is possible to use Ktor's [Curl engine](https://ktor.io/docs/http-client-engines.html#curl). You can set/override the HTTP engine like the following: ```kotlin // this example sets up the SDK to use the Curl engine for HTTP communication. import com.configcat.* import io.ktor.client.engine.curl.* val client = ConfigCatClient("#YOUR-SDK-KEY#") { httpEngine = Curl.create { // additional engine setup } } ``` ### HTTP Timeout[​](#http-timeout "Direct link to HTTP Timeout") You can set the maximum wait time for a ConfigCat HTTP response. ```kotlin import com.configcat.* import kotlin.time.Duration.Companion.seconds val client = ConfigCatClient("#YOUR-SDK-KEY#") { requestTimeout = 10.seconds } ``` > The default request timeout is 30 seconds. ### HTTP Proxy[​](#http-proxy "Direct link to HTTP Proxy") If your application runs behind a proxy you can do the following: ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") { httpProxy = ProxyBuilder.http("http://proxy-server:1234/") } ``` > You can check the availability of the proxy configuration in specific HTTP engines [here](https://ktor.io/docs/proxy.html). ## Force refresh[​](#force-refresh "Direct link to Force refresh") Call the `forceRefresh()` method on the client to download the latest config JSON and update the cache. ## Logging[​](#logging "Direct link to Logging") The default logger used by the SDK is simply using `println()` to log messages, but you can override it with your custom logger implementation via the `logger` client option. The custom implementation must satisfy the [Logger](https://github.com/configcat/kotlin-sdk/blob/main/src/commonMain/kotlin/com/configcat/log/Logger.kt) interface. ```kotlin class MyCustomLogger: Logger { override fun error(message: String) { // write the error logs } override fun error(message: String, throwable: Throwable) { // write the error logs } override fun warning(message: String) { // write the warning logs } override fun info(message: String) { // write the info logs } override fun debug(message: String) { // write the debug logs } } ``` Then you can use your custom logger implementation at the SDK's initialization: ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") { logger = MyCustomLogger() } ``` You can change the verbosity of the logs by passing a `logLevel` parameter to the client options. ```kotlin val client = ConfigCatClient("#YOUR-SDK-KEY#") { logLevel = LogLevel.INFO } ``` Available log levels: | Level | Description | | --------- | --------------------------------------------------------------------------------------- | | `OFF` | Turn the logging off. | | `ERROR` | Only error level events are logged. | | `WARNING` | Default. Errors and Warnings are logged. | | `INFO` | Errors, Warnings and feature flag evaluation is logged. | | `DEBUG` | All of the above plus debug info is logged. Debug logs can be different for other SDKs. | Info level logging helps to inspect how a feature flag was evaluated: ```bash [INFO] 2022-01-20T18:22:02.313703 ConfigCat - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"","Email":"configcat@example.com","Country":"US","SubscriptionType":"Pro","Role":"Admin","version":"1.0.0"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'False' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'True' => MATCH, applying rule Returning 'True'. ``` ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the ConfigCat SDK that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Sample Apps[​](#sample-apps "Direct link to Sample Apps") Check out our Sample Applications how they use the ConfigCat SDK * [Kotlin Multiplatform Mobile app](https://github.com/configcat/kotlin-sdk/tree/main/samples/kmm) * [Android app](https://github.com/configcat/kotlin-sdk/tree/main/samples/android) * [Kotlin app](https://github.com/configcat/kotlin-sdk/tree/main/samples/kotlin) * [React app](https://github.com/configcat/kotlin-sdk/tree/main/samples/js) * [Node.js app](https://github.com/configcat/kotlin-sdk/tree/main/samples/node-js) ## Look Under the Hood[​](#look-under-the-hood "Direct link to Look Under the Hood") * [ConfigCat Kotlin Multiplatform SDK's repository on GitHub](https://github.com/configcat/kotlin-sdk) * [ConfigCat Kotlin Multiplatform SDK's API documentation](https://configcat.github.io/kotlin-sdk/) * [ConfigCat Kotlin Multiplatform SDK on Maven Central](https://central.sonatype.com/artifact/com.configcat/configcat-kotlin-client) --- # Source: https://configcat.com/docs/sdk-reference/community/laravel.md # ConfigCat package for Laravel Copy page [![Star on GitHub](https://img.shields.io/github/stars/pod-point/laravel-configcat.svg?style=social)](https://github.com/pod-point/laravel-configcat/stargazers) [![Latest Version on Packagist](https://img.shields.io/packagist/v/pod-point/laravel-configcat.svg?style=flat-square)](https://packagist.org/packages/pod-point/laravel-configcat) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/pod-point/laravel-configcat/run-tests.yml?branch=main\&label=tests) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/Pod-Point/laravel-configcat/blob/main/LICENSE.md) [![Total Downloads](https://img.shields.io/packagist/dt/pod-point/laravel-configcat.svg?style=flat-square)](https://packagist.org/packages/pod-point/laravel-configcat) caution As this is a community maintained package, ConfigCat can't guarantee it's stability, safety and can't provide official customer support. [ConfigCat package for Laravel on GitHub](https://github.com/Pod-Point/laravel-configcat) ## Installation[​](#installation "Direct link to Installation") You can install the package via composer: ```bash composer require pod-point/laravel-configcat ``` ### Publishing the config file[​](#publishing-the-config-file "Direct link to Publishing the config file") Next, you should publish the Laravel package configuration file using the `vendor:publish` Artisan command. It will be placed in your application's config directory: ```bash php artisan vendor:publish --provider="PodPoint\ConfigCat\ConfigCatServiceProvider" ``` Don't forget to specify your [ConfigCat SDK `key`](https://app.configcat.com/sdkkey) within the freshly published Laravel configuration file under `config/configcat.php`. The Laravel configuration for this package comes with sensible defaults. See [`config/configcat.php`](https://github.com/Pod-Point/laravel-configcat/blob/main/config/configcat.php) for more details. ## Usage[​](#usage "Direct link to Usage") ### Facade & global helper[​](#facade--global-helper "Direct link to Facade & global helper") The `ConfigCat` facade as well as the global helper can be used to retrieve the actual value of the feature flag, text or number setting: ```php use PodPoint\ConfigCat\Facades\ConfigCat; $flag = ConfigCat::get('new_registration_flow'); $flag = configcat('new_registration_flow'); ``` > **Note:** You can define the actual value of a feature flag to be `bool(true)` or `bool(false)` on ConfigCat but not only, it can also be [a number or a text setting](https://configcat.com/docs/main-concepts.md#about-setting-types). If the feature flag is undefined or something went wrong, `bool(false)` will be returned by default, however you can change this by specifying a default value **only when using the Facade or the global helper** to retrieve the feature flag value using: ```php use PodPoint\ConfigCat\Facades\ConfigCat; $flag = ConfigCat::get('new_registration_flow', true); $flag = configcat('new_registration_flow', true); ``` You can also globally sepcify a default value from the [`config/configcat.php`](https://github.com/Pod-Point/laravel-configcat/blob/main/config/configcat.php) file. ⚠️ **Only** `boolean`, `string`, `integer` or `float` default value types are supported as these are the only [setting types](https://configcat.com/docs/main-concepts.md#about-setting-types) available from ConfigCat. ### Validation rule[​](#validation-rule "Direct link to Validation rule") Given the following validation rules: ```php Validator::make([ 'email' => 'taylor@laravel.com', 'username' => 'taylor', ], [ 'email' => 'required_if_configcat:new_registration_flow,true', 'username' => 'required_if_configcat:new_registration_flow,false', ]); ``` * When the feature flag is **on** * The `email` will be a required field * The `username` will be an optional field * When the feature flag is **off**, undefined, a text or number setting * The `email` will be an optional field * The `username` will be a required field ### HTTP middleware[​](#http-middleware "Direct link to HTTP middleware") The following route will only be accessible if the [feature flag](https://configcat.com/docs/main-concepts.md#about-setting-types) is truthy, otherwise a `404` will be thrown. ```php Router::get('/registration')->middleware('configcat.on:new_registration_flow'); ``` The opposite is possible, also throwing a `404` if the feature flag is falsy: ```php Router::get('/sign-up')->middleware('configcat.off:new_registration_flow'); ``` **Note:** undefined, text or number settings will be considered as feature flags turned `off`. ### Blade directive[​](#blade-directive "Direct link to Blade directive") The following view content will only be rendered if the feature flag is truthy: ```blade @configcat('new_registration_flow') New registration form @endconfigcat ``` ```blade @unlessconfigcat('new_registration_flow') Old registration form @endconfigcat ``` ```blade @configcat('new_registration_flow_1') Sign up @elseconfigcat('new_registration_flow_2') Get started @else Register @endconfigcat ``` **Note:** undefined, text or number settings will be considered as feature flags turned `off`. ## Advanced usage[​](#advanced-usage "Direct link to Advanced usage") ### User targeting[​](#user-targeting "Direct link to User targeting") The [User Object](https://configcat.com/docs/sdk-reference/php.md#user-object) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. ConfigCat needs to understand the representation of your users from your application. To do so, you will need to transform your user into a `ConfigCat\User` object. This can be done directly from the [`config/configcat.php`](https://github.com/Pod-Point/laravel-configcat/blob/main/config/configcat.php) file. Here is an example: ```php 'user' => \PodPoint\ConfigCat\Support\DefaultUserTransformer::class, ``` Which will be using a sensible default transformer: ```php class DefaultUserTransformer { public function __invoke(\Illuminate\Foundation\Auth\User $user) { return new \ConfigCat\User($user->getKey(), $user->email); } } ``` Feel free to create your own transformer class and use it instead, just **remember** that it needs to be **callable** with the `__invoke()` function. > **Note:** for security reasons, all of the logic computation for the user targeting is executed on your application side of things using ConfigCat's SDK. No user details will be leaving your application in order find out wether or not a user should have a feature flag enabled or not. Once you have defined your mapping, you will be able to explicitly use the representation of your user when checking a feature flag: ```php use App\Models\User; use PodPoint\ConfigCat\Facades\ConfigCat; $user = User::where('email', 'taylor@laravel.com')->firstOrFail(); ConfigCat::get('new_registration_flow', $default, $user); ``` This is also applicable for the global helper and the Blade directive: ```php configcat('new_registration_flow', $default, $user); ``` ```blade @configcat('new_registration_flow', $user) New registration form @endconfigcat ``` > **Note:** if you have defined your user mapping but are not explicitly using a specific user when checking for a flag, we will automatically try to use the logged in user, if any, for convenience. ### Caching & logging[​](#caching--logging "Direct link to Caching & logging") This package supports native Laravel caching and logging capabilities in order to cache the feature flag values from ConfigCat's CDN as well as log any information when resolving feature flags. We've setup some sensible defaults but various levels of caching and logging can be configured. See [`config/configcat.php`](https://github.com/Pod-Point/laravel-configcat/blob/main/config/configcat.php) for more info. ### Test support: mock, fake & overrides[​](#test-support-mock-fake--overrides "Direct link to Test support: mock, fake & overrides") #### In-memory testing[​](#in-memory-testing "Direct link to In-memory testing") When writing unit or functional tests, you may need to be able to mock or fake this package completely so you can test various behaviors within your application. This is all possible through the powerful Facade. **Mocking:** ```php use PodPoint\ConfigCat\Facades\ConfigCat; ConfigCat::shouldReceive('get') ->once() ->with('new_registration_flow') ->andReturn(true); ``` See for more info. **Fake:** Faking it will prevent the package to genuinely try to hit ConfigCat's CDN: ```php use PodPoint\ConfigCat\Facades\ConfigCat; // you can fake it ConfigCat::fake(); // optionally setup some predefined feature flags for your test ConfigCat::fake(['new_registration_flow' => true]); ``` #### End-to-end testing[​](#end-to-end-testing "Direct link to End-to-end testing") When running tests within a browser which doesn't share the same instance of the application, using mocks or fakes is not applicable. This is why we provide some overrides through ConfigCat SDK which will make the client under the hood localhost only and will use a locally generated `json` file in order to read the feature flags for the system under test. First of all, you will need to make sure to enable `overrides` from [`config/configcat.php`](https://github.com/Pod-Point/laravel-configcat/blob/main/config/configcat.php). You could also optionally tweak the file path for the `json` file if you wish to. The file will be automatically created for you when using overrides. Similarly to `ConfigCat::fake()` you can come up with some predefined feature flags which will be saved into a `json` file: ```php use PodPoint\ConfigCat\Facades\ConfigCat; ConfigCat::override(['new_registration_flow' => true]); ``` ## Testing[​](#testing "Direct link to Testing") Run the tests with: ```bash composer test ``` ## Changelog[​](#changelog "Direct link to Changelog") Please see our [Releases](https://github.com/pod-point/laravel-configcat/releases) for more information on what has changed recently. ## Contributing[​](#contributing "Direct link to Contributing") Please see [CONTRIBUTING](https://github.com/Pod-Point/laravel-configcat/blob/main/CONTRIBUTING.md) for details. ## Credits[​](#credits "Direct link to Credits") * [configcat/php-sdk](https://github.com/configcat/php-sdk) * [ylsideas/feature-flags](https://github.com/ylsideas/feature-flags) for inspiration * [Pod Point](https://github.com/pod-point) * [All Contributors](https://github.com/pod-point/laravel-configcat/graphs/contributors) ## License[​](#license "Direct link to License") The MIT License (MIT). Please see [License File](https://github.com/Pod-Point/laravel-configcat/blob/main/LICENSE.md) for more information. --- # Source: https://configcat.com/docs/main-concepts.md # Main Concepts Copy page ## Feature Flag or Setting[​](#feature-flag-or-setting "Direct link to Feature Flag or Setting") A *Setting* is an essential bit of *ConfigCat*. It can be of multiple types, such as an on/off switch (bool), number (int, double) or any text (string). You can use it to change your application's behavior remotely, without a new deployment. A *Feature Flag* is a *Setting* of type Bool. ### Anatomy of a *Feature Flag* or *Setting*[​](#anatomy-of-a-feature-flag-or-setting "Direct link to anatomy-of-a-feature-flag-or-setting") | Properties | Description | | ---------- | ---------------------------------------------------------------------------------------------------------------------- | | Name | A human readable name that differentiates the *Setting* on the *ConfigCat Dashboard*. e.g., `My Cool Feature enabled`. | | Key | A variable name within your code. e.g., `isCoolFeatureEnabled`. | | Type | Type of information you'd like to keep in the *Setting*. e.g., On/Off Toggle, Text, Number | | Value | The actual value of your *Setting*. e.g., `true`, `false`. Can be different in each environment. | ### About *Setting* types[​](#about-setting-types "Direct link to about-setting-types") | Setting Kind | Setting Type | Description | | -------------- | ------------ | --------------------------------------------------------------------------------- | | On/Off Toggle | Boolean | true/false, usually referenced as Feature Flag, Feature Toggle or Feature switch. | | Text | String | Any string, max. 100000 characters, can't be empty. | | Whole Number | Integer | Any whole number within the range of `Int32`. | | Decimal Number | Double | Any decimal number within the range of `double`. | ## Config[​](#config "Direct link to Config") A *Config* is a collection of *Settings*. *Configs* help you organize settings around topics, or around your software components. A *Config* is like an online version of a traditional config file. ## Environment[​](#environment "Direct link to Environment") An environment in ConfigCat represents an environment in your development lifecycle (like production, staging, development etc.). Different environments have the same settings but can have different values. info Each environment-config pair has its own SDK Key which must be used to initialize the ConfigCat SDK within your application. ## Product[​](#product "Direct link to Product") A collection of *Configs*, *Environments* and *Team members*. A *Product* typically represents your application (or your service) and the people working on it. It might be a good idea to invite others to your *Product* to collaborate. ## Organization[​](#organization "Direct link to Organization") An *Organization* represents a collection of preferences that are valid for all the *Products* and *Members* who belong to an *Organization*. Like billing information, authentication rules or data privacy preferences. --- # Source: https://configcat.com/docs/advanced/code-references/manual.md # CLI - Add to CI/CD pipelines manually Copy page This section describes how to use the [ConfigCat CLI](https://configcat.com/docs/advanced/cli.md) to scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. ## Prerequisites[​](#prerequisites "Direct link to Prerequisites") * [Install](https://configcat.com/docs/advanced/cli.md#installation) the CLI in your CI/CD or local environment. * [Setup](https://configcat.com/docs/advanced/cli.md#setup) the CLI with your ConfigCat Management API credentials. * Get your selected [Config's ID](https://configcat.com/docs/advanced/code-references/overview.md#config-id). ## Scan & Upload[​](#scan--upload "Direct link to Scan & Upload") To initiate the scanning with uploading the results, you can use the `scan` command with the `--upload` option. ### With Git VCS[​](#with-git-vcs "Direct link to With Git VCS") The scan command detects when it's being executed on a Git repository and automatically [extracts additional information](https://configcat.com/docs/advanced/code-references/overview.md#scanning-git-repositories). The following snippet shows a minimal example that uses only the required parameters in the case of a Git repository. ```bash configcat scan /path/to/your/repo \ --config-id YOUR-CONFIG-ID \ # required --repo YOUR-REPOSITORY-NAME \ # required --upload # upload the scan report ``` You can use the optional template URL parameters for generating VCS links to your source code. ```bash configcat scan /path/to/your/repo \ --config-id YOUR-CONFIG-ID \ # required --repo YOUR-REPOSITORY-NAME \ # required --file-url-template "https://github.com/my/repo/blob/{commitHash}/{filePath}#L{lineNumber}" \ # optional, used to generate VCS file links --commit-url-template "https://github.com/my/repo/commit/{commitHash}" \ # optional, used to generate VCS commit links --upload # upload the scan report ``` info The template parameters (`filePath`, `lineNumber`, and `commitHash`) are automatically replaced by the CLI based on the collected information from the Git repository. ### With Non-Git VCS[​](#with-non-git-vcs "Direct link to With Non-Git VCS") As the `scan` command cannot determine such information as `branch` and `commitHash` when you execute it on a non-Git repository, you have to set these parameters manually. ```bash configcat scan /path/to/your/repo \ --config-id YOUR-CONFIG-ID \ # required --repo YOUR-REPOSITORY-NAME \ # required --branch BRANCH-NAME \ # required in case of non-git repository --commit-hash \ # optional, used to show it on the report and generate commit links --file-url-template "https://github.com/my/repo/blob/{commitHash}/{filePath}#L{lineNumber}" \ # optional, used to generate VCS file links --commit-url-template "https://github.com/my/repo/commit/{commitHash}" \ # optional, used to generate VCS commit links --upload # upload the scan report ``` ### Docker[​](#docker "Direct link to Docker") After [installing](https://configcat.com/docs/advanced/cli.md#installation) the ConfigCat CLI with Docker, you can scan your repository by mounting its folder as a volume and setting the [ConfigCat Management API credentials](https://app.configcat.com/my-account/public-api-credentials) as environment variables on the executing container. ```bash docker run --rm \ -v /path/to/your/repo:/repository \ # mount the repository as volume -e CONFIGCAT_API_USER=YOUR-API-USER \ # Management API username -e CONFIGCAT_API_PASS=YOUR-API-PASS \ # Management API password configcat/cli scan /repository \ # scan the mounted volume --config-id YOUR-CONFIG-ID \ # required --repo YOUR-REPOSITORY-NAME \ # required --upload # upload the scan report ``` ## Reference[​](#reference "Direct link to Reference") See the `scan` command's [reference documentation](https://configcat.github.io/cli/configcat-scan.html) for all available command parameters. --- # Source: https://configcat.com/docs/advanced/mcp-server.md # MCP Server Copy page ## Overview[​](#overview "Direct link to Overview") [Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is an open protocol that standardizes how applications provide context to large language models (LLMs). The ConfigCat MCP server lets you manage feature flags and configurations via the Public Management API seamlessly from AI tools. It also enables your code editor to understand your feature flags, integrate the appropriate ConfigCat SDK into your project or even create new feature flags directly in your codebase. Your browser does not support the video tag. You can download the video here: [mcp-demo.mp4](https://configcat.com/docs/assets/mcp/mcp-demo.mp4). ## Features[​](#features "Direct link to Features") * Manage organizations, members and permissions * Create and update products, configs, and environments * Manage feature flags and settings * Manage tags and user segments * Connect with integrations and webhooks * Track activity with audit logs and zombie flag (stale flag) reports * Find code references linked to your features * Integrate ConfigCat SDK and implement feature flags in your project ## Prerequisites[​](#prerequisites "Direct link to Prerequisites") * [Node.js](https://nodejs.org) version 16 or higher installed * [Public Management API basic auth credentials](https://app.configcat.com/my-account/public-api-credentials) for ConfigCat MCP server created ## Setup[​](#setup "Direct link to Setup") Supply your [Public Management API basic auth credentials](https://app.configcat.com/my-account/public-api-credentials). The MCP server's configuration includes the following environment variables: | Variable | Required | Default | Description | | -------------------- | -------- | --------------------------- | ----------------------------------- | | `CONFIGCAT_API_USER` | ☑ | – | Management API basic auth username. | | `CONFIGCAT_API_PASS` | ☑ | – | Management API basic auth password. | | `CONFIGCAT_BASE_URL` | | `https://api.configcat.com` | Override API host (rarely needed). | ### Client Configuration[​](#client-configuration "Direct link to Client Configuration") * Cursor * Visual Studio Code * Claude Desktop 1. Install [Cursor](https://cursor.com/) 2. Open **Preferences** → **Cursor Settings** → **MCP & Integrations** 3. Click **Add Custom MCP** 4. Add (or merge) the snippet below into your JSON settings: ```json { "mcpServers": { "ConfigCat": { "command": "npx", "args": ["-y", "@configcat/mcp-server"], "env": { "CONFIGCAT_API_USER": "YOUR_API_USER", "CONFIGCAT_API_PASS": "YOUR_API_PASSWORD" } } } } ``` 5. **Save** – the server will start on demand. 6. You can start writing prompts into Cursor's AI panel. 1) Install [VS Code](https://code.visualstudio.com/) and [GitHub Copilot](https://code.visualstudio.com/docs/copilot/setup) 2) Create a `.vscode/mcp.json` file in your project root with the following content: ```json { "servers": { "ConfigCat": { "command": "npx", "args": ["-y", "@configcat/mcp-server"], "env": { "CONFIGCAT_API_USER": "YOUR_API_USER", "CONFIGCAT_API_PASS": "YOUR_API_PASSWORD" } } } } ``` 3. Save the settings file. The MCP server should now be available in VS Code. 4. You can start writing prompts into VS Code's AI panel. 1) Install [Claude Desktop](https://claude.ai/download) 2) Open **Settings** → **Developer** 3) Click **Edit Config** 4) In `claude_desktop_config.json` add: ```json { "mcpServers": { "ConfigCat": { "command": "npx", "args": ["-y", "@configcat/mcp-server"], "env": { "CONFIGCAT_API_USER": "YOUR_API_USER", "CONFIGCAT_API_PASS": "YOUR_API_PASSWORD" } } } } ``` 5. **Save** & restart Claude Desktop. info Replace `YOUR_API_USER` and `YOUR_API_PASSWORD` environment variables with your [Public Management API basic auth credentials](https://app.configcat.com/my-account/public-api-credentials). ## Interaction[​](#interaction "Direct link to Interaction") After you install the ConfigCat MCP server in your AI client, you can prompt your agent to create or manage your feature flags and configurations. Typically you need to click Run tool (or the equivalent option in your AI client) to execute the result. For example, you could try asking > Create a boolean feature flag called "my\_awesome\_feature" in the "Backend" config or > Turn the "my\_awesome\_feature" flag ON in all environments or > Update the "my\_awesome\_feature” flag in dev environment so it’s only enabled for users in Canada or > Create a new feature flag by cloning the configuration of the "my\_awesome\_feature" flag, and name it "my\_another\_awesome\_feature". or > Update the "my\_awesome\_feature" flag description: "When enabled, show my awesome feature.” or > List the stale feature flags that haven’t been modified in the past 6 days. or > Show who last modified the "myNewAwesomeFeature" flag, and to what. or > Invite sarah\@example.com to the "Main" product with "Administrators" permissions. ## See Also[​](#see-also "Direct link to See Also") * [ConfigCat MCP server GitHub repository](https://github.com/configcat/mcp-server) * [ConfigCat MCP server available tools](https://github.com/configcat/mcp-server?tab=readme-ov-file#available-tools) * [Management API Reference](https://configcat.com/docs/api/reference/configcat-public-management-api.md) * [How to Manage Feature Flags with ConfigCat's MCP Server - Blog post](https://configcat.com/blog/mcp-server-feature-flags/) --- # Source: https://configcat.com/docs/api/reference/me.md # Me Copy page Information about the current user. ## [📄️ Get authenticated user details](https://configcat.com/docs/api/reference/get-me.md) --- # Source: https://configcat.com/docs/api/reference/members.md # Members Copy page With these endpoints you can manage your Members. [Here](https://configcat.com/docs/advanced/team-management/team-management-basics.md) you can read more about Team Management. ## [📄️ List Organization Members](https://configcat.com/docs/api/reference/get-organization-members.md) [This endpoint returns the list of Members that belongs](https://configcat.com/docs/api/reference/get-organization-members.md) ## [📄️ List Organization Members](https://configcat.com/docs/api/reference/get-organization-members-v-2.md) [This endpoint returns the list of Members that belongs](https://configcat.com/docs/api/reference/get-organization-members-v-2.md) ## [📄️ List Pending Invitations in Organization](https://configcat.com/docs/api/reference/get-pending-invitations-org.md) [This endpoint returns the list of pending invitations within the](https://configcat.com/docs/api/reference/get-pending-invitations-org.md) ## [📄️ List Pending Invitations in Product](https://configcat.com/docs/api/reference/get-pending-invitations.md) [This endpoint returns the list of pending invitations within the](https://configcat.com/docs/api/reference/get-pending-invitations.md) ## [📄️ List Product Members](https://configcat.com/docs/api/reference/get-product-members.md) [This endpoint returns the list of Members that belongs](https://configcat.com/docs/api/reference/get-product-members.md) ## [📄️ Invite Member](https://configcat.com/docs/api/reference/invite-member.md) [This endpoint invites a Member into the given Product identified by the \`productId\` parameter.](https://configcat.com/docs/api/reference/invite-member.md) ## [📄️ Update Member Permissions](https://configcat.com/docs/api/reference/add-member-to-group.md) [This endpoint updates the permissions of a Member identified by the \`userId\`.](https://configcat.com/docs/api/reference/add-member-to-group.md) ## [📄️ Delete Member from Organization](https://configcat.com/docs/api/reference/delete-organization-member.md) [This endpoint removes a Member identified by the \`userId\` from the](https://configcat.com/docs/api/reference/delete-organization-member.md) ## [📄️ Delete Invitation](https://configcat.com/docs/api/reference/delete-invitation.md) [This endpoint removes an Invitation identified by the \`invitationId\` parameter.](https://configcat.com/docs/api/reference/delete-invitation.md) ## [📄️ Delete Member from Product](https://configcat.com/docs/api/reference/delete-product-member.md) [This endpoint removes a Member identified by the \`userId\` from the](https://configcat.com/docs/api/reference/delete-product-member.md) --- # Source: https://configcat.com/docs/advanced/migration-from-launchdarkly-translation.md # Details of LaunchDarkly to ConfigCat Translation Copy page This document discusses the details of how [ConfigCat's "Import from LaunchDarkly" tool](https://configcat.com/docs/advanced/migration-from-launchdarkly.md#migrate-launchdarkly-feature-flags-and-segments-to-configcat) translates LaunchDarkly projects to ConfigCat products (i.e., how, in practice, the import tool converts the project data fetched fromLaunchDarkly's REST API to ConfigCat's Export/Import JSON format). You need this information if you want to understand * why the import tool produces the result that it does, * what issues can arise during translation, and how to solve them, * what the limitations of translation are. ## Mapping between LaunchDarkly and ConfigCat entities[​](#mapping-between-launchdarkly-and-configcat-entities "Direct link to Mapping between LaunchDarkly and ConfigCat entities") The table below shows how LaunchDarkly entities are mapped to ConfigCat entities. | LaunchDarkly entity | Corresponding ConfigCat entity | Notes | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | project | [product](https://configcat.com/docs/main-concepts.md#product) | | | environment | [environment](https://configcat.com/docs/main-concepts.md#environment) | | | segment | [segment](https://configcat.com/docs/targeting/targeting-rule/segment-condition.md#what-is-a-segment-condition-what-is-a-segment) | LaunchDarkly segments are specific to an environment, but ConfigCat segments are specific to a product, so mapped segment names are prefixed with the environment name to avoid ambiguity. | | feature flag | [feature flag / setting](https://configcat.com/docs/targeting/targeting-overview.md#feature-flag--setting) | LaunchDarkly feature flags are directly contained by a project, but ConfigCat feature flags are organized into [configs](https://configcat.com/docs/main-concepts.md#config), so a config named "Main Config" is created to contain them. | | targeting toggle | - | No direct translation is possible. More on this [here](https://configcat.com/docs/advanced/migration-from-launchdarkly.md#targeting-toggle-translation-mode). | | prerequisites | - | Each prerequisite is translated to a [Targeting Rule](https://configcat.com/docs/targeting/targeting-overview.md#targeting-rule) containing a [Flag Condition](https://configcat.com/docs/targeting/targeting-rule/flag-condition.md). | | individual targets | - | Each target group is translated to a [Targeting Rule](https://configcat.com/docs/targeting/targeting-overview.md#targeting-rule) containing an IS ONE OF [User Condition](https://configcat.com/docs/targeting/targeting-rule/user-condition.md). | | custom rule | [Targeting Rule](https://configcat.com/docs/targeting/targeting-overview.md#targeting-rule) | Multiple clauses (i.e. [AND conditions](https://configcat.com/docs/targeting/targeting-rule/targeting-rule-overview.md#and-and-or-relationships) in ConfigCat's terminology) are not supported for segments, only for feature flags at the moment. | | custom rule clause | [User Condition](https://configcat.com/docs/targeting/targeting-rule/user-condition.md) or [Segment Condition](https://configcat.com/docs/targeting/targeting-rule/segment-condition.md) | Some LaunchDarkly clauses cannot be translated to ConfigCat conditions with the same evaluation behavior, or at all. See also [translation issues](#translation-issues) | | clause attribute reference | [comparison attribute](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#comparison-attribute) | LaunchDarkly context attribute paths don't always translate to ConfigCat user attribute names directly. See also [this section](#mapping-between-launchdarkly-contexts-and-configcat-user-objects). | | clause operator | [comparator](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#comparator) | Most LaunchDarkly operators have their counterparts in ConfigCat (there can be minor or major differences between them though), but a few operators are not supported by ConfigCat at all (e.g. "matches" / "does not match"). | | clause values | [comparison value](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#comparison-value) | As opposed to LaunchDarkly, not all counterparts of operators support multiple values. | | percentage rollout | [Percentage Options](https://configcat.com/docs/targeting/percentage-options.md) | In LaunchDarkly, the basis of the grouping can be set for each percentage rollout, while in ConfigCat [Percentage Evaluation Attribute](https://configcat.com/docs/targeting/percentage-options.md#percentage-evaluation-attribute) can only be set at the feature flag level. | | default rule | [trivial / fallback rule](https://configcat.com/docs/targeting/targeting-overview.md#to-all-users--to-all-other--to-unidentified-value) | | ## Mapping between LaunchDarkly contexts and ConfigCat User Objects[​](#mapping-between-launchdarkly-contexts-and-configcat-user-objects "Direct link to Mapping between LaunchDarkly contexts and ConfigCat User Objects") Both LaunchDarkly and ConfigCat support passing user and/or session-related contextual information to feature flag evaluation, which is essential for targeting: LaunchDarkly offers [contexts](https://launchdarkly.com/docs/home/observability/contexts), while ConfigCat offers [User Objects](https://configcat.com/docs/targeting/user-object.md) for this purpose. However, the data structure of these is different: * In LaunchDarkly, in addition to the default user context, it is possible to define and use other, arbitrary contexts (e.g. device, application, etc.). [Multi-contexts](https://launchdarkly.com/docs/home/flags/multi-contexts) and nested objects are also possible. * On the contrary, ConfigCat's User Object is a simpler data structure, primarily designed for storing user-related information. However, via custom attributes it's still able to store arbitrary information. On top of that, LaunchDarkly context attributes are identified by the combination of a context kind and a path expression, while ConfigCat uses simple attribute names. For this reason, it is necessary to define an unambiguous mapping between the two. This is done as shown in the following table: | LaunchDarkly context kind | LaunchDarkly context attribute path | Corresponding ConfigCat user attribute name | | ------------------------- | ----------------------------------- | ------------------------------------------- | | not specified or `user` | empty string or `/` | `/` | | not specified or `user` | `key` or `/key` | `Identifier` | | not specified or `user` | `email` or `/email` | `Email` | | not specified or `user` | `country` or `/country` | `Country` | | not specified or `user` | `Identifier` or `/Identifier` | `/Identifier` | | not specified or `user` | `Email` or `/Email` | `/Email` | | not specified or `user` | `Country` or `/Country` | `/Country` | | not specified or `user` | `name` or `/name` | `name` | | not specified or `user` | `/address/city` | `/address/city` | | `device` | empty string or `/` | `device:/` | | `device` | `name` or `/name` | `device:name` | | `organization` | `name` or `/name` | `organization:name` | | `organization` | `/address/city` | `organization:/address/city` | | any | `kind` or `/kind` | `/kind` | Please note that: * Both LaunchDarkly context attribute paths and ConfigCat user attribute names are case-sensitive. * In ConfigCat, `Identifier`, `Email` and `Country` are predefined attributes. Everything else qualifies as custom attributes. * One-component LaunchDarkly attribute path expressions are always normalized to their unescaped form if possible. E.g. `/~0~1x` → `~/x`, but `/~1~00` → `/~1~00` (as `/~0` would be an ambiguous mapping). * Multi-component LaunchDarkly attribute path expressions are kept as is (unless they contain `:` characters - see below). * Context kinds other than `user` are included as a prefix in the mapped ConfigCat user attribute name, with `:` as the separator. Because of this, LaunchDarkly context attribute paths containing `:` characters needs to be escaped to avoid ambiguity. E.g. `a:b` -> `/a~;b`, `/a:b` -> `/a~;b`. ## Translation issues[​](#translation-issues "Direct link to Translation issues") There are technical differences between LaunchDarkly and ConfigCat, therefore it's not always possible to translate all entities accurately, i.e. so that they are represented identically in ConfigCat, and provide equivalent behavior to the original. (By equivalent behaviour we primarily mean equivalent evaluation behaviour, i.e. that the evaluation of a feature flag or segment produces the same result for the same input parameters.) Such problematic cases are called *translation issues*, and a *severity level* is assigned to them as follows. 🔴 HIGH - The imported entity cannot provide equivalent behavior to the original at all.
🟡 MEDIUM - The imported entity may not provide equivalent behavior to the original in every case.
🔵 LOW - The imported entity does not exactly reflect the original in some way, but it is expected to provide equivalent behavior to the original. The tables below show the possible translation issues. ### Limitations[​](#limitations "Direct link to Limitations") info Usually these issues arise when you are on a lower plan, and hitting a subscription limit. If that's the case, feel free to [contact us](https://configcat.com/support/?prefilled=ld-import-limit), we are happy to raise your limits temporarily so you can fully explore the product and evaluate it at your pace. | Code | Level | Issue | What can be the cause? | How is it handled? | | ---- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | L001 | 🔴 HIGH | The number of Targeting Rules resulting from the translation would exceed the [subscription / technical limit](https://configcat.com/docs/subscription-plan-limits.md). | There are too many rules in the original feature flag. | As many LaunchDarkly rules as the limit allows are imported, but the rest is omitted. | | L002 | 🔴 HIGH | The number of conditions resulting from the translation would exceed the [subscription / technical limit](https://configcat.com/docs/subscription-plan-limits.md). | There are too many clauses in a rule of the original feature flag. | As many LaunchDarkly clauses as the limit allows are imported, but the rest is omitted. | | L003 | 🔴 HIGH | The number of percentage options resulting from the translation would exceed the [subscription / technical limit](https://configcat.com/docs/subscription-plan-limits.md). | There are too many percentage rollout variations in the original feature flag. | As many LaunchDarkly percentage rollout variations as the limit allows are imported, but the rest is omitted. The percentage of the last imported item is adjusted so that the sum of percentages equals 100%. | | L004 | 🔴 HIGH | The length of a comparison value resulting from the translation would exceed the [subscription / technical limit](https://configcat.com/docs/subscription-plan-limits.md). | The value(s) of a LaunchDarkly clause translate to a string comparison value that would be too long. | The comparison value is truncated so that it fits within the limit. | | L005 | 🔴 HIGH | The number of items in a comparison value list resulting from the translation would exceed the [subscription / technical limit](https://configcat.com/docs/subscription-plan-limits.md). | The values of a clause translate to a comparison value list that would have too many items. | The comparison value list is truncated so that it fits within the limit. | | L006 | 🔴 HIGH | The length of an item in a comparison value list resulting from the translation would exceed the [subscription / technical limit](https://configcat.com/docs/subscription-plan-limits.md). | One or more values of a clause translate to a comparison value item that would be too long. | The comparison value item is truncated so that it fits within the limit. | | L007 | 🔴 HIGH | The length of a text setting value resulting from the translation would exceed the [subscription / technical limit](https://configcat.com/docs/subscription-plan-limits.md). | A feature flag variation value translates to a text setting value that would be too long. | The text setting value is truncated so that it fits within the limit. | ### Technical differences[​](#technical-differences "Direct link to Technical differences") | Code | Level | Issue | What can be the cause? | How is it handled? | | ---- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | T001 | 🔵 LOW | A project, environment, segment or feature flag was imported under a different name than the original. | 1. LaunchDarkly project, environment and segment names do not have to be unique (since those items always have a unique key in LaunchDarkly too). The corresponding ConfigCat entities, however, must have a case-insensitive unique name.
2. LaunchDarkly allows longer names than ConfigCat. | 1. In the case of identical names, the LaunchDarkly unique key is included in the name. If this is still not unique, then a number suffix is added as well.
2. Names that are too long are truncated at the maximum length. If this results in a conflicting name, it is made unique by adding a number suffix. | | T002 | 🟡 MEDIUM | A feature flag was imported with a different key than the original. | 1. Feature flag keys are unique in both systems, but they must be case sensitive in LaunchDarkly and case insensitive in ConfigCat.
2. As opposed to LaunchDarkly, ConfigCat feature flag keys are not allowed to start with a number or contain dots.
3. Depending on the Targeting Toggle Translation Mode option, the targeting toggle may be emulated using an extra prerequisite flag. The key for this is generated by adding the suffix `_tt` to the key of the main flag. | 1. Conflicts are resolved by adding a number suffix.
2. Characters that are invalid in ConfigCat are replaced with `_`. If the first character is not a letter, the prefix `x_` is also added to the key. If this results in a conflicting key, it is made unique by adding a number suffix.
3. Conflicts are resolved by adding a number suffix. (But always the uniqueness of the the actually imported flags' keys are ensured first.) | | T003 | 🔵 LOW | A feature flag tag name was truncated. | LaunchDarkly may allow longer tag names than ConfigCat. | Names that are too long are truncated at the maximum length. If this results in a conflicting name, no effort is made to make it unique. | | T004 | 🔵 LOW | A JSON feature flag was encountered. | LaunchDarkly allows feature flags with JSON values, but ConfigCat doesn't support that directly at the moment. | A text setting is created in ConfigCat, with values containing the JSON variation values serialized to text. It is your responsibility to deserialize the text once returned by feature flag evaluation. | | T005 | 🟡 MEDIUM | A comparison attribute name was truncated. | A context attribute name is mapped to a user attribute name that is too long. | The comparison attribute name is truncated so that it fits within the limit. If this results in a conflicting name, no effort is made to make it unique. | | T006 | 🔴 HIGH | Unset off variation was encountered. | In LaunchDarkly, it is not required to set a variation for the case when targeting is turned off. In that case, feature flag evaluation will return the default value you pass to the LaunchDarkly SDK. There is no way to reproduce this behavior in ConfigCat. | There is no way to emulate this behavior in ConfigCat, so a placeholder value is used as follows:- boolean flag: `false`
- string flag: `""` (empty string)
- json flag: `"null"`
- number flag: 0 | | T007 | 🔵 LOW | Targeting is turned off, and the targeting toggle was respected. | Targeting Toggle Translation Mode option was set to "Respect targeting toggle and don't import rules", and1. targeting is turned off for the feature flag in the specific environment,
2. or targeting is turned off for one or more prerequisites in the specific environment (see also the "Prerequisite flags must be on" section in [this article](https://launchdarkly.com/docs/home/flags/prereqs)). | A single Targeting Rule that returns the off variation is created in ConfigCat, and the actual rules are not imported for the specific environment. (The imported feature flag will work as it does in LaunchDarkly at the time of import.) | | T008 | 🟡 MEDIUM | Targeting is turned off, and the targeting toggle was ignored. | Targeting Toggle Translation Mode option was set to "Ignore targeting toggle and import rules anyway", and1. targeting is turned off for the feature flag in the specific environment,
2. or targeting is turned off for one or more prerequisites in the specific environment (see also the "Prerequisite flags must be on" section in [this article](https://launchdarkly.com/docs/home/flags/prereqs)). | The off variation is ignored, and the actual rules are imported for the specific environment. (The imported feature flag will not work as it does in LaunchDarkly at the time of import.) | | T009 | 🔴 HIGH | A segment clause references multiple segments, but cannot be translated due to subscription / technical limit. | ConfigCat doesn't support referencing multiple segments in Segment Conditions. There is a workaround though: non-negated LaunchDarkly clauses can be expanded into multiple ConfigCat Targeting Rules, negated LaunchDarkly clauses can be expanded into multiple ConfigCat conditions. However, in the specific case the expansion is not possible because of subscription / technical limits. | A Segment Condition is created in ConfigCat but it references the first segment only. The rest of the segment references are omitted. | | T010 | 🔴 HIGH | A segment that references another segment was encountered. | ConfigCat segments do not support targeting segments. | A placeholder condition is created in ConfigCat. | | T011 | 🔴 HIGH | An untranslatable clause was encountered in a feature flag or segment rule. | The LaunchDarkly clause is not translatable to a ConfigCat condition, not even via a workaround. Such cases are:1. Feature flag or segment rule clause uses the "matches" / "does not match" operators.
2. Feature flag rule clause is based on Context kind but cannot be translated to an ARRAY IS (NOT) ONE OF condition.
3. Segment rule clause is based on Context kind.
4. Segment rule clause uses the "starts with" / "does not start with" / "ends with" / "does not end with" operators.
5. Segment rule clause uses the "before" or "after" operator.
6. Feature flag or segment rule targets application versions (no such feature in ConfigCat). | A placeholder condition is created in ConfigCat. | | T012 | 🔵 LOW | A clause was translated to multiple Targeting Rules or conditions. | Some LaunchDarkly clauses like segment clauses referencing multiple segments cannot be directly translated to a single ConfigCat condition. However, in the specific case, a workaround that provides logically equivalent evaluation behavior is possible. | If the LaunchDarkly clause is non-negated, it is expanded into multiple ConfigCat Targeting Rules, otherwise it is expanded into multiple ConfigCat conditions. | | T013 | 🔴 HIGH | A "contains" / "does not contain" segment clause with multiple values was encountered. | In segments, the ConfigCat counterparts of the "contains" / "does not contain" operators only accept a single comparison value at the moment. | The clause is translated to a CONTAINS / DOES NOT CONTAIN segment, however only the first clause value is preserved. The rest of the values are omitted. | | T014 | 🔵 LOW | A "<", "<=", ">", ">=", "SemVer <", "SemVer <=", "SemVer >", "SemVer >=" or "before" / "after" clause with multiple values was encountered. | The ConfigCat counterpart of these operators allows a single comparison value only. | Multiple comparison values are reduced to a single one. (This can be done in such a way that the clause remains logically accurate.) The rest of the values are omitted though.
It is also worth noting that the evaluation behavior of "SemVer <=" and "SemVer >=" clauses with multiple values is inconsistent with similar operators in LaunchDarkly. So, since translation preserves the inconsistent behavior, it may produce surprising results in such cases. | | T015 | 🟡 MEDIUM | A "Context kind is (not) one of" clause was encountered. | In ConfigCat, there is no such concept as contexts and context kinds. ConfigCat SDKs won't automatically provide context kinds as an attribute via the User Object. | An ARRAY IS (NOT) ONE OF condition is created in ConfigCat, but it is your responsibility to pass the context kind values to the ConfigCat SDK via the custom user attribute named `/kind`. | | T016 | 🟡 MEDIUM | A mobile targeting-related clause was encountered. | For mobile apps, LaunchDarkly allows targeting special, [automatically provided context attributes](https://launchdarkly.com/docs/sdk/features/environment-attributes) of context kinds `ld_application` and `ld_device`. ConfigCat SDKs won't automatically provide these attributes via the User Object. | The clause is translated, but it is your responsibility to pass the attribute values to the ConfigCat SDK via custom user attributes. | | T017 | 🟡 MEDIUM | A not accurately translatable "is (not) one of" clause was encountered. | In LaunchDarkly, "is (not) one of" clauses can work with string, boolean and number values, but their ConfigCat counterparts can work with strings only. This can be a problem in two cases:1. "is (not) one of" clauses with boolean comparison values cannot be translated accurately as ConfigCat offers no comparators that work with boolean values at the moment,
2. "is (not) one of" clauses with number comparison values may be translated accurately using the = (number) / != (number) comparators. These accept a single comparison value though, so clauses with multiple values must be expanded into multiple targeting rules or conditions, depending on negation. However, in the specific case the expansion is not possible because of subscription / technical limits. | An IS (NOT) ONE OF condition is created in ConfigCat and the non-string values are converted to string.
From the perspective of feature flag evaluation this means the following: the ConfigCat SDK will convert non-string user attributes to string, and do case-sensitive string comparisons when evaluating the feature flag. In the case of boolean and decimal number values this can lead to undesired behavior. E.g. on some platforms, the ConfigCat SDK may convert the false boolean value to the string `False`, which won't be matched by an IS ONE OF condition having a comparison value `false`. Similarly, there could be subtle differences in decimal number to string conversion across various platforms. | | T018 | 🔵 LOW | One or more variations of a percentage rollout had to be omitted. | LaunchDarkly includes all the feature flag variations in a percentage rollout even if most of them are set 0%. However, this could lead to exceeding the subscription limit on Percentage Options in ConfigCat (especially, on lower plans). | As variations set to 0% don't affect the evaluation of the imported Percentage Options, translation omits as many of them as needed to fit within the limit. | | T019 | 🟡 MEDIUM | One or more percentage values of a percentage rollout had to be adjusted. | As opposed to LaunchDarkly, ConfigCat doesn't allow fractional percentage values in Percentage Options. | Non-integer percentage values are rounded. This may also cause the sum of the percentage values to over or undershoot 100%. In such cases, further adjustments are performed to make the sum exactly 100%. | | T020 | 🔴 HIGH | There are multiple percentage rollout rules in the feature flag, but they do not use the same attribute as the basis of the rollout. | In LaunchDarkly, it is possible to set different attributes as the basis of the rollout for each percentage rollout rule. In ConfigCat, this can only be set at the feature flag level. | There is no workaround. The attribute that occurs the most times is set as the flag's Percentage Evaluation Attribute. | | T021 | 🔴 HIGH | A segment with no rules was encountered. | LaunchDarkly allows segments to have no rules, while ConfigCat segments specify exactly one rule. | A segment with a placeholder condition is created in ConfigCat. | | T022 | 🔴 HIGH | A segment with multiple rules was encountered. | LaunchDarkly allows segments to have multiple rules, while ConfigCat segments specify exactly one rule. | A segment is created in ConfigCat, with a translation of the first rule only. The rest of the rules are omitted. | | T023 | 🔴 HIGH | A segment rule with multiple clauses was encountered. | LaunchDarkly allows multiple clauses in segment rules, while ConfigCat doesn't support AND conditions in segments at the moment. | There is no workaround. Clauses except for the first one are omitted. | | T024 | 🔴 HIGH | A segment rule with percentage targeting was encountered. | LaunchDarkly allows segment rules to include a percentage of targets only. ConfigCat segments doesn't offer such feature. | There is no workaround. The percentage targeting part is ignored. | | T025 | 🔴 HIGH | A segment rule was only partially translated. | Translating the segment rule would require multiple rules in ConfigCat, which is not supported. | The segment rule is only partially imported. | | T026 | 🔴 HIGH | A big segment was encountered. | Big segments are not supported by ConfigCat. | A normal segment with a hint about the issue is created in ConfigCat. | | T027 | 🔴 HIGH | Comparison value list item contains comma. | In the case of segments, multiple clause values translate to a comma separated comparison value list. There is no way to escape the comma, so it must be replaced with another character, otherwise values containing a comma would be interpreted as multiple items. | Comma is replaced with semicolon in comparison value list items. | ### Data consistency[​](#data-consistency "Direct link to Data consistency") | Code | Level | Issue | What can be the cause? | How is it handled? | | ---- | --------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | D001 | 🔴 HIGH | The data model fetched from LaunchDarkly contains invalid, inconsistent or unexpected data. | In theory, such a thing cannot happen, but in practice it cannot be excluded. | Obviously, the import tool cannot produce a correct result from an inherently incorrect input. As a best effort, it generates a valid import model so that the import operation can go through, and you can review and fix the problematic entities. | | D002 | 🟡 MEDIUM | The feature flag was modified in LaunchDarkly while the feature flag data was being fetched. | Due to the peculiarities of the LaunchDarkly REST API, the full data model of a feature flag can only be queried for a single environment per a single request. So, it may happen that some non-environment-related properties of the feature flag are modified while fetching the feature flag data (e.g. name, variations, etc.) In such cases, inconsistencies across environments are possible in the retrieved data. | The import tool can only detect inconsistencies, but cannot do anything about them. Please check whether the imported feature flag is set correctly in each environment. Alternatively, you may try to re-import the specific feature flag. | ## Further technical differences[​](#further-technical-differences "Direct link to Further technical differences") * As opposed to LaunchDarkly, ConfigCat distinguishes between integer and decimal number feature flags. Therefore, when translating number feature flags, the ConfigCat setting type is guessed based on the variation values specified at the time of the import. * For percentage rollouts, LaunchDarkly and ConfigCat use different algorithms to split users into groups. That is, even if the percentage values are the same, the distribution of users will be different. In other words, [stickiness](https://configcat.com/docs/targeting/percentage-options.md#stickiness) of percentage rollouts cannot be transferred to ConfigCat. * In the case of percentage rollouts within custom rules, evaluation behavior is different between the two services when the attribute used as the basis of the percentage rollout is not provided (i.e. not passed to the SDK on evaluation): * LaunchDarkly will serve the value of the first variation whose percentage value is not 0%. * ConfigCat will skip the targeting rule and continue evaluation with the next rule. * In LaunchDarkly, all clause operators can work with context attribute value lists. In ConfigCat, most of the comparators (counterparts of operators) can work with a single user attribute only. The only exceptions is ARRAY IS (NOT) ONE OF. * In LaunchDarkly, it is possible to control whether or not specific feature flags are visible to mobile and/or client-side SDKs ([Client-side SDK availability](https://launchdarkly.com/docs/home/flags/new#make-flags-available-to-client-side-and-mobile-sdks)). There is no such feature in ConfigCat, so this preference is ignored. All the feature flags are imported into a single config which can be accessed by all kinds of ConfigCat SDKs. * In LaunchDarkly, it is possible to mark a feature flag as temporary or permanent. There is no such feature in ConfigCat. Yet translation preserves this piece of information by adding a tag to the feature flag. * In LaunchDarkly, it is possible to assign a name to the variations (possible outcomes of the feature flag). There is no such feature in ConfigCat at the moment, so these pieces of information are not transferred. --- # Source: https://configcat.com/docs/advanced/migration-from-launchdarkly.md # Migration from LaunchDarkly Copy page This document is for current LaunchDarkly users who want to migrate to ConfigCat. It guides you through the migration process while providing information on the technical differences between the two services that you need to be aware of. Migration can be done on a LaunchDarkly project basis, and migration of a project usually consists of the following three steps: 1. Migrating LaunchDarkly feature flags and segments to ConfigCat 2. Adjusting the code of your applications to use ConfigCat instead of LaunchDarkly 3. Migrating LaunchDarkly teams and permissions to ConfigCat ConfigCat provides a wizard-like tool that is able to do the heavy lifting for step 1. However, there is currently no automation for step 2 and 3. So please expect these steps to require some manual work. However, before diving into it all, please check [this list](https://configcat.com/docs/sdk-reference/overview.md) to see if ConfigCat supports the platform your applications are running on. If not, feel free to [contact us](https://configcat.com/support). Maybe we can still figure out a way for you to migrate to ConfigCat. ## Getting started[​](#getting-started "Direct link to Getting started") To be able to perform the migration, it's essential that you have a basic understanding of ConfigCat's main concepts and hierarchy. So, as the very first step, please read through [this brief guide](https://configcat.com/docs/main-concepts.md). LaunchDarkly projects correspond to ConfigCat products in the ConfigCat hierarchy. However, as you already know, products are not standalone entities, they are contained by a ConfigCat organization. So, to get started with migration, you will need to have a ConfigCat account and be a member of the ConfigCat organization that you want to host the products corresponding to the projects you plan to migrate from LaunchDarkly. You will also need to have the Organization Admin permission in that ConfigCat organization to be able to create products. * If the target ConfigCat organization does not exist yet, you can create one by [signing up](https://app.configcat.com/auth/signup). During the signup process, you will have the opportunity to create your own organization, in which you will have the Organization Admin permission by default. * Otherwise, you will need to get an invitation to the target ConfigCat organization, and after joining, you will need to request the Organization Admin permission. Once the target ConfigCat organization is set up and you have the necessary permissions in it, you can start the actual migration. ## Migrate LaunchDarkly feature flags and segments to ConfigCat[​](#migrate-launchdarkly-feature-flags-and-segments-to-configcat "Direct link to Migrate LaunchDarkly feature flags and segments to ConfigCat") It is recommended to migrate your LaunchDarkly feature flags and segments to ConfigCat first, using ConfigCat's official import tool, which was designed for this specific purpose. The tool also takes care of creating the corresponding ConfigCat products and environments, and it does everything possible to reproduce your LaunchDarkly feature flags and segments in ConfigCat so they match the original evaluation behavior as closely as possible. ### Using the import tool[​](#using-the-import-tool "Direct link to Using the import tool") To launch the import tool, open the dropdown menu in the top left corner of the [ConfigCat Dashboard](https://app.configcat.com/organization), navigate to the Organization Overview page, then click the card labeled "Import from LaunchDarkly". ![Launching the import tool](/docs/assets/migration-from-launchdarkly/launch-import-tool_192dpi.png) This will take you to a page with a wizard-like UI: ![The import tool](/docs/assets/migration-from-launchdarkly/import-tool_192dpi.png) Follow the instructions and go through the steps to perform the import. Feel free to experiment with the import tool. You can't really cause any irreversible damage by doing so. After finishing an import, you can delete the imported products in ConfigCat and start over if you are not satisfied with the result. It is also possible to re-import products or specific parts of those without having to delete the products created previously. The import tool is able to update the existing entities with fresh data. However, this may involve undoable overwriting of existing data, so please be careful. The import tool will warn you if something like this is about to happen. ### Targeting toggle translation mode[​](#targeting-toggle-translation-mode "Direct link to Targeting toggle translation mode") In step 3 of the wizard, you may need to make a decision that might not be self-evident. LaunchDarkly feature flags have a [toggle](https://docs.launchdarkly.com/home/flags/toggle) that allows you to enable or disable targeting for the specific feature flag. However, there is no similar feature in ConfigCat. So, in case the LaunchDarkly projects you selected for import contain feature flags where the targeting toggle is turned off in some of the environments, you need to decide how to work around such cases. Your options are the following: #### Ignore targeting toggle and import rules anyway[​](#ignore-targeting-toggle-and-import-rules-anyway "Direct link to Ignore targeting toggle and import rules anyway") This will result in an evaluation behavior different from LaunchDarkly. Choose this option if you want to keep your targeting rules even if the targeting toggle is off. Please consider the following consequences: * The state of targeting toggles will be ignored. * The *off variation* values won't be served. * The targeting rules will be imported and evaluated as if the targeting toggle was on. #### Respect targeting toggle and don't import rules[​](#respect-targeting-toggle-and-dont-import-rules "Direct link to Respect targeting toggle and don't import rules") This will result in the same evaluation behavior as in LaunchDarkly. Choose this option if you want your feature flags to produce the same values as in LaunchDarkly. Please consider the following consequences: * The state of targeting toggles will be respected. * The *off variation* values will be served. * The targeting rules won't be imported in environments where the targeting toggle is off. #### Emulate targeting toggle using a prerequisite flag[​](#emulate-targeting-toggle-using-a-prerequisite-flag "Direct link to Emulate targeting toggle using a prerequisite flag") This is a workaround that combines the upsides of the other two options at the expense of creating extra feature flags. Choose this option if you want to import your targeting rules in all cases, and also want your feature flags to produce the same values as they do in LaunchDarkly. Please consider the following consequences: * The state of targeting toggles will be respected, however, for each problematic LaunchDarkly feature flag an extra [prerequisite flag](https://configcat.com/docs/targeting/targeting-rule/flag-condition.md) will be created in ConfigCat to emulate the targeting toggle. * The *off variation* values will be served. * The targeting rules will be imported and evaluated depending on the state of the extra prerequisite flag. ### About the import operation[​](#about-the-import-operation "Direct link to About the import operation") After making your choices on what and how to import in the first steps of the wizard, the import tool performs the operation by importing the selected LaunchDarkly projects one by one. Importing a project consists of two phases: #### Translation phase[​](#translation-phase "Direct link to Translation phase") First, the import tool translates the LaunchDarkly project to a ConfigCat product. For more details on how this is done, please refer to [this document](https://configcat.com/docs/advanced/migration-from-launchdarkly-translation.md). It's important to note that the import tool performs translation on a best effort basis. It aims to do translation in such a way that you get a feature flag evaluation behavior as close to the original as possible. However, since there are technical differences between LaunchDarkly and ConfigCat, an accurate translation is not possible in every case. Such problematic cases are called *translation issues*. The import tool detects and collects these issues during translation, and includes them in the report generated at the end of the import operation so you can review them, and make the necessary adjustments where necessary. You can find the list of possible translation issues [here](https://configcat.com/docs/advanced/migration-from-launchdarkly-translation.md#translation-issues). #### Import phase[​](#import-phase "Direct link to Import phase") After the translation phase, the import tool loads the result into ConfigCat. This is when the corresponding ConfigCat product is actually created (or updated if it already exists). As the import tool has previously performed all the necessary validation and adjustments, generally you shouldn't encounter any issues during this phase. However, in rare cases failures may occur (most likely, due to a concurrent modification in ConfigCat). The import tool notifies you of such cases, and it also includes the failure details in the report. ### Final steps[​](#final-steps "Direct link to Final steps") After finishing the import operation, the import tool displays a summary. This shows you the overall success of each LaunchDarkly project selected for import. * If you see success icons next to every project, it means everything went fine, no significant issues were detected. * If you see a warning or error icon next to any project, it means that there are significant issues you need to pay closer attention to, and you will almost certainly need to make manual adjustments, or, in case of failure, even repeat the import. In either case, it's highly recommended to download and go through the report. It provides details about the detected issues, and also includes links to the original and imported entities, which can make it easier for you to look into and resolve the issues. ## Adjust the code of your applications[​](#adjust-the-code-of-your-applications "Direct link to Adjust the code of your applications") The next step in the migration process is to adjust the code of your applications to use ConfigCat instead of LaunchDarkly to evaluate your feature flags. This will also require more or less manual work, depending on what API your applications currently use for feature flag evaluation. ### Adjust a codebase that uses LaunchDarkly SDK[​](#adjust-a-codebase-that-uses-launchdarkly-sdk "Direct link to Adjust a codebase that uses LaunchDarkly SDK") If your applications implement feature flagging by directly consuming the LaunchDarkly SDK API, you will need to change those parts to use the ConfigCat SDK API. We show how to do this through a simple example. Let's assume you have the following simple Node.js application: ```js import LaunchDarkly from "@launchdarkly/node-server-sdk"; const sdkKey = process.env.LAUNCHDARKLY_SDK_KEY ?? "#YOUR-SDK-KEY#"; const client = LaunchDarkly.init(sdkKey); try { await client.waitForInitialization({ timeout: 10 }); } catch (error) { console.error(`SDK failed to initialize: ${error}`); process.exit(1); } const context = { "kind": "multi", "user": { "key": "#UNIQUE-USER-IDENTIFIER#", "name": "Alice", "email": "alice@example.com", "country": "UK" }, "organization": { "key": "#UNIQUE-ORG-IDENTIFIER#", "address": { "city": "London" } } }; const flagValue = await client.variation("isAwesomeFeatureEnabled", context, false); if (flagValue) { console.log("Feature is enabled.") } else { console.log("Feature is disabled.") } process.exit(0); ``` Let's see now step by step how to convert this code to ConfigCat: 1. Uninstall the LaunchDarkly SDK package, and install the ConfigCat one instead: ```bash npm uninstall @launchdarkly/node-server-sdk npm install configcat-node ``` 2. Instead of the `LaunchDarkly` namespace, import `configcat`: ```js import configcat from "configcat-node"; ``` 3. Replace the LaunchDarkly SDK key with the ConfigCat one. You can obtain it from the [ConfigCat Dashboard](https://app.configcat.com/organization), by selecting the config containing the imported feature flag on the sidebar, and clicking the "VIEW SDK KEY" button in the top right corner of the page. 4. Instead of a LaunchDarkly client instance, obtain a ConfigCat one: ```js const client = configcat.getClient(sdkKey, configcat.PollingMode.AutoPoll, { maxInitWaitTimeSeconds: 10 }); ``` Please note that the ConfigCat client doesn't maintain a persistent connection to the remote server, but uses different polling strategies to get the data necessary for feature flag evaluation. Refer to the [SDK reference](https://configcat.com/docs/sdk-reference/js/overview.md#creating-the-configcat-client) to learn more about the options. For frontend applications and long-running backend services, Auto Polling mode is usually a good choice. 5. Adjust the wait-for-initialization logic. * When using Auto Polling mode, you can rewrite it like this: ```js const clientCacheState = await client.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { /* ... */ process.exit(1); } ``` Please note that the `waitForReady` method is not available on all platforms. On such platforms, you can't really implement this logic at the moment. However, you don't really need to as the feature flag evaluation methods wait for initialization internally anyway. (It's worth noting that if initialization can't complete within the timeout duration specified by the `maxInitWaitTimeSeconds` option, then feature flag evaluation methods will return the default value you pass to them.) Actually, you only need this wait-for-initialization logic at the startup of your applications if you want to use [synchronous feature flag evaluation via snapshots](https://configcat.com/docs/sdk-reference/js/overview.md#snapshots-and-synchronous-feature-flag-evaluation). * For other polling modes, the wait-for-initialization logic doesn't make sense, so just omit it. 6. Rewrite LaunchDarkly contexts to ConfigCat User Objects. ConfigCat uses the concept of [User Object](https://configcat.com/docs/targeting/user-object.md) to pass user and/or session-related contextual data to feature flag evaluation. It serves the same purpose as [LaunchDarkly contexts](https://launchdarkly.com/docs/home/observability/contexts), but it's a simpler data structure. To be able to convert a context data structure to a User Object one, you will need to do the following: * Read [the section on User Objects](https://configcat.com/docs/sdk-reference/js/overview.md#user-object) in the reference of the SDK for your platform. * Read [this section](https://configcat.com/docs/advanced/migration-from-launchdarkly-translation.md#mapping-between-launchdarkly-contexts-and-configcat-user-objects) to learn how context paths are mapped to User Object attribute names. For an example of such conversion, see the adjusted code at the end of this section. Please also keep in mind: * Some LaunchDarkly SDKs may [automatically provide additional attributes](https://launchdarkly.com/docs/sdk/features/environment-attributes) in contexts. ConfigCat SDKs don't offer a feature like that at the moment, so in case you target such additional attributes in your feature flags, you will need to provide them manually in your applications. * LaunchDarkly allows multiple attribute values (an array of values) for all clause operators, but ConfigCat allows multiple attribute values (an array of strings) for the ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF comparators only. This means that it's not possible to specify multiple values for a user attribute if the evaluated feature flag contains a [User Condition](https://configcat.com/docs/targeting/targeting-rule/user-condition.md) that references the attribute, but has a comparator other than the two mentioned. Unfortunately, no workaround exists for this case. 7. Rewrite feature flag evaluation calls. This step is pretty straightforward as ConfigCat SDKs provide similar evaluation methods to LaunchDarkly SDKs. Those methods are named `getValue`, `getValueAsync` or similar. A few things to pay attention to: * The order of parameters is different. In ConfigCat, the User Object comes last. * The ConfigCat feature flag key may be different from the LaunchDarkly one. E.g. if the key starts with a non-letter character, or contains a dot, it will be changed by the import tool because such keys are not valid in ConfigCat. To see which keys have been changed, look for [T002](https://configcat.com/docs/advanced/migration-from-launchdarkly-translation.md#translation-issue-T002) translation issues in the report. * ConfigCat SDKs don't support [automatic camel casing](https://launchdarkly.com/docs/sdk/client-side/react/react-web#flag-keys-in-the-react-web-sdk) of feature flag keys. * In statically typed languages, ConfigCat evaluation methods require that the default value type and the feature flag type match. (Usually, there is [a section about this](https://configcat.com/docs/sdk-reference/js/overview.md#setting-type-mapping) in the SDK reference.) * Please be extra careful when evaluating number type feature flags. ConfigCat distinguishes between integer and decimal number feature flags. The former must be evaluated using `getValue`, `getIntValue` or similar, while the latter must be evaluated using `getValue`, `getDoubleValue` or similar. (JavaScript-based SDKs don't have this issue, but you can run into it in other languages.) * On some platforms, the ConfigCat client provides asynchronous evaluation methods only. In such cases, synchronous feature flag evaluation is usually still possible, [via snapshots](https://configcat.com/docs/sdk-reference/js/overview.md#snapshots-and-synchronous-feature-flag-evaluation). But this works slightly differently from the asynchronous methods, so make sure you understand its behavior and possible pitfalls. By adjusting the example code according to the above, we get this: ```js import configcat from "configcat-node"; const sdkKey = process.env.CONFIGCAT_SDK_KEY ?? "#YOUR-SDK-KEY#"; const client = configcat.getClient(sdkKey, configcat.PollingMode.AutoPoll, { maxInitWaitTimeSeconds: 10 }); const clientCacheState = await client.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { console.error("SDK failed to initialize."); process.exit(1); } const user = { identifier: "#UNIQUE-USER-IDENTIFIER#", email: "alice@example.com", country: "UK", custom: { "name": "Alice", "organization:key": "#UNIQUE-ORG-IDENTIFIER#", "organization:/address/city": "London", "/kind": ["user", "organization"], } }; const flagValue = await client.getValueAsync("isAwesomeFeatureEnabled", false, user); if (flagValue) { console.log("Feature is enabled.") } else { console.log("Feature is disabled.") } process.exit(0); ``` The conversion can be done in a similar way on other platforms as well. Obviously, there may be minor differences, plus advanced topics are not covered here, so it's recommended to start this work by going through the SDK reference for your platform. ### Adjust a codebase that uses OpenFeature[​](#adjust-a-codebase-that-uses-openfeature "Direct link to Adjust a codebase that uses OpenFeature") You should have an easier time if feature flagging is done using the [OpenFeature](https://openfeature.dev/docs/reference/intro/) abstraction in your applications. In this case, please check [this list](https://configcat.com/docs/sdk-reference/openfeature/overview/) to see if a ConfigCat OpenFeature provider is available for your platform. If you're out of luck, you can still use the ConfigCat SDK directly as explained in the previous section, or [contact us](https://configcat.com/support) about the missing OpenFeature provider. Otherwise, to switch to ConfigCat, you need to do the following: 1. Uninstall the LaunchDarkly OpenFeature provider package, and install the ConfigCat one instead. 2. Adjust the initialization logic. Look for a call to `setProvider`, `setProviderAndWait` or similar, and change it so an instance of ConfigCat OpenFeature provider is passed to it. (For ConfigCat, use `setProviderAndWait` if possible.) 3. Convert [LaunchDarkly-specific evaluation context objects](https://github.com/launchdarkly/openfeature-node-server?tab=readme-ov-file#openfeature-specific-considerations) to have a data structure compatible with ConfigCat. This is done in a very similar way to what's described in the previous section. Read [this section](https://configcat.com/docs/advanced/migration-from-launchdarkly-translation.md#mapping-between-launchdarkly-contexts-and-configcat-user-objects) to learn how context paths are mapped to User Object attribute names. For example, something like ```js const evaluationContext = { kind: "multi", user: { targetingKey: "#UNIQUE-USER-IDENTIFIER#", name: "Alice", email: "alice@example.com", country: "UK" }, organization: { targetingKey: "#UNIQUE-ORG-IDENTIFIER#", address: { city: "London" } } }; ``` should be converted to this: ```js const evaluationContext = { targetingKey: "#UNIQUE-USER-IDENTIFIER#", name: "Alice" email: "alice@example.com", country: "UK", "organization:key": "#UNIQUE-ORG-IDENTIFIER#", "organization:/address/city": "London", "/kind": ["user", "organization"], }; ``` 4. Review feature flag evaluation calls. Most of the pitfalls pointed out in the "Rewrite feature flag evaluation calls" part of the previous section applies here too. ### Implement experiments and analytics[​](#implement-experiments-and-analytics "Direct link to Implement experiments and analytics") There are some fundamental differences in the feature flag evaluation process between LaunchDarkly and ConfigCat. In ConfigCat, feature flag evaluation is entirely implemented within the SDKs, meaning your users' sensitive data never leaves your system. The data flow is one-way – from ConfigCat CDN servers to your SDKs – and ConfigCat does not receive or store any attributes of the [User Object](https://configcat.com/docs/targeting/user-object.md) passed to the SDKs. This design prioritizes the privacy and security of user data. However, this has an important consequence: as opposed to LaunchDarkly, ConfigCat cannot provide an out-of-the-box solution to A/B testing, experiments or other analytics. For this, you will need an additional service that provides the necessary functionality. Here are some examples of how you can integrate such tools with ConfigCat to replicate LaunchDarkly's analytics features: * [Amplitude](https://configcat.com/docs/integrations/amplitude.md#experiments) * [Google Analytics](https://configcat.com/docs/integrations/google-analytics.md) * [Mixpanel](https://configcat.com/docs/integrations/mixpanel.md#experiments) * [Twilio Segment](https://configcat.com/docs/integrations/segment.md#analytics) ## Migrate LaunchDarkly teams and permissions to ConfigCat[​](#migrate-launchdarkly-teams-and-permissions-to-configcat "Direct link to Migrate LaunchDarkly teams and permissions to ConfigCat") To complete the migration process, you will also need to migrate your teams and permissions from LaunchDarkly. At the moment, ConfigCat doesn't offer a tool or other automated solution for this task since there are fundamental differences between the user management and permission systems of the two services. LaunchDarkly allows more fine-grained access control over resources, while ConfigCat's permission system was designed to be simpler and easier to understand, at the expense of fewer possibilities for fine-tuning access control. Therefore, we can only give you some pointers, but this task will inevitably require some effort on your part. As the first step, we recommend getting familiar with ConfigCat's user management and permission system. You can find the basic concepts in the following guides: * [Organization & Roles](https://configcat.com/docs/organization.md) * [Team Management Basics](https://configcat.com/docs/advanced/team-management/team-management-basics.md) As you can see from this, ConfigCat doesn't use the concept of teams and roles of LaunchDarkly. You can't define such entities at the organization level, but *permission groups* per product instead. ### Map LaunchDarkly roles to ConfigCat permission groups[​](#map-launchdarkly-roles-to-configcat-permission-groups "Direct link to Map LaunchDarkly roles to ConfigCat permission groups") Permission groups roughly correspond to LaunchDarkly roles, with a few key differences: * They are scoped to the product where they are defined. * There are no [built-in roles](https://launchdarkly.com/docs/home/account/built-in-roles) like Reader or Writer. To recreate these in ConfigCat, you will need to define the corresponding permission groups in each relevant product. However, LaunchDarkly's Admin and Owner roles can't really be represented using permission groups. ConfigCat supports the concept of [Organization Admin role](https://configcat.com/docs/organization.md#organization-admin-role) but it's an organization-level permission. You can assign this to users on invite or on your organization's "Members & Roles" page as shown in the next section. * To migrate [custom roles](https://launchdarkly.com/docs/home/account/custom-roles) to ConfigCat, you will need to translate the [policies](https://launchdarkly.com/docs/home/account/role-concepts#policies) they define to the fixed set of permissions offered by ConfigCat permission groups. Obviously, this won't be entirely possible in every case. With this in mind, create the necessary permission groups in your products, based on the roles defined in your LaunchDarkly organization. To set up permission groups for a product, open the [ConfigCat Dashboard](https://app.configcat.com/organization), select the product on the sidebar, and choose "Permission Groups" in the top menu. ![Launching the import tool](/docs/assets/migration-from-launchdarkly/permission-groups_192dpi.png) ### Invite users to ConfigCat and assign them to permission groups[​](#invite-users-to-configcat-and-assign-them-to-permission-groups "Direct link to Invite users to ConfigCat and assign them to permission groups") Permission groups also act as per-product teams. Once created, you can assign users to them, who will then have the permissions specified by the permission group. (A user can only be a member of a single permission group at a time though.) This is how you map your LaunchDarkly teams to ConfigCat. However, users don't yet exist in ConfigCat at this point. You need to invite them to ConfigCat first. To do this, follow [these instructions](https://configcat.com/docs/advanced/team-management/team-management-basics.md#invite-others-to-collaborate). When inviting users, you will need to choose a product, more specifically, a permission group to invite them to. This means that they will be automatically assigned to the specified permission groups after signing up. So, as you have already created the permission groups, ideally you can immediately invite your users to the right permission groups. (Of course, you may need to do this in batches.) It can easily happen that you want to add a user to more than one product. In such cases, invite the user to one of the products (it doesn't matter which one), then, after they've signed up, navigate to the "Members & Roles" page of your organization, and assign them to the other products too, using the "Change roles" feature of the "Members & Roles" table. ![Launching the import tool](/docs/assets/migration-from-launchdarkly/member-and-roles_192dpi.png) --- # Source: https://configcat.com/docs/integrations/mixpanel.md # Mixpanel - Monitor your feature flag change events and feature flag analytics Copy page ## Overview[​](#overview "Direct link to Overview") There are two available integration opportunities between [ConfigCat and Mixpanel](https://mixpanel.com/partners/integrations/configcat): * [Monitoring your feature flag change events in Mixpanel with Annotations](#annotations) * [Sending feature flag evaluation analytics to Mixpanel Experiments](#experiments) ## Monitoring your feature flag change events in Mixpanel with Annotations[​](#annotations "Direct link to Monitoring your feature flag change events in Mixpanel with Annotations") Ensures that every setting change in ConfigCat is sent to Mixpanel as an [Annotation](https://docs.mixpanel.com/docs/reports/insights#annotations). ![Mixpanel Annotation](/docs/assets/mixpanel/annotation.png) ### Installation[​](#installation "Direct link to Installation") 1. Have a [Mixpanel account](https://mixpanel.com/). 2. Create a Service account that has at least an Analyst role. ![mixpanel\_service\_Account](/docs/assets/mixpanel/service_account.png) 3. Open the [integrations tab](https://app.configcat.com/product/integrations) on the ConfigCat Dashboard. 4. Click on Mixpanel's CONNECT button and set your Mixpanel Service Account's Username, Secret, and your Project ID. 5. OPTIONAL - Set the proper server of your Mixpanel account. [More about Mixpanel servers](https://docs.mixpanel.com/docs/privacy/eu-residency). 6. You're all set. Go ahead and make some changes on your feature flags, then check your annotations in Mixpanel. ### Un-installation[​](#un-installation "Direct link to Un-installation") 1. Open the [integrations tab](https://app.configcat.com/product/integrations) on the ConfigCat Dashboard. 2. Click on Mixpanel's DISCONNECT button. ### Annotation details[​](#annotation-details "Direct link to Annotation details") Every annotation sent to Mixpanel by ConfigCat has: * **Integration ID:** configcat. * **Date:** When the change happened * **Description:** A brief summary of the change. ## Sending feature flag evaluation analytics to Mixpanel Experiments[​](#experiments "Direct link to Sending feature flag evaluation analytics to Mixpanel Experiments") Ensures that feature flag evaluations are logged into [Mixpanel Experiments](https://docs.mixpanel.com/docs/reports/apps/experiments). With this integration, you can have advanced analytics about your feature flag usages, A/B test results. ### Setup[​](#setup "Direct link to Setup") 1. **Install SDKs:** Add both the ConfigCat SDK and Mixpanel SDK to your application. 2. **Configure SDKs:** * **ConfigCat SDK:** Initialize with your ConfigCat SDK key. * **Mixpanel SDK:** Set up with your Mixpanel token. 3. **Integrate Feature Flag Evaluations:** * During the initialization of the ConfigCat SDK, subscribe to the `flagEvaluated` hook. * Send feature flag evaluation data to Mixpanel using the `$experiment_started` event name. Include the following parameters: * `Experiment name`: the feature flag's key. * `Variant name`: the evaluated feature flag's value or variation ID * `Variation ID` (optional): the evaluated feature flag's variation ID * You can use the [Identify API](https://docs.mixpanel.com/docs/tracking-methods/id-management/identifying-users) in Mixpanel to enrich all your events with feature flag metadata. This way you can easily group/filter your existing Mixpanel events by feature flag evaluations. Code samples: * JavaScript, Node, SSR * React * Python * Ruby * Go * Java * Android * Swift (iOS) * Other languages ```js const configCatClient = configcat.getClient("#YOUR_SDK_KEY", PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', evaluationDetails => { // Send an `$experiment_started` event. mixpanel.track('$experiment_started', { 'Experiment name': evaluationDetails.key, 'Variant name': evaluationDetails.value, 'Variation ID': evaluationDetails.variationId }); // Use the identify API. mixpanel.people.set({ ["configcat_" + evaluationDetails.key]: evaluationDetails.value }); }), }); ``` ```tsx hooks.on('flagEvaluated', evaluationDetails => { // Send an `$experiment_started` event. mixpanel.track('$experiment_started', { 'Experiment name': evaluationDetails.key, 'Variant name': evaluationDetails.value, 'Variation ID': evaluationDetails.variationId }); // Use the identify API. mixpanel.people.set({ ["configcat_" + evaluationDetails.key]: evaluationDetails.value }); }), }} > ``` ```python def on_flag_evaluated(evaluation_details): # Send an `$experiment_started` event. mixpanel.track(evaluation_details.user.get_identifier(), '$experiment_started', { 'Experiment name': evaluation_details.key, 'Variant name': evaluation_details.value, 'Variation ID': evaluation_details.variation_id }) # Use the identify API. mixpanel.people_set(evaluation_details.user.get_identifier(), { f'configcat_{evaluationDetails.key}': evaluation_details.value, }) pass client = configcatclient.get('#YOUR-SDK-KEY#', ConfigCatOptions( hooks=Hooks(on_flag_evaluated=on_flag_evaluated) ) ) ``` ```ruby def on_flag_evaluated(evaluation_details): # Send an `$experiment_started` event. mixpanel.track(evaluation_details.user.get_identifier(), "$experiment_started", { "Experiment name": evaluation_details.key, "Variant name": evaluation_details.value, "Variation ID": evaluation_details.variation_id }) # Use the identify API. mixpanel.people.set(evaluation_details.user.get_identifier(), { "configcat_#{evaluationDetails.key}" => evaluation_details.value, }) end client = ConfigCat.get("#YOUR-SDK-KEY#", ConfigCat::ConfigCatOptions.new( hooks: ConfigCat::Hooks.new(on_flag_evaluated: method(:on_flag_evaluated)) ) ) ``` ```go mp := mixpanel.NewApiClient("#YOUR-MIXPANEL-PROJECT-TOKEN#") client := configcat.NewCustomClient(configcat.Config{SDKKey: "#YOUR-SDK-KEY#", Hooks: &configcat.Hooks{OnFlagEvaluated: func(details *configcat.EvaluationDetails) { // Send an `$experiment_started` event. _ = mp.Track(context.Background(), []*mixpanel.Event{ mp.NewEvent("$experiment_started", details.Data.User.(*configcat.UserData).Identifier, map[string]any{ "Experiment name": details.Data.Key, "Variant name": details.Value, "Variation ID": details.Data.VariationID, }), }) // Use the identify API. _ = mp.PeopleSet(context.Background(), []*mixpanel.PeopleProperties{ mixpanel.NewPeopleProperties(details.Data.User.(*configcat.UserData).Identifier, map[string]any{ "configcat_" + details.Data.Key: details.Value, }), }, ) }}}) ``` ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.hooks().addOnFlagEvaluated(details -> { // Send an `$experiment_started` event. JSONObject eventProps = new JSONObject(); eventProps.put("Experiment name", details.getKey()); eventProps.put("Variant name", details.getValue()); eventProps.put("Variation ID", details.getVariationId()); JSONObject event = messageBuilder.event(details.getUser().getIdentifier(), "$experiment_started", eventProps); mixpanel.sendMessage(event); // Use the identify API. JSONObject userProps = new JSONObject(); userProps.put("configcat_" + details.getKey(), details.getValue()); JSONObject updateUser = messageBuilder.set(details.getUser().getIdentifier(), userProps); mixpanel.sendMessage(updateUser); }); }); ``` ```java ConfigCatClient client = ConfigCatClient.get("#YOUR-SDK-KEY#", options -> { options.hooks().addOnFlagEvaluated(details -> { // Send an `$experiment_started` event. JSONObject eventProps = new JSONObject(); eventProps.put("Experiment name", details.getKey()); eventProps.put("Variant name", details.getValue()); eventProps.put("Variation ID", details.getVariationId()); mixpanel.track("$experiment_started", eventProps); // Use the identify API. mixpanel.getPeople().set("configcat_" + details.getKey(), details.getValue()); }); }); ``` ```swift let client = ConfigCatClient.get(sdkKey: "#YOUR-SDK-KEY#") { options in options.hooks.addOnFlagEvaluated { details in // Send an `$experiment_started` event. Mixpanel.mainInstance().track(event:"$experiment_started", properties: [ "Experiment name": details.key, "Variant name": details.value, "Variation ID": details.variationId ?? "", ]) // Use the identify API. let keyProperty = "configcat_" + details.Data.Key; Mixpanel.mainInstance().people.set(properties: [ keyProperty: details.value]) } } ``` While our documentation primarily provides code examples for languages that Mixpanel natively supports and has an official SDK, you can integrate with other languages by sending an event to Mixpanel with a third-party SDK or with using the [Mixpanel's Track Events API](https://developer.mixpanel.com/reference/track-event). 1. **Subscribe to the FlagEvaluated hook** in the ConfigCat SDK. 2. **Send an event to Mixpanel** using the `$experiment_started` event name. Include the following event properties: * `Experiment name`: the feature flag's key from the FlagEvaluated hook's EvaluationDetails * `Variant name`: the evaluated feature flag's value or the variationId from the FlagEvaluated hook's EvaluationDetails * `Variant name`: the evaluated feature flag's value or the variationId from the FlagEvaluated hook's EvaluationDetails * `distinct_id` (optional): in case you are using the tracking in a backend component or you don't identify all your event sendings to Mixpanel with user details, you have to send the [distinct\_id](https://docs.mixpanel.com/docs/tracking-methods/id-management/identifying-users#what-is-distinct-id) property as well to identify your user. You can use the User object's Identifier property from the FlagEvaluated hook or a value that best describes your user. note For Text feature flags with lengthy values (e.g., JSON), send the `variationId` instead of the `value` as the `Variant name` to Mixpanel. The `variationId` is a hashed version of the feature flag value, accessible on the ConfigCat Dashboard by enabling the *Show VariationIDs to support A/B testing* setting. Learn more [here](https://app.configcat.com/product/preferences). 4. Deploy your application and wait for feature flag evaluations to happen so Experiments in Mixpanel could be populated. ### Usage with Experiments[​](#usage-with-experiments "Direct link to Usage with Experiments") Check your Experiments page in Mixpanel, select your feature flag as the Experiment. ![Mixpanel Experiments report](/docs/assets/mixpanel/experiments.png) ### Usage with Insights report[​](#usage-with-insights-report "Direct link to Usage with Insights report") If you don't have access to the Experiments feature in Mixpanel, you can create a custom Insights report based on the `Experiment Started` event. You can filter for your feature flag keys with the `Experiment name` property and visualize the different variants by using the `Variant name` property as a Breakdown. Example: ![Mixpanel Insights report](/docs/assets/mixpanel/insights.png) ### Usage with enriched user properties for your custom events.[​](#usage-with-enriched-user-properties-for-your-custom-events "Direct link to Usage with enriched user properties for your custom events.") If you use the [Identify API](https://docs.mixpanel.com/docs/tracking-methods/id-management/identifying-users) approach, you'll be able to use the feature flag evaluation data in your current reports. Example with a Breakdown: ![Mixpanel Insights report with enriched data](/docs/assets/mixpanel/enrichment.png) ## Useful Resources[​](#useful-resources "Direct link to Useful Resources") * [Integrating ConfigCat and Mixpanel Analytics for Business Success - Blog Post](https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/) * [ConfigCat Integrations API](https://configcat.com/docs/api/reference/integrations/) --- # Source: https://configcat.com/docs/integrations/monday.md # monday.com - Manage feature flags from monday Copy page The [ConfigCat Feature Flags monday app](https://monday.com/marketplace/10000079) allows you to connect your Monday items and feature flags. Create or link existing flags to your items without leaving your monday instance. Turn features On/Off right from a linked item on your Monday board. You can also easily modify the linked flags to edit or add new Targeting or Percentage Rules. This guide will help you with the plugin installation and familiarise you with the plugin usage. ## Installation[​](#installation "Direct link to Installation") 1. Install [ConfigCat Feature Flags](https://monday.com/marketplace/10000079) monday.com app to your monday account. 2. Open one of your boards on monday.com and click on an Item. 3. Add the ConfigCat Feature Flags monday app to your Item. 4. To use ConfigCat Feature Flags, you must first authorize it with your ConfigCat Public API credentials. 5. Copy your ConfigCat Public API credentials to the inputs. Read more about [ConfigCat Public API credentials here](https://app.configcat.com/my-account/public-api-credentials). 6. Click **Authorize**. info Every monday.com user must authorize ConfigCat in monday.com who wants to use the ConfigCat Feature Flags app. Your browser does not support the video tag. ## Usage[​](#usage "Direct link to Usage") ### Linking existing feature flags[​](#linking-existing-feature-flags "Direct link to Linking existing feature flags") 1. Open any Item on your monday.com board. 2. Push the **Link existing feature flag** button. 3. Select a Product, Config, Environment, and Feature Flag to be linked to your monday.com Item. 4. When linked, you can manage the selected feature flag from this monday.com Item. Your browser does not support the video tag. ### Creating new feature flags[​](#creating-new-feature-flags "Direct link to Creating new feature flags") 1. Open any Item on your monday.com board. 2. Push the **Create and link feature flag** button. 3. Select a Product and Config where you want to create the feature flag. 4. Set up your feature flag. 5. Select which environment you would like to link to this Item. 6. When linked, you can manage the selected feature flag from this monday.com Item. Your browser does not support the video tag. ### View and Edit linked feature flags[​](#view-and-edit-linked-feature-flags "Direct link to View and Edit linked feature flags") 1. Open any Item on your monday.com board. 2. See the linked feature flags in the **Feature Flag (ConfigCat)** view. 3. You can manage the selected feature flag from this Item. 4. You can add new Targeting Rules or Percentage Options to Feature Flags. 5. You can add new Targeting Rules with User, Segment or Prerequisite conditions with a large selection of Comparators. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) 6. You can remove Targeting Rules as well. Your browser does not support the video tag. ### Remove linked feature flags[​](#remove-linked-feature-flags "Direct link to Remove linked feature flags") 1. Open any Item on your monday.com board with a linked feature flag. 2. Remove the linked feature flag by opening the **More menu** and selecting the **Unlink** option. Your browser does not support the video tag. ### View linked Items in ConfigCat[​](#view-linked-items-in-configcat "Direct link to View linked Items in ConfigCat") 1. View the linked Item next to your Feature Flags in ConfigCat and jump to the monday.com Item directly. Your browser does not support the video tag. --- # Source: https://configcat.com/docs/advanced/proxy/monitoring.md # Monitoring Copy page The ConfigCat Proxy provides diagnostic data including health status, metrics, and traces. info Exposed endpoints (`/status` and `/metrics`) are served on a specific port, so you can separate them from the public HTTP communication. These are the basic diagnostic-related options: | Option | Default | Description | | ---------------------------------------------------------------------------------------------------------------------- | ------- | ----------------------------------------------- | | - YAML
- Environment variable```yaml diag: enabled: ``````shell CONFIGCAT_DIAG_ENABLED= ``` | `true` | Turns the collection of diagnostic data on/off. | | - YAML
- Environment variable```yaml diag: port: 8051 ``````shell CONFIGCAT_DIAG_PORT=8051 ``` | `8051` | The port used by the diagnostics HTTP server. | ## Status Endpoint[​](#status "Direct link to Status Endpoint") The Proxy provides status information (health check) about its components on the following endpoint: GETOPTIONS/status The Proxy regularly checks whether the underlying SDKs can communicate with their configured source and with the cache. This endpoint returns the actual state of these checks. **Responses**: * 200: The status returned successfully. * 204: In response to an `OPTIONS` request. **Example Response**: ```json { "status": "healthy", "sdks": { "my_sdk": { "key": "****************************************hwTYg", "mode": "online", "source": { "type": "remote", "status": "healthy", "records": [ "Mon, 29 May 2023 16:36:40 UTC: [ok] config fetched" ] } }, "another_sdk": { "key": "****************************************ovVnQ", "mode": "offline", "source": { "type": "cache", "status": "healthy", "records": [ "Mon, 29 May 2023 16:36:40 UTC: [ok] reload from cache succeeded", "Mon, 29 May 2023 16:36:45 UTC: [ok] config from cache not modified" ] } } }, "cache": { "status": "healthy", "records": [ "Mon, 29 May 2023 16:36:40 UTC: [ok] cache read succeeded", "Mon, 29 May 2023 16:36:40 UTC: [ok] cache write succeeded", "Mon, 29 May 2023 16:36:40 UTC: [ok] cache read succeeded", "Mon, 29 May 2023 16:36:45 UTC: [ok] cache read succeeded" ] } } ``` **Details**: If everything is operational, each `status` node shows the value `healthy`. If a component encounters a failure, it'll put an error to its `records` collection. If a component's last two records are errors, its `status` will switch to `degraded`. If a component becomes operational again it'll put an `[ok]` to the `records` and will switch back to `healthy`. If an SDK couldn't initialize itself neither from an external cache nor from the ConfigCat CDN, its status will be `down`. It means, this SDK is not able to accept evaluation requests because it doesn't have a valid *config JSON* to work with. If an SDK was able to initialize from its configured source, but its last two attempts to refresh has been failed (either from cache or from the ConfigCat CDN), it will become `degraded` because each refresh attempt will put an error to its `records` collection. This means, it's still able to evaluate feature flags, but it might work on a stale *config JSON*. The root `status` is `healthy` if all of the SDKs are `healthy`. If any of the SDKs become `degraded` or `down`, the root will also switch to `degraded` (or `down` if each SDK is `down`). You can control whether metrics collection should be enabled with the following configuration option: | Option | Default | Description | | ---------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------ | | - YAML
- Environment variable```yaml diag: status: enabled: ``````shell CONFIGCAT_DIAG_STATUS_ENABLED= ``` | `true` | Turns the hosting of the [status endpoint](#status) on the diagnostics HTTP server on/off. | info You can enable the status endpoint on the main HTTP port (default: `8050`) with the [HTTP configuration options](https://configcat.com/docs/advanced/proxy/proxy-overview.md#http). ## Metrics[​](#metrics "Direct link to Metrics") If enabled, the Proxy collects various metrics. These can be either exported in Prometheus format or sent to an OTLP-compatible observability backend. You can control whether metric collection should be enabled with the following configuration option: | Option | Default | Description | | ------------------------------------------------------------------------------------------------------------------------------------------ | ------- | -------------------------------- | | - YAML
- Environment variable```yaml diag: metrics: enabled: ``````shell CONFIGCAT_DIAG_METRICS_ENABLED= ``` | `true` | Turns metrics collection on/off. | ### Prometheus[​](#prometheus-metrics "Direct link to Prometheus") You can set up the Proxy to export metrics about its internal state in Prometheus format. These metrics are served on the `/metrics` endpoint. #### Custom Metrics[​](#custom-metrics "Direct link to Custom Metrics") | Name | Type | Description | | --------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `configcat_stream_connections` | Gauge | Number of active client connections per stream.

Tags:- `sdk`: The SDK's identifier that handles the connection.
- `type`: `sse` or `grpc`.
- `flag`: The streamed feature flag's key. | | `configcat_stream_msg_sent_total` | Counter | Total number of all messages sent with streaming.

Tags:- `sdk`: The related SDK's identifier.
- `type`: `sse` or `grpc`.
- `flag`: The evaluated feature flag's key. | The Proxy also exports metrics about the Go environment, e.g., `go_goroutines` or `go_memstats_alloc_bytes`, and process-related stats, e.g., `process_cpu_seconds_total`. #### Integration[​](#integration "Direct link to Integration") To integrate with Prometheus, put the following scrape config—that points to the Proxy—into your Prometheus configuration: ```yaml scrape_configs: - job_name: configcat_proxy metrics_path: /metrics static_configs: - targets: - :8051 ``` #### Configuration Options[​](#configuration-options "Direct link to Configuration Options") | Option | Default | Description | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------ | | - YAML
- Environment variable```yaml diag: metrics: prometheus: enabled: ``````shell CONFIGCAT_DIAG_METRICS_PROMETHEUS_ENABLED= ``` | `true` | Turns the Prometheus compatible `/metrics` endpoint on the diagnostics HTTP server on/off. | ### OTLP[​](#otlp "Direct link to OTLP") You can set up the Proxy to send metrics via [OTLP](https://opentelemetry.io/docs/specs/otlp/) to a compatible collector such as [Amazon CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-OTLPEndpoint.html), [NewRelic](https://docs.newrelic.com/docs/opentelemetry/get-started/apm-monitoring/opentelemetry-apm-intro/), [DataDog](https://docs.datadoghq.com/opentelemetry/setup/otlp_ingest_in_the_agent), or [Honeycomb](https://docs.honeycomb.io/send-data/opentelemetry/). #### Custom Metrics[​](#custom-metrics-1 "Direct link to Custom Metrics") | Name | Type | Description | | ----------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `stream.connections` | Gauge | Number of active client connections per stream.

Tags:- `sdk`: The SDK's identifier that handles the connection.
- `type`: `sse` or `grpc`.
- `flag`: The streamed feature flag's key. | | `stream.msg.sent.total` | Counter | Total number of all messages sent with streaming.

Tags:- `sdk`: The related SDK's identifier.
- `type`: `sse` or `grpc`.
- `flag`: The evaluated feature flag's key. | #### Configuration Options[​](#configuration-options-1 "Direct link to Configuration Options") | Option | Default | Description | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------ | | - YAML
- Environment variable```yaml diag: metrics: otlp: enabled: ``````shell CONFIGCAT_DIAG_METRICS_OTLP_ENABLED= ``` | `false` | Turns the sending of metrics via OTLP on/off. | | - YAML
- Environment variable```yaml diag: metrics: otlp: protocol: "" ``````shell CONFIGCAT_DIAG_METRICS_OTLP_PROTOCOL="" ``` | `http` | The protocol used to send metrics over OTLP. Possible values: `http`, `https`, and `grpc`. | | - YAML
- Environment variable```yaml diag: metrics: otlp: endpoint: "localhost:4318" ``````shell CONFIGCAT_DIAG_METRICS_OTLP_ENDPOINT="localhost:4318" ``` | `localhost:4318` | The OTLP collector's endpoint. | Additional OTLP-related options can be set by using the default [OpenTelemetry environment variables](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/). For example, to set custom headers for each OTLP request, you can use the `OTEL_EXPORTER_OTLP_HEADERS` environment variable. ```shell OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer " ``` ## Traces[​](#traces "Direct link to Traces") The Proxy is able to send traces via [OTLP](https://opentelemetry.io/docs/specs/otlp/) to a compatible collector such as [Amazon CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-OTLPEndpoint.html), [NewRelic](https://docs.newrelic.com/docs/opentelemetry/get-started/apm-monitoring/opentelemetry-apm-intro/), [DataDog](https://docs.datadoghq.com/opentelemetry/setup/otlp_ingest_in_the_agent), or [Honeycomb](https://docs.honeycomb.io/send-data/opentelemetry/). You can control whether trace collection should be enabled with the following configuration option: | Option | Default | Description | | ---------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------ | | - YAML
- Environment variable```yaml diag: traces: enabled: ``````shell CONFIGCAT_DIAG_TRACES_ENABLED= ``` | `false` | Turns trace collection on/off. | #### OTLP-related Options[​](#otlp-related-options "Direct link to OTLP-related Options") | Option | Default | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | ----------------------------------------------------------------------------------------- | | - YAML
- Environment variable```yaml diag: traces: otlp: enabled: ``````shell CONFIGCAT_DIAG_TRACES_OTLP_ENABLED= ``` | `false` | Turns the sending of traces via OTLP on/off. | | - YAML
- Environment variable```yaml diag: traces: otlp: protocol: "" ``````shell CONFIGCAT_DIAG_TRACES_OTLP_PROTOCOL="" ``` | `http` | The protocol used to send traces over OTLP. Possible values: `http`, `https`, and `grpc`. | | - YAML
- Environment variable```yaml diag: traces: otlp: endpoint: "localhost:4318" ``````shell CONFIGCAT_DIAG_TRACES_OTLP_ENDPOINT="localhost:4318" ``` | `localhost:4318` | The OTLP collector's endpoint. | Additional OTLP-related options can be set by using the default [OpenTelemetry environment variables](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/). For example, to set custom headers for each OTLP request, you can use the `OTEL_EXPORTER_OTLP_HEADERS` environment variable. ```shell OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer " ``` ## OpenTelemetry Instrumentation Libraries[​](#opentelemetry-instrumentation-libraries "Direct link to OpenTelemetry Instrumentation Libraries") Metrics and traces are also exported by the following official OpenTelemetry instrumentation libraries: * [otelhttp](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/net/http/otelhttp) * [otelgrpc](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/google.golang.org/grpc/otelgrpc) * [redisotel](https://github.com/redis/go-redis/tree/master/extra/redisotel) * [otelmongo](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo) * [otelaws](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws) --- # Source: https://configcat.com/docs/glossary/multi-armed-bandit.md # Multi-Armed Bandit - Optimizing Decisions in Real-Time Copy page ## Introduction[​](#introduction "Direct link to Introduction") In an ever-evolving digital landscape, making optimal decisions swiftly can be the difference between success and stagnation. The Multi-Armed Bandit framework embodies this principle, offering a dynamic approach to decision-making that balances the exploration of new opportunities with the exploitation of known strategies. Explore the strategic world of Multi-Armed Bandits, where every choice has the potential to significantly enhance performance and outcomes. ## What is a Multi-Armed Bandit?[​](#what-is-a-multi-armed-bandit "Direct link to What is a Multi-Armed Bandit?") At its core, the Multi-Armed Bandit (MAB) problem is a scenario in which an agent is faced with several choices, or "arms," each with uncertain rewards. The agent must choose which arm to pull, metaphorically speaking, in a sequence of trials to maximize its total reward over time. This framework is a simplified model of the complex decision-making processes that occur in various fields such as finance, healthcare, online advertising, and more. ## The Goals of Multi-Armed Bandit Algorithms[​](#the-goals-of-multi-armed-bandit-algorithms "Direct link to The Goals of Multi-Armed Bandit Algorithms") * **Optimal Action Identification**: To discover and exploit the best possible actions that yield the highest rewards. * **Uncertainty Reduction**: To gather information about the reward distribution of each action. * **Regret Minimization**: To minimize the difference between the rewards received and the rewards that could have been received by always choosing the best action. ## The Multi-Armed Bandit Process[​](#the-multi-armed-bandit-process "Direct link to The Multi-Armed Bandit Process") * **Trial and Error**: The agent tests different arms to gather data on their performance. * **Reward Assessment**: After each trial, the agent assesses the reward from the chosen arm. * **Strategy Adaptation**: Based on accumulated knowledge, the agent refines its selection strategy. * **Continuous Learning**: The process is iterative, allowing continuous learning and adaptation to changing environments. ## Why Multi-Armed Bandit is Essential[​](#why-multi-armed-bandit-is-essential "Direct link to Why Multi-Armed Bandit is Essential") * **Real-Time Decision Making**: MAB algorithms provide a framework for making decisions on-the-fly in real-time environments. * **Resource Efficiency**: They help allocate limited resources to the most effective strategies. * **Adaptability**: MABs are robust to changes and can quickly adjust strategies based on new data. * **Experimental Efficiency**: They are crucial in A/B testing scenarios where rapid learning is essential. ## Challenges in Multi-Armed Bandit Implementations and Solutions[​](#challenges-in-multi-armed-bandit-implementations-and-solutions "Direct link to Challenges in Multi-Armed Bandit Implementations and Solutions") * **Exploration vs. Exploitation Dilemma**: Balancing the need to explore new actions with the need to exploit known high-reward actions. Solution: Employ algorithms like epsilon-greedy, UCB (Upper Confidence Bound), or Thompson Sampling to manage this trade-off effectively. * **Dynamic Environments**: Adapting to environments where reward distributions change over time. Solution: Use non-stationary MAB algorithms that adjust to trends and volatility. * **Complex Reward Structures**: Dealing with scenarios where rewards are not immediate or straightforward. Solution: Develop MAB models that can handle delayed feedback and complex reward mechanisms. ## Conclusion[​](#conclusion "Direct link to Conclusion") The Multi-Armed Bandit framework is a powerful tool in the modern decision-maker's arsenal, allowing for smarter, data-driven choices that evolve with experience. Whether it's optimizing click-through rates in digital marketing or determining treatment plans in clinical trials, MABs offer a structured yet flexible approach to navigating the uncertainties inherent in decision-making processes. As we continue to harness the potential of these algorithms, the ceiling for innovation and efficiency rises ever higher. --- # Source: https://configcat.com/docs/sdk-reference/openfeature/nestjs.md # Using ConfigCat's OpenFeature Provider in NestJS Copy page ## Getting started[​](#getting-started "Direct link to Getting started") OpenFeature offers a [NestJS SDK](https://github.com/open-feature/js-sdk/tree/main/packages/nest) to streamline the use of OpenFeature in NestJS applications. This SDK is built on top of the [OpenFeature JavaScript Node.js SDK](https://github.com/open-feature/js-sdk/blob/main/packages/server). Since ConfigCat implements [a provider](https://configcat.com/docs/sdk-reference/openfeature/node.md) for the Node.js SDK, you can use ConfigCat with the OpenFeature NestJS SDK, as explained below. ### 1. Install the NestJS SDK and the ConfigCat provider[​](#1-install-the-nestjs-sdk-and-the-configcat-provider "Direct link to 1. Install the NestJS SDK and the ConfigCat provider") ```bash npm i @openfeature/nestjs-sdk @openfeature/config-cat-provider ``` ### 2. Initialize the NestJS SDK[​](#2-initialize-the-nestjs-sdk "Direct link to 2. Initialize the NestJS SDK") The `ConfigCatProvider.create()` function takes the SDK key, the desired [polling mode](https://configcat.com/docs/sdk-reference/js/node.md#polling-modes) (Auto Polling is recommended for this kind of application) and an optional `options` argument containing additional configuration options for the underlying [ConfigCat client](https://configcat.com/docs/sdk-reference/js/node.md#creating-the-configcat-client): ```ts import { Module } from '@nestjs/common'; import { OpenFeatureModule } from '@openfeature/nestjs-sdk'; import { ConfigCatProvider } from '@openfeature/config-cat-provider'; import { createConsoleLogger, LogLevel, PollingMode } from '@configcat/sdk'; import { FeatureFlagService } from './_services/feature-flag.service'; const configCatProvider = ConfigCatProvider.create('#YOUR-SDK-KEY#', PollingMode.AutoPoll, { // Specify options for the underlying ConfigCat client logger: createConsoleLogger(LogLevel.Info), setupHooks: (hooks) => hooks.on('clientReady', () => console.log('Client is ready!')), // ... }); @Module({ imports: [ OpenFeatureModule.forRoot({ defaultProvider: configCatProvider, // Set the context for your evaluations contextFactory: (request) => ({ targetingKey: 'user-1' }) }), ], controllers: [/* ... */], providers: [FeatureFlagService], }) export class AppModule {} ``` ### 3. Use your feature flag[​](#3-use-your-feature-flag "Direct link to 3. Use your feature flag") To improve maintainability and testability, it's usually a good idea not to directly evaluate your feature flags, but to wrap them in a service: ```ts import { Injectable } from '@nestjs/common'; import { OpenFeatureClient, Client } from '@openfeature/nestjs-sdk'; @Injectable() export class FeatureFlagService { constructor( @OpenFeatureClient() private readonly defaultClient: Client, ) { } public async isAwesomeFeatureEnabled() { return await this.defaultClient.getBooleanValue('isAwesomeFeatureEnabled', false); } } ``` Then you can inject this service into your controllers and use it to evaluate feature flags: ```ts import { Controller, Get } from '@nestjs/common'; import { FeatureFlagService } from './_services/feature-flag.service'; @Controller() export class AppController { constructor( private readonly featureFlagService: FeatureFlagService ) {} @Get() async welcome() { return await this.featureFlagService.isAwesomeFeatureEnabled() ? 'Awesome feature is enabled!' : 'Awesome feature is disabled.'; } } ``` ## Evaluation Context[​](#evaluation-context "Direct link to Evaluation Context") An [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context) in the OpenFeature specification is a container for arbitrary contextual data that can be used as a basis for feature flag evaluation. You can find [here](https://configcat.com/docs/sdk-reference/openfeature/node.md#evaluation-context) how the ConfigCat provider translates these evaluation contexts to ConfigCat [User Objects](https://configcat.com/docs/sdk-reference/js/node.md#user-object). ## Advanced features[​](#advanced-features "Direct link to Advanced features") Read the documentation of the [OpenFeature NestJS SDK](https://openfeature.dev/docs/reference/technologies/server/javascript/nestjs/) to learn more about the advanced capabilities of the SDK. ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat OpenFeature Provider's repository on GitHub](https://github.com/open-feature/js-sdk-contrib/tree/main/libs/providers/config-cat) * [ConfigCat OpenFeature Provider in NPM](https://www.npmjs.com/package/@openfeature/config-cat-provider) --- # Source: https://configcat.com/docs/network-traffic.md # Network Traffic Copy page Network Traffic refers to the data transmitted between your applications and ConfigCat CDN. It includes the requests made to fetch feature flags and settings. Generally speaking, the Network Traffic is proportional to: * the size of the `config JSON`, * the number of clients connecting to ConfigCat, * and the frequency of changes in the `config JSON`. Here are a few examples of config JSON file sizes: | Config JSON complexity | | Network Traffic | | | ---------------------- | --------------- | ------------------- | ----------------------------------- | | # of feature flags | Targeting Rules | first download size | no change
`304 - Not Modified` | | 11 | none | 0.5 kB | 65 B | | 17 | few | 1.6 kB | 65 B | | 370 | many | 159 kB | 65 B | #### Size of the `config JSON`[​](#size-of-the-config-json "Direct link to size-of-the-config-json") It is affected by the number of feature flags, settings, targeting rules, segments, and the length of their values. #### Number of clients connecting to ConfigCat[​](#number-of-clients-connecting-to-configcat "Direct link to Number of clients connecting to ConfigCat") Every time a client downloads the config JSON, it contributes to the overall Network Traffic. #### Frequency of changes in the `config JSON`[​](#frequency-of-changes-in-the-config-json "Direct link to frequency-of-changes-in-the-config-json") The `config JSON` is cached on the ConfigCat CDN. If there is no change, the ConfigCat CDN will respond with `304 Not Modified`. If there is a change, the ConfigCat CDN will respond with `200 OK` and the new `config JSON` content in the response body. ### Shared infrastructure[​](#shared-infrastructure "Direct link to Shared infrastructure") The following plans run on shared infrastructure. So all customers use the same API nodes and Config Delivery Network (CDN). | Plan | Data / month | | -------------- | ------------ | | **Free** | 20 GB | | **Pro** | 100 GB | | **Smart** | 1 TB | | **Enterprise** | 4 TB | info If you hit this limit, we will keep your application up and running. However, you can expect us to contact you on how we can meet your needs. ### Dedicated infrastructure[​](#dedicated-infrastructure "Direct link to Dedicated infrastructure") The following plans include dedicated API and CDN nodes. #### Hosted[​](#hosted "Direct link to Hosted") Runs on dedicated servers provided by ConfigCat. | | Data / month | | ----------------- | ------------ | | **Basic package** | 24 TB | #### On-Premise (Self-hosted)[​](#on-premise-self-hosted "Direct link to On-Premise (Self-hosted)") Runs on the customer's own servers. We suggest [contacting ConfigCat's engineering](https://configcat.com/support/) team on exact requirements and performance. ## How to reduce the monthly Network Traffic?[​](#how-to-reduce-the-monthly-network-traffic "Direct link to How to reduce the monthly Network Traffic?") ### Delete the old feature flags and unused Targeting Rules[​](#delete-the-old-feature-flags-and-unused-targeting-rules "Direct link to Delete the old feature flags and unused Targeting Rules") If you have a large number of feature flags and Targeting Rules in a config, you can reduce the size of the `config JSON` by deleting the old ones. The [Zombie Flags](https://configcat.com/docs/zombie-flags.md) feature can help you finding stale feature flags. ### Avoid keeping lots of data in the comparison value of Targeting Rules or segments[​](#avoid-keeping-lots-of-data-in-the-comparison-value-of-targeting-rules-or-segments "Direct link to Avoid keeping lots of data in the comparison value of Targeting Rules or segments") The comparison value of a Targeting Rule or segment is stored in the `config JSON` and downloaded by the SDKs. If you have a lot of Targeting Rules or segments with lengthy comparison values, you can reduce the size of the `config JSON` by shortening them. ### Consider the amount of text you keep in a text setting's value[​](#consider-the-amount-of-text-you-keep-in-a-text-settings-value "Direct link to Consider the amount of text you keep in a text setting's value") Similarly to the comparison value of Targeting Rules or segments, the value of a text setting is stored in the `config JSON` and downloaded by the SDKs. If you have a lot of text settings with lengthy values, you can reduce the size of the `config JSON` by shortening them. ### Separate your feature flags into multiple configs[​](#separate-your-feature-flags-into-multiple-configs "Direct link to Separate your feature flags into multiple configs") If you have a large number of feature flags, you can reduce the size of the `config JSON` by separating them into multiple configs. This way, the payload of each download will be smaller. ### Use the ConfigCat Proxy to cache/proxy config JSON downloads[​](#use-the-configcat-proxy-to-cacheproxy-config-json-downloads "Direct link to Use the ConfigCat Proxy to cache/proxy config JSON downloads") The [ConfigCat Proxy](https://configcat.com/docs/advanced/proxy/proxy-overview.md) allows you to host a feature flag evaluation and config JSON proxy/cache service within your own infrastructure.
The [CDN proxy](https://configcat.com/docs/advanced/proxy/endpoints.md#cdn-proxy) feature allows you to proxy/cache config JSON downloads, and the ConfigCat SDKs can be routed to the ConfigCat Proxy running in your own infrastructure greatly reducing network traffic. ### Purchase additional network traffic[​](#purchase-additional-network-traffic "Direct link to Purchase additional network traffic") You can purchase an add-on for your subscription to increase your limits. [Contact us](https://configcat.com/support/) for more information. | Plan | Price | Additional config JSON downloads | Additional network traffic | | -------------- | ----------------- | -------------------------------- | -------------------------- | | **Smart** | $250 or €229 / mo | +250 million | +1TB | | **Enterprise** | $700 or €649 / mo | +1 billion | +4TB | --- # Source: https://configcat.com/docs/news.md # News & Product Updates Copy page Here, you'll find all the latest updates, enhancements, and new features we've added to our service. Stay tuned to this page to keep up with all the latest news from ConfigCat! ## Feature flag evaluation in GitHub Actions[​](#feature-flag-evaluation-in-github-actions "Direct link to Feature flag evaluation in GitHub Actions") #### Feb 2, 2026[​](#feb-2-2026 "Direct link to Feb 2, 2026") We have released a new GitHub Action that can evaluate feature flags in GitHub workflows. For more details about how to use the action, [see the documentation](https://configcat.com/docs/integrations/github-eval.md). *** ## Enhanced SDK key filtering with Proxy Profile selection rules[​](#enhanced-sdk-key-filtering-with-proxy-profile-selection-rules "Direct link to Enhanced SDK key filtering with Proxy Profile selection rules") #### Jan 30, 2026[​](#jan-30-2026 "Direct link to Jan 30, 2026") We're happy to announce that we improved the Proxy Profile's SDK key selection mechanism. In addition to manual configuration, you can now build custom selection rules that respond to future product, config, and environment creation/deletion/renaming. ![Proxy Profile selection rules](/docs/assets/proxy/profile-selection-rules2.png) For more details about how selection rules work, [see the documentation](https://configcat.com/docs/advanced/proxy/proxy-overview.md#selection-rules). *** ## New payment currencies (AUD, GBP) available[​](#new-payment-currencies-aud-gbp-available "Direct link to New payment currencies (AUD, GBP) available") #### Jan 27, 2026[​](#jan-27-2026 "Direct link to Jan 27, 2026") You can now pay your ConfigCat subscription in **Australian dollars (AUD)** and **British pounds (GBP)**, in addition to USD and EUR. To switch from your current payment currency, contact [](mailto:sales@configcat.com). We will help you with the change. If you prefer another currency, just let us know at [](mailto:sales@configcat.com). We will check what is possible and get back to you. *** ## More control over your Slack notifications[​](#more-control-over-your-slack-notifications "Direct link to More control over your Slack notifications") #### Jan 19, 2026[​](#jan-19-2026 "Direct link to Jan 19, 2026") Good news! We listened to your feedback and made our Slack integration more flexible. You can now control whether Slack notifications show or hide sensitive targeting data. This gives more context in private channels, while keeping safe defaults for shared ones. Until now, comparison values used with confidential (hashed) operators were always masked in Slack. This remains the default behavior. From now on, you can optionally change this setting for existing Slack integrations on the [Integrations page](https://app.configcat.com/product/integrations).
When creating a new Slack integration, you will be asked during setup whether targeting rule values should be sent in cleartext. No action is required to keep sensitive data hidden for existing integrations. We recommend keeping this setting disabled for shared or public Slack channels. ![Slack integration sensitive data](/docs/assets/news/slack-sensitive_192dpi.png) *** ## ConfigCat MCP Server[​](#configcat-mcp-server "Direct link to ConfigCat MCP Server") #### Sept 30, 2025[​](#sept-30-2025 "Direct link to Sept 30, 2025") We just released a new official ConfigCat's Model Context Protocol (MCP) Server. AI tools like Cursor can now interact with ConfigCat via our new MCP server. * **Complete set of tools for ConfigCat's Public Management API operations** You can Create, Read, Update and Delete any entities like Feature Flags, Configs, Environments or Products within ConfigCat. * **Enables your code editor to understand your feature flags** Integrate the appropriate ConfigCat SDK, implement feature flags in your project, remove Zombie (stale) flags and more. []() For more info about how to set up the MCP server, [see Documentation](https://configcat.com/docs/advanced/mcp-server.md). *** ## Automatic ConfigCat Proxy configuration with Proxy profiles / OpenFeature Remote Evaluation Protocol[​](#automatic-configcat-proxy-configuration-with-proxy-profiles--openfeature-remote-evaluation-protocol "Direct link to Automatic ConfigCat Proxy configuration with Proxy profiles / OpenFeature Remote Evaluation Protocol") #### Aug 22, 2025[​](#aug-22-2025 "Direct link to Aug 22, 2025") We have two exciting [ConfigCat Proxy](https://configcat.com/docs/advanced/proxy/proxy-overview.md) related news: 1. From the [v2.0.0](https://github.com/configcat/configcat-proxy/releases/tag/v2.0.0) version, the Proxy has the ability to use [Proxy profiles](https://app.configcat.com/organization/proxy-profiles) to determine which SDK keys to download and distribute. info You need to be an Organization Admin to access the Proxy profiles page on the Dashboard. ![Proxy profiles page](/docs/assets/news/proxy-profiles.png) [See the documentation](https://configcat.com/docs/advanced/proxy/proxy-overview.md#1-automatic-configuration-with-proxy-profiles) for more information on how to set up your Proxy with profiles. 2. From the [v2.0.0](https://github.com/configcat/configcat-proxy/releases/tag/v2.0.0) version, the Proxy conforms to the [OpenFeature Remote Evaluation Protocol](https://github.com/open-feature/protocol) (OFREP), which means it can be used with OFREP compatible OpenFeature providers. [See the API documentation](https://configcat.com/docs/advanced/proxy/endpoints.md#openfeature-remote-evaluation-protocol-ofrep) for the OFREP implementation with usage examples. *** ## New SDK for JavaScript with Cloudflare Workers support[​](#new-sdk-for-javascript-with-cloudflare-workers-support "Direct link to New SDK for JavaScript with Cloudflare Workers support") #### Aug 15, 2025[​](#aug-15-2025 "Direct link to Aug 15, 2025") We just released the [new, revamped ConfigCat SDK for JavaScript platforms](https://configcat.com/docs/sdk-reference/js/overview/). Unlike the previous platform-specific SDKs, it ships as a [single, unified NPM package](https://www.npmjs.com/package/@configcat/sdk) that supports multiple JS environments. ![Unified NPM package](/docs/assets/news/unified-js-sdk_192dpi.png) The new SDK combines and, thus, supersedes these SDKs: * [ConfigCat SDK for JavaScript frontend applications](https://configcat.com/docs/sdk-reference/js/) * [ConfigCat SDK for JavaScript Server-Side Rendered applications](https://configcat.com/docs/sdk-reference/js-ssr/) * [ConfigCat SDK for Node.js](https://configcat.com/docs/sdk-reference/node/) * [ConfigCat SDK for Chromium Extensions](https://github.com/configcat/js-chromium-extension-sdk) The legacy SDKs remain available for use but won't receive new features and improvements any more. They will continue getting security updates until official support ends on August 31, 2026. The new SDK maintains strong backward compatibility, so in most cases migration is simple and straightforward. For details, see the "Migration to the new SDK" section in the SDK references linked above. But there are other advantages to upgrading to the new SDK sooner rather than later: * Most notably, it adds support for **Deno**, **Bun** and **Cloudflare Workers**. Plus, makes the Browser and Chromium Extension SDKs work in **Web Workers** too. * Another improvement worth mentioning is that the new SDK is a **zero-dependency library**, which can spare you some package management-related headaches. It distributes **ES2017-compatible code** to allow you to minimize the library's footprint in your application bundles. * A nice new feature is **query string-based flag overrides** (especially handy during development) and the possibility of **custom flag override data sources** - even with full feature flags, not just simple values (useful for testing). * Then there is a **new hook** named `configFetched` for observing config fetch errors and **new options** named `configFetcher` and `logFilter` for customizing config fetching and logging. * Error reporting received nice improvements as well: among others, the SDK now includes **error codes** to help identify error causes. For the full list of new features and improvements, take a look at the [release notes](https://github.com/configcat/js-unified-sdk/releases/tag/v1.0.0). *** ## New ConfigCat OpenFeature providers[​](#new-configcat-openfeature-providers "Direct link to New ConfigCat OpenFeature providers") #### July 4, 2025[​](#july-4-2025 "Direct link to July 4, 2025") We're happy to share that we have released new OpenFeature providers for the following platforms: * [Angular](https://configcat.com/docs/sdk-reference/openfeature/angular.md) * [React](https://configcat.com/docs/sdk-reference/openfeature/react.md) * [NestJS](https://configcat.com/docs/sdk-reference/openfeature/nestjs.md) * [Swift (iOS)](https://configcat.com/docs/sdk-reference/openfeature/swift.md) * [Kotlin (Android)](https://configcat.com/docs/sdk-reference/openfeature/kotlin.md) * [Ruby](https://configcat.com/docs/sdk-reference/openfeature/ruby.md) [See the documentation](https://configcat.com/docs/sdk-reference/openfeature/overview.md) for the complete list of currently supported platforms. *** ## Quality of Life improvements[​](#quality-of-life-improvements "Direct link to Quality of Life improvements") #### Jun 3, 2025[​](#jun-3-2025 "Direct link to Jun 3, 2025") We've just rolled out a set of updates that make working with feature flags in ConfigCat smoother and more practical. Here's what's new: ### Zombie flag Report improvements[​](#zombie-flag-report-improvements "Direct link to Zombie flag Report improvements") Stale feature flags can build up quickly and lead to technical debt. We've improved the Zombie Flags feature to make it more useful and easier to manage: * **New Zombie Flags page** The original email report didn't offer immediate feedback. That's why we created the new [Zombie Flags page](https://app.configcat.com/product/zombie-flags), where you can instantly view stale flags and filter them by product. If you're using our [Code References](https://configcat.com/docs/advanced/code-references/overview.md) feature, the page also shows exactly where the flags appear in your code, making it easier to clean things up. * **Ignore flags by tag** If you have long-lived feature flags that are meant to stay, you can now tag them (for example, with “permanent”) and exclude them from the Zombie Flags Report. * **Less noise, more focus** The previous report included any flag that was stale in at least one selected environment. Now, you can adjust the settings so only flags that are stale in all selected environments appear in the report. * **Now available via API** You can also check stale flags programmatically using the [Zombie (stale) flags](https://configcat.com/docs/api/reference/get-staleflags.md) endpoint in our Public Management API. Narrow down your [Zombie Flags Report](https://app.configcat.com/my-account/zombie-flags-report) email with the new preferences, try out our new [Zombie Flags page](https://app.configcat.com/product/zombie-flags), or check the [documentation](https://configcat.com/docs/zombie-flags.md) to learn more. ![Zombie Flags page](/docs/assets/news/zombie-page_192dpi.png) ### Clone feature flag[​](#clone-feature-flag "Direct link to Clone feature flag") Cloning a feature flag now lets you quickly create a new flag in any config. It copies over all the targeting rules, values across environments, and tags, making setup faster and more consistent. ![Clone feature flag](/docs/assets/news/clone-feature-flag_192dpi.png) ### Copy all feature flag rules[​](#copy-all-feature-flag-rules "Direct link to Copy all feature flag rules") We've made it easier to copy flag values across environments. Now, you can: * Copy rules for an entire config, or * Choose specific feature flags to copy. ![Copy all feature flag rules](/docs/assets/news/copy-all-feature-flag-values_192dpi.png) ### A Smoother Flag Creation Experience[​](#a-smoother-flag-creation-experience "Direct link to A Smoother Flag Creation Experience") When creating a new feature flag, you no longer have to set values separately for each environment. You can now set them once globally, then fine-tune as needed later. We truly hope you'll love these new features and improvements. Happy feature flagging! ❤️ *** ## 🚀 Refer & Earn with ConfigCat[​](#-refer--earn-with-configcat "Direct link to 🚀 Refer & Earn with ConfigCat") #### May 30, 2025[​](#may-30-2025 "Direct link to May 30, 2025") Earn up to **$10,000 per referral** just by sharing something you already love. ### Here’s how it works:[​](#heres-how-it-works "Direct link to Here’s how it works:") * 👥 The people you refer get **10% off** any paid plan. * 💰 You earn **20% of their payments**, up to **$10,000 per referral**. * 💸 Get paid via **PayPal** (more payout options coming soon). * 🔗 Share your unique referral link via **email, LinkedIn, or QR code** – powered by [Cello](https://cello.so/). ![Refer and Earn](/docs/assets/news/refer-and-earn.png) ![Refer and Earn](/docs/assets/news/invite.png) > This isn’t just a referral program - it’s our way of saying *thank you* for being part of the ConfigCat community.
You help us grow, and we make sure you benefit too. ✅ No cold outreach. No contact sharing. You're simply sharing something you already use and like. **Ready to start earning?**
Click the **“Refer & Earn”** button in your ConfigCat dashboard and let the rewards roll in. *** ## User provisioning (SCIM) is here\![​](#user-provisioning-scim-is-here "Direct link to User provisioning (SCIM) is here!") #### May 21, 2025[​](#may-21-2025 "Direct link to May 21, 2025") **We're happy to announce that ConfigCat now supports user provisioning using SCIM (System for Cross-domain Identity Management)!** SCIM makes it easy to sync users and groups from your Identity Provider into your ConfigCat Organization. Once synced, you can link Identity Provider groups to ConfigCat permission groups, so users are placed in the right roles without manual work. We've tested the feature with [Entra ID (Azure AD)](https://configcat.com/docs/advanced/team-management/scim/identity-providers/entra-id.md), [Okta](https://configcat.com/docs/advanced/team-management/scim/identity-providers/okta.md) and [OneLogin](https://configcat.com/docs/advanced/team-management/scim/identity-providers/onelogin.md), but any Identity Provider that supports the SCIM 2.0 protocol should work too. SCIM provisioning is available on all ConfigCat plans, including the Free plan. Each plan includes limits for synced users, groups, and permission assignments. See details [here](https://configcat.com/docs/subscription-plan-limits.md). Read our [documentation](https://configcat.com/docs/advanced/team-management/scim/scim-overview.md) and set up the User provisioning on the [Authentication & Provisioning](https://app.configcat.com/organization/authentication) page in your ConfigCat Dashboard. info You'll need to be an Organization Admin to access it. ![Identity Provider groups](/docs/assets/news/scim-groups.png) ![Identity Provider users](/docs/assets/news/scim-users.png) *** ## Import from LaunchDarkly is here\![​](#import-from-launchdarkly-is-here "Direct link to Import from LaunchDarkly is here!") #### Apr 29, 2025[​](#apr-29-2025 "Direct link to Apr 29, 2025") **Thinking about moving away from LaunchDarkly? ConfigCat just made that easier for you.** If you're curious about switching to a LaunchDarkly alternative, ConfigCat has good news for you: we've launched a new feature called the "Import from LaunchDarkly" tool, which makes it a breeze to migrate LaunchDarkly feature flags and segments into ConfigCat. It's available on all plans, even the Free plan. So if you're just exploring, you can give it a go with zero commitment. (Just a heads-up: your plan's limits still apply. If you bump into anything, [contact us](https://configcat.com/support/?prefilled=ld-import-limit), and we'll surely figure out a solution for you!) You can find the import tool on the [Organization Overview](https://app.configcat.com/organization) page in your ConfigCat Dashboard: ![Launching the import tool](/docs/assets/migration-from-launchdarkly/launch-import-tool_192dpi.png) info You'll need to be an Organization Admin to access it. If you decide to make the full switch, we've prepared a [migration guide](https://configcat.com/docs/advanced/migration-from-launchdarkly.md) to walk you through the whole process. So why not make the jump? You'll land on your paws anyway. 🐱 *** ## Price Adjustment & Smart Plan Update[​](#price-adjustment--smart-plan-update "Direct link to Price Adjustment & Smart Plan Update") #### Feb 17, 2025[​](#feb-17-2025 "Direct link to Feb 17, 2025") As of 17th February 2025, we've made the following updates: ### Price adjustment[​](#price-adjustment "Direct link to Price adjustment") Due to changes in the EUR-USD exchange rate, we've made an adjustment to our prices: * Our EUR plans will have a 10% increase * Our USD plans will have a 1% increase This applies only to new upgrades and future customers. ### Smart plan Update[​](#smart-plan-update "Direct link to Smart plan Update") * The Smart Plan now has a product limit of 10. Existing Smart plan customers are not affected by this change. *** ## What's new in 2025[​](#whats-new-in-2025 "Direct link to What's new in 2025") #### Jan 20, 2025[​](#jan-20-2025 "Direct link to Jan 20, 2025") We have a few important updates to share with you, including new integrations, changes to our pricing, and some highly requested features. Here's what's happening: ### 🚀 ConfigCat now available in JetBrains Marketplace[​](#-configcat-now-available-in-jetbrains-marketplace "Direct link to 🚀 ConfigCat now available in JetBrains Marketplace") We're happy to announce that the ConfigCat Feature Flag plugin is now available on the JetBrains Marketplace. You can now manage your feature flags directly from 15 supported JetBrains IDEs. Check out the plugin [here](https://configcat.com/docs/integrations/intellij/). ### 🌓 Dark Mode & UI Facelift[​](#-dark-mode--ui-facelift "Direct link to 🌓 Dark Mode & UI Facelift") Dark Mode has been one of the most requested features, and we're happy to announce that it's now available!
Plus, we've given the UI a fresh, modern look to make things even easier and more enjoyable to use. ![Darkmode](/docs/assets/news/darkmode.png) ### 💳 Multiple Payment Sources[​](#-multiple-payment-sources "Direct link to 💳 Multiple Payment Sources") You can now add backup credit cards to your organization, making your payments more flexible and secure. ### 📈 Price adjustments and Plan updates[​](#-price-adjustments-and-plan-updates "Direct link to 📈 Price adjustments and Plan updates") We're making a few changes to our pricing plans, which will take effect on 17th February 2025. * *Price adjustment* Over the past few years, the constantly fluctuating USD/EUR exchange rate has significantly widened the gap between our EUR and USD pricing. We're making adjustments to bring these prices closer together: * Our EUR plans will have a 10% increase * Our USD plans will have a 1% increase This change will only apply to upgrades and will affect future customers starting on the 17th February 2025. * *Updates to Free and Smart plans* * Free Plan: The Product limit has been increased to 2. Existing Free plan users have automatically received this benefit. * Smart Plan (effective from 17 February 2025): The Product limit will be capped at 10. Existing Smart plan customers will not be affected by this change. *** ## Disable two-factor authentication permission[​](#disable-two-factor-authentication-permission "Direct link to Disable two-factor authentication permission") #### Oct 8, 2024[​](#oct-8-2024 "Direct link to Oct 8, 2024") You can disable two-factor authentication for your team members. This feature is useful if someone loses the device used for two-factor authentication. *Only team members with Organization Admin role or with 'Can disable two-factor authentication for other team members' permission can disable two-factor authentication.* [Open Team Members page on our Dashboard](https://app.configcat.com/product/members) *** ## Introducing ConfigCat Playground: Test Feature Flags Easily in a safe environment[​](#introducing-configcat-playground-test-feature-flags-easily-in-a-safe-environment "Direct link to Introducing ConfigCat Playground: Test Feature Flags Easily in a safe environment") #### Sept 26, 2024[​](#sept-26-2024 "Direct link to Sept 26, 2024") We've just released the ConfigCat Playground, a simulator that provides a safe virtual environment where you can try out everything ConfigCat has to offer. This new feature gives you virtual devices and a virtual app that can be connected to your ConfigCat feature flags. This lets you test feature flags and targeting rules without needing to connect any real applications. Please do not use the Playground with feature flags already connected to live applications. We highly recommend using feature flags from non-production environments when experimenting in the Playground. To get started, simply click on the **"Test in Playground"** option in the **...** menu of any boolean feature flag inside your ConfigCat Dashboard. ![ConfigCat Playground](/docs/assets/news/playground.png) ![Test in Playground option in the ... menu](/docs/assets/news/playground-context-menu.png) *** ## New ConfigCat OpenFeature providers[​](#new-configcat-openfeature-providers-1 "Direct link to New ConfigCat OpenFeature providers") #### Sept 6, 2024[​](#sept-6-2024 "Direct link to Sept 6, 2024") We're happy to share that we have released new OpenFeature providers for the following platforms: * [PHP](https://configcat.com/docs/sdk-reference/openfeature/php.md) * [Python](https://configcat.com/docs/sdk-reference/openfeature/python.md) * [Rust](https://configcat.com/docs/sdk-reference/openfeature/rust.md) [See the documentation](https://configcat.com/docs/sdk-reference/openfeature/overview.md) for the complete list of currently supported platforms. *** ## Integration management via Public Management API and Terraform[​](#integration-management-via-public-management-api-and-terraform "Direct link to Integration management via Public Management API and Terraform") #### Aug 13, 2024[​](#aug-13-2024 "Direct link to Aug 13, 2024") From now on, you can manage your Integrations through the ConfigCat Public Management API and Terraform provider. See the docs for details: * ConfigCat Public Management API: use the [Integrations](https://api.configcat.com/docs/index.html#tag/Integrations) endpoints. * ConfigCat Feature Flags Provider for Terraform: use the [configcat\_integration ](https://registry.terraform.io/providers/configcat/configcat/latest/docs/resources/integration)resource. *** ## New ConfigCat SDK for Unreal Engine[​](#new-configcat-sdk-for-unreal-engine "Direct link to New ConfigCat SDK for Unreal Engine") #### Jul 31, 2024[​](#jul-31-2024 "Direct link to Jul 31, 2024") We just released a new official ConfigCat SDK supporting Unreal Engine applications. ![ConfigCat SDK for Unreal Engine](/docs/assets/news/unreal.jpg) [See Documentation](https://configcat.com/docs/sdk-reference/unreal.md) *** ## New ConfigCat SDK for Rust[​](#new-configcat-sdk-for-rust "Direct link to New ConfigCat SDK for Rust") #### Jul 19, 2024[​](#jul-19-2024 "Direct link to Jul 19, 2024") We just released a new official ConfigCat SDK supporting Rust applications. [See Documentation](https://configcat.com/docs/sdk-reference/rust.md) *** ## Ability to connect multiple integrations[​](#ability-to-connect-multiple-integrations "Direct link to Ability to connect multiple integrations") #### Jun 27, 2024[​](#jun-27-2024 "Direct link to Jun 27, 2024") We're happy to share that we have added the ability to connect multiple [integrations](https://app.configcat.com/integrations) of the same type.
Moreover, it's now possible to apply environment/config filters on each individual integration. ![Multiple integrations menu](/docs/assets/news/multi_integ_1.png) ![Multiple integrations dialog](/docs/assets/news/multi_integ_2.png) *** ## Advanced feature flag analytics with Twilio Segment[​](#advanced-feature-flag-analytics-with-twilio-segment "Direct link to Advanced feature flag analytics with Twilio Segment") #### Jun 14, 2024[​](#jun-14-2024 "Direct link to Jun 14, 2024") We're happy to share that we have introduced a new way to track your feature flags in your analytics tools. From now on you can [send feature flag change events and](https://configcat.com/docs/integrations/segment.md#changeevents) and [send feature flag evaluation analytics](https://configcat.com/docs/integrations/segment.md#analytics) to Twilio Segment. *** ## Introducing the ConfigCat Feature Flags Tutorial[​](#introducing-the-configcat-feature-flags-tutorial "Direct link to Introducing the ConfigCat Feature Flags Tutorial") #### Jun 11, 2024[​](#jun-11-2024 "Direct link to Jun 11, 2024") We're excited to launch our [Feature Flags Tutorial](https://tutorial.configcat.com/?lm=13), a comprehensive guide designed to enhance your skills in feature management. This tutorial covers everything from basic toggling and simple targeting to advanced techniques like percentage rollouts and handling rollbacks. ![Feature Flags Tutorial](/docs/assets/news/tutorial_192dpi.png) ### Tutorial Highlights:[​](#tutorial-highlights "Direct link to Tutorial Highlights:") * Begin with toggling a feature flag on and off to see its immediate impact on a user interface, simulating real-world user scenarios. * Simple Targeting: Learn to apply basic targeting rules by enabling a feature for all users except those in a specific country. * Dogfooding: Practice internal testing by setting the feature to be visible only to users from your company. * Percentage Rollout: Advance to partial feature deployment by enabling a new feature for a percentage of your users, testing its acceptance incrementally. * Rollback: Master the ability to quickly revert changes for specific user groups when encountering issues during rollout. This step-by-step guide is ideal for anyone looking to integrate feature flags into their projects efficiently. [Explore the Tutorial](https://tutorial.configcat.com/?lm=14) *** ## Advanced feature flag analytics with Mixpanel, Amplitude and Google Analytics[​](#advanced-feature-flag-analytics-with-mixpanel-amplitude-and-google-analytics "Direct link to Advanced feature flag analytics with Mixpanel, Amplitude and Google Analytics") #### May 15, 2024[​](#may-15-2024 "Direct link to May 15, 2024") We're happy to share that we have introduced new ways to track your feature flags in your analytics tools. From now on you can: * [Monitor feature flag change events in Mixpanel with Annotations](https://configcat.com/docs/integrations/mixpanel/#annotations) * [Send feature flag evaluation analytics to Mixpanel Experiments](https://configcat.com/docs/integrations/mixpanel/#experiments) * [Send feature flag evaluation analytics to Amplitude Experiments](https://configcat.com/docs/integrations/amplitude/#experiments) * [Send feature flag evaluation analytics to Google Analytics](https://configcat.com/docs/integrations/google-analytics) *** ## Webhook and Product preference management in Public Management API and Terraform[​](#webhook-and-product-preference-management-in-public-management-api-and-terraform "Direct link to Webhook and Product preference management in Public Management API and Terraform") #### May 8, 2024[​](#may-8-2024 "Direct link to May 8, 2024") From now on, you can manage your Webhooks and Product preferences through the ConfigCat Public Management API and the Terraform provider. See the docs for details: * ConfigCat Public Management API: use the [Webhooks ](https://api.configcat.com/docs/index.html#tag/Webhooks), [Get Product Preferences](https://api.configcat.com/docs/index.html#tag/Products/operation/get-product-preferences) and [Update Product Preferences](https://api.configcat.com/docs/index.html#tag/Products/operation/update-product-preferences) endpoints. * ConfigCat Feature Flags Provider for Terraform: use the [configcat\_webhook ](https://registry.terraform.io/providers/configcat/configcat/latest/docs/resources/webhook)and [configcat\_product\_preferences](https://registry.terraform.io/providers/configcat/configcat/latest/docs/resources/product_preferences) resources. *** ## ConfigCat Proxy Released\![​](#configcat-proxy-released "Direct link to ConfigCat Proxy Released!") #### Apr 17, 2024[​](#apr-17-2024 "Direct link to Apr 17, 2024") We're happy to announce the official release of [ConfigCat Proxy](https://github.com/configcat/configcat-proxy). 🎉 ConfigCat Proxy allows you to host feature flag evaluation service in your own infrastructure.
The Proxy provides the following: 🚀 **Performance**: Faster evaluation for stateless or short-lived apps.
🦾 **Reliability**: Continuous operation, even if ConfigCat CDN is down.
🔐 **Security**: Protect config JSON files from exposure to frontend and mobile apps.
📈 **Scalability**: Easily handle varying application loads.
📡 **Streaming**: Real-time feature flag change notifications via SSE and gRPC.
Learn more about ConfigCat Proxy [here](https://configcat.com/docs/advanced/proxy/proxy-overview/). *** ## Introducing Config V2: More Powerful Feature Flagging\![​](#introducing-config-v2-more-powerful-feature-flagging "Direct link to Introducing Config V2: More Powerful Feature Flagging!") #### Apr 05, 2024[​](#apr-05-2024 "Direct link to Apr 05, 2024") We're thrilled to announce the upcoming launch of Config V2, the next generation of ConfigCat. This major update introduces a number of enhancements including a revamped Dashboard, Public Management API, updated SDKs, and a host of new features designed to streamline your feature flag and configuration management experience. ### What's New in Config V2?[​](#whats-new-in-config-v2 "Direct link to What's New in Config V2?") * A modernized config editor UI for an enhanced Dashboard experience. * Advanced targeting rules with AND conditions for more precise user targeting. * New comparators and prerequisite flags for complex rule creation. ### Gradual Release & Opt-in[​](#gradual-release--opt-in "Direct link to Gradual Release & Opt-in") Config V2 will be rolled out gradually over the next three months. Interested customers are encouraged to opt-in early by [contacting our support team](https://configcat.com/support/) ### Seamless Migration, No Immediate Changes Required[​](#seamless-migration-no-immediate-changes-required "Direct link to Seamless Migration, No Immediate Changes Required") Post-release, rest assured that your existing configurations will continue to function just as before. There's no immediate pressure to migrate, allowing you to transition to Config V2 when it suits you best. Here is a [detailed guide](https://configcat.com/docs/advanced/config-v2/) to know more about Config V2 and the new features. *** ## ConfigCat customer experience survey[​](#configcat-customer-experience-survey "Direct link to ConfigCat customer experience survey") #### Mar 22, 2024[​](#mar-22-2024 "Direct link to Mar 22, 2024") Please take a moment to share your experience with ConfigCat. Fill out [this survey](https://forms.gle/VepSDp3pF9FCVzAE9) and help us improve our product!
Thank you for your time! 🙏 *** ## Join the Config V2 Beta Program[​](#join-the-config-v2-beta-program "Direct link to Join the Config V2 Beta Program") #### Jan 19, 2024[​](#jan-19-2024 "Direct link to Jan 19, 2024") We're looking for ConfigCat users willing to participate in the beta testing of Config V2. ### What is Config V2?[​](#what-is-config-v2 "Direct link to What is Config V2?") Config V2 is a new version of ConfigCat. It brings together a bundle of highly requested features like AND conditions, new comparators (Text Equals, Text Starts with Any of, Text Ends with Any of, Before/After), Prerequisite flags, and more. [Read more about Config V2 and the new features.](https://configcat.com/docs/advanced/config-v2.md) You can get early access to the new features and shape the final product with your feedback. ### How to join the beta program?[​](#how-to-join-the-beta-program "Direct link to How to join the beta program?") 1. [Apply via this form](https://forms.gle/wEFxKYs5Lv5iiLUF8) 2. Join the **#config-v2-beta-testing** channel in our [Community Slack](https://configcat.com/slack/) to give feedback. *** ## Resource ordering in Public Management API and Terraform[​](#resource-ordering-in-public-management-api-and-terraform "Direct link to Resource ordering in Public Management API and Terraform") #### Jan 9, 2024[​](#jan-9-2024 "Direct link to Jan 9, 2024") From now on, you can change the order of your products, configs and environments trough the ConfigCat Public Management API and the Terraform provider. See the docs for details: * *ConfigCat Public Management API*: specify the order argument in the [Products](https://configcat.com/docs/api/reference/products.md), [Configs](https://configcat.com/docs/api/reference/configs.md), [Environment](https://configcat.com/docs/api/reference/environments.md) and [Feature Flags & Settings](https://configcat.com/docs/api/reference/feature-flags-settings.md) endpoints * *ConfigCat Feature Flags Provider for Terraform*: specify the order argument of the [configcat\_product](https://registry.terraform.io/providers/configcat/configcat/latest/docs/resources/product#argument-reference), [configcat\_config](https://registry.terraform.io/providers/configcat/configcat/latest/docs/resources/config#argument-reference), [configcat\_environment](https://registry.terraform.io/providers/configcat/configcat/latest/docs/resources/environment#argument-reference) and [configcat\_setting](https://registry.terraform.io/providers/configcat/configcat/latest/docs/resources/setting#argument-reference). *** ## ConfigCat OpenFeature Providers available[​](#configcat-openfeature-providers-available "Direct link to ConfigCat OpenFeature Providers available") #### Jan 5, 2024[​](#jan-5-2024 "Direct link to Jan 5, 2024") OpenFeature now supports ConfigCat via dedicated providers for their SDKs. So if you prefer using ConfigCat via the OpenFeature API, you can now do so with the following providers: * [ConfigCat OpenFeature Provider for Java](https://github.com/open-feature/java-sdk-contrib/tree/main/providers/configcat) * [ConfigCat OpenFeature Provider for Go](https://github.com/open-feature/go-sdk-contrib/tree/main/providers/configcat) * [ConfigCat OpenFeature Provider for JavaScript](https://github.com/open-feature/js-sdk-contrib/tree/main/libs/providers/config-cat) *** ## ConfigCat Proxy Beta[​](#configcat-proxy-beta "Direct link to ConfigCat Proxy Beta") #### Nov 17, 2023[​](#nov-17-2023 "Direct link to Nov 17, 2023") We're happy to share that the ConfigCat Proxy is now in the Beta phase and we need your help to make it even better! 📚 Want to learn more about the ConfigCat Proxy? Get all the details [here](https://configcat.com/docs/advanced/proxy/proxy-overview.md). 🔧 We'd like to invite you to participate in the beta testing. If you're interested, join the dedicated **#configcat-proxy-beta** channel in our [Slack Community](https://configcat.com/slack). Share your experiences, ask questions, and collaborate with our team and fellow community members. *** ## New cleartext comparators in Segments[​](#new-cleartext-comparators-in-segments "Direct link to New cleartext comparators in Segments") #### Oct 26, 2023[​](#oct-26-2023 "Direct link to Oct 26, 2023") ConfigCat now supports two new cleartext comparators: IS ONE OF and IS NOT ONE OF. ![New cleartext comparators](/docs/assets/images/isoneofcleartext-ac6dd72b09032cd397f39bccd1651c2f.png) These new comparators allow you to check if a given value is part of a list or not. This is in addition to the hashed confidential versions that were previously available. *** ## Unique tag names[​](#unique-tag-names "Direct link to Unique tag names") #### Oct 4, 2023[​](#oct-4-2023 "Direct link to Oct 4, 2023") Now, tag names within a product must be unique. This new feature ensures better organization and avoids any potential confusion with colliding tag names. *** ## Manage Permission Groups with Terraform[​](#manage-permission-groups-with-terraform "Direct link to Manage Permission Groups with Terraform") #### Aug 23, 2023[​](#aug-23-2023 "Direct link to Aug 23, 2023") Introducing Permission Group management in [**ConfigCat Feature Flags Provider for Terraform**](https://registry.terraform.io/providers/configcat/configcat/latest/docs)! Use the [**configcat\_permission\_group**](https://registry.terraform.io/providers/configcat/configcat/latest/docs/resources/permission_group) resource for control and the [**configcat\_permission\_groups**](https://registry.terraform.io/providers/configcat/configcat/latest/docs/data-sources/permission_groups) data source for access to existing Permission Groups. *** ## Some updates regarding SLA guaranteed Uptime[​](#some-updates-regarding-sla-guaranteed-uptime "Direct link to Some updates regarding SLA guaranteed Uptime") #### Aug 15, 2023[​](#aug-15-2023 "Direct link to Aug 15, 2023") We're excited to announce important updates to our Service Level Agreement (SLA) concerning uptime commitments. We're increasing our uptime commitment for the following plans: | Uptime Changes | Previous | Current | | --------------- | -------- | --------------- | | Free Plan | 99% | 99% (No Change) | | Pro Plan | 99.8% | 99.9% | | Smart Plan | 99.9% | 99.95% | | Enterprise Plan | 99.9% | 99.99% | | Dedicated Plan | 99.9% | 99.99% | By enhancing our SLA terms, we aim to provide a more consistent and trustworthy service that you can depend on, day in and day out. *** ## Old SDKs will stop working after October 1st, 2023[​](#old-sdks-will-stop-working-after-october-1st-2023 "Direct link to Old SDKs will stop working after October 1st, 2023") #### Aug 10, 2023[​](#aug-10-2023 "Direct link to Aug 10, 2023") All ConfigCat SDKs released before Feb, 2020 will stop working after October 1st, 2023. Please, upgrade all your SDKs to the latest. Although we aim to keep older SDK versions functional, those trailing more than one major or minor release lack official support and SLA. Many of these outdated SDKs will no longer remain functional. ### Affected SDKs and versions[​](#affected-sdks-and-versions "Direct link to Affected SDKs and versions") | SDK Type | Latest available version | Will stop working | | -------- | ------------------------ | ----------------- | | Python | v8.0.0 | < v3.0.2 | | Ruby | v7.0.0 | < v2.0.3 | | .NET | v8.2.0 | < v4.0.0 | | Go | v8.0.0 | < v4.0.0 | | Java | v8.2.2 | < v4.0.0 | | Android | v9.0.1 | < v4.0.0 | | JS | v8.1.0 | < v3.0.0 | | JS-SSR | v7.1.0 | < v1.0.2 | | Node | v10.1.0 | < v4.0.0 | | PHP | v7.1.1 | < v3.0.2 | | Swift | v9.4.0 | < v4.0.0 | *** ## Introducing Network Traffic limits for all plans[​](#introducing-network-traffic-limits-for-all-plans "Direct link to Introducing Network Traffic limits for all plans") #### Aug 1, 2023[​](#aug-1-2023 "Direct link to Aug 1, 2023") We are introducing [**Network Traffic**](https://configcat.com/docs/network-traffic.md) limits for all plans. The usage is based on the Network Traffic your applications are making to the ConfigCat CDN. ### Why are we introducing these limits?[​](#why-are-we-introducing-these-limits "Direct link to Why are we introducing these limits?") Our cloud provider charges us for the Network Traffic we use to serve your feature flags. By introducing these limits, we can cover these costs and continue providing the service. Instead of raising prices for all users in general, we decided to specifically reflect the network-related operation costs in our current pricing plans. ### What are the limits?[​](#what-are-the-limits "Direct link to What are the limits?") | Free | Pro | Smart | Enterprise | | ---------- | ----------- | --------- | ---------- | | 20 GB / mo | 100 GB / mo | 1 TB / mo | 4 TB / mo | ### What to expect?[​](#what-to-expect "Direct link to What to expect?") 94% of our users will not be affected by these limits. If you are in the 6% that exceeds the limit, we will reach out to you directly to assist in the next 3 months in finding the best solution for your specific use case. Rest assured that even if you exceed the limit, your feature flags will continue to work seamlessly. If you have any further questions or need assistance, please don't hesitate to [**reach out to us**](https://configcat.com/support). We're here to help! *** ## Introducing "Test with User"[​](#introducing-test-with-user "Direct link to Introducing \"Test with User\"") #### Jul 26, 2023[​](#jul-26-2023 "Direct link to Jul 26, 2023") We're pleased to announce the arrival of "Test with User" for feature flags! With "Test with User," you can now test your feature flags before deploying them to production. Wondering how your flags will perform for specific users? This feature allows you to see the evaluation results based on a given User Object. *** ## Chromium Extension SDK (Beta)[​](#chromium-extension-sdk-beta "Direct link to Chromium Extension SDK (Beta)") #### Dec 3, 2022[​](#dec-3-2022 "Direct link to Dec 3, 2022") A new JS SDK for Chromium Extensions supporting the [Manifest V3](https://developer.chrome.com/docs/extensions/mv3/intro/) API is now on public beta and available via [npm](https://www.npmjs.com/package/configcat-js-chromium-extension). [Open on GitHub](https://github.com/configcat/js-chromium-extension-sdk) *** ## New ConfigCat SDK for C++[​](#new-configcat-sdk-for-c "Direct link to New ConfigCat SDK for C++") #### Oct 7, 2022[​](#oct-7-2022 "Direct link to Oct 7, 2022") We just released a new official ConfigCat SDK supporting C++ applications. [See Documentation](https://configcat.com/docs/sdk-reference/cpp.md) *** ## New ConfigCat SDK for React[​](#new-configcat-sdk-for-react "Direct link to New ConfigCat SDK for React") #### Sept 6, 2022[​](#sept-6-2022 "Direct link to Sept 6, 2022") We just released a new official ConfigCat SDK supporting React applications. [See Documentation](https://configcat.com/docs/sdk-reference/react.md) *** ## monday.com integration[​](#mondaycom-integration "Direct link to monday.com integration") #### Jul 18, 2022[​](#jul-18-2022 "Direct link to Jul 18, 2022") Turn your features On / Off right from a monday.com item. [ConfigCat Feature Flags monday.com app](https://monday.com/marketplace/10000079) *** ## ISO/IEC 27001:2013 certification[​](#isoiec-270012013-certification "Direct link to ISO/IEC 27001:2013 certification") #### Jun 27, 2022[​](#jun-27-2022 "Direct link to Jun 27, 2022") We're happy to announce that ConfigCat has achieved the ISO/IEC 27001:2013 certification for Information Security Management Systems (ISMS). [Read more and download the certificates here](https://configcat.com/iso/) *** ## Reordering feature flags and other entities[​](#reordering-feature-flags-and-other-entities "Direct link to Reordering feature flags and other entities") #### Mar 22, 2022[​](#mar-22-2022 "Direct link to Mar 22, 2022") Click the Reorder icon on any overview to change the ordering of your feature flags, environments, configs or products. *** ## Copy feature flag values between environments[​](#copy-feature-flag-values-between-environments "Direct link to Copy feature flag values between environments") #### Feb 23, 2022[​](#feb-23-2022 "Direct link to Feb 23, 2022") You can copy feature flag values (including segment, targeting, percentage rules) from one environment to another. *** ## Segments are here[​](#segments-are-here "Direct link to Segments are here") #### Feb 15, 2022[​](#feb-15-2022 "Direct link to Feb 15, 2022") Segments let you group your users based on any of their properties (e.g: Beta Testers). You can target the same segment with multiple feature flags. [Go to segments on our Dashboard](https://app.configcat.com/product/segments) *** ## TV Mode[​](#tv-mode "Direct link to TV Mode") #### Dec 15, 2021[​](#dec-15-2021 "Direct link to Dec 15, 2021") Display your feature flags on the TVs around the office! [Config overview on our Dashboard](https://app.configcat.com/overview) *** ## Config Overview[​](#config-overview "Direct link to Config Overview") #### Nov 17, 2021[​](#nov-17-2021 "Direct link to Nov 17, 2021") Introducing a new overview to track your feature flag values in all your environments side-by-side. Open the environment menu to access the overview. [Open config overview on our Dashboard](https://app.configcat.com/overview) *** ## "Which projects are using this flag?"[​](#which-projects-are-using-this-flag "Direct link to \"Which projects are using this flag?\"") #### Nov 2, 2021[​](#nov-2-2021 "Direct link to Nov 2, 2021") ConfigCat: "Say no more fam! Let me show you!" [See the documentation for details](https://configcat.com/docs/advanced/code-references/overview.md) *** ## Searching feature flags instead of Ctrl+F[​](#searching-feature-flags-instead-of-ctrlf "Direct link to Searching feature flags instead of Ctrl+F") #### Oct 5, 2021[​](#oct-5-2021 "Direct link to Oct 5, 2021") Added a search bar to the feature flags page. We recommend using it instead of Ctr+F and Cmd+F since the page is lazy loaded. So it might not yield results from parts of the page that are not currently rendered. *** ## Environment colors are finally here[​](#environment-colors-are-finally-here "Direct link to Environment colors are finally here") #### Sep 24, 2021[​](#sep-24-2021 "Direct link to Sep 24, 2021") Just updated the UX on the product overview page and added a few small features. * You can choose from a number of colors for your environments. * Also adding descriptions helps teammates to find their way around environments and configs. [Set your colors and add descriptions on the product overview page on our Dashboard](https://app.configcat.com/product) *** ## Send less invitations using SAML SSO, Auto-assign users and product join requests[​](#send-less-invitations-using-saml-sso-auto-assign-users-and-product-join-requests "Direct link to Send less invitations using SAML SSO, Auto-assign users and product join requests") #### Sep 23, 2021[​](#sep-23-2021 "Direct link to Sep 23, 2021") To make organization level user management more convenient we added a bunch of new features: * Added an [organization overview on our Dashboard page](https://app.configcat.com/) to see products more clearly. * Team members can send join requests to admins if they want to join a product. * Whenever someone signs up to ConfigCat using a verified email domain, they could be automatically assigned to products. * SAML Single Sign-On supporting all of the major identity providers. * Improved layout for admins to [manage organization members](https://app.configcat.com/organization/members) on our Dashboard page. *Only team members with Organization Admin role can access these features.* [Set up user provisioning and SAML Single Sign-On on our Dashboard](https://app.configcat.com/organization/authentication) *** ## New Organization Admin functionalities[​](#new-organization-admin-functionalities "Direct link to New Organization Admin functionalities") #### Aug 13, 2021[​](#aug-13-2021 "Direct link to Aug 13, 2021") * Organization Admins can remove a member from the whole organization. * Organization Admins can modify a member's permissions globally. *Only team members with Organization Admin role can access these features.* [Open Organization Members & Roles page on our Dashboard](https://app.configcat.com/organization/members) *** ## Disable Two-factor authentication[​](#disable-two-factor-authentication "Direct link to Disable Two-factor authentication") #### Aug 4, 2021[​](#aug-4-2021 "Direct link to Aug 4, 2021") Disable Two-factor authentication for your team members. This feature is useful if somebody lost the device used for Two-factor authentication. *Only team members with Organization Admin role can disable Two-factor authentication.* [Open Organization Members & Roles page on our Dashboard](https://app.configcat.com/organization/members) *** ## Export / Import[​](#export--import "Direct link to Export / Import") #### Jul 28, 2021[​](#jul-28-2021 "Direct link to Jul 28, 2021") Export (download), and import (upload) Configs, Environments, and Feature Flags from, and to file. [Open Export / Import page on our Dashboard](https://app.configcat.com/product/exportimport) *** ## Dashboard v3 released[​](#dashboard-v3-released "Direct link to Dashboard v3 released") #### Jun 30, 2021[​](#jun-30-2021 "Direct link to Jun 30, 2021") Hope you like it. Tell us your opinion over [Slack](https://configcat.com/slack) or [Email](mailto:team@configcat.com). *** ## Help us grow[​](#help-us-grow "Direct link to Help us grow") #### Jun 10, 2021[​](#jun-10-2021 "Direct link to Jun 10, 2021") If you like ConfigCat, you can help us grow by leaving a review. Plus Capterra is giving **20€ as a reward** to the first 100 reviewers. Any of the following works: * [TrustRadius](https://www.trustradius.com/welcome/configcat) * [Trust Pilot](https://www.trustpilot.com/evaluate/configcat.com) * [G2 Crowd](https://www.g2.com/products/configcat/reviews/start) * [Capterra](https://reviews.capterra.com/new/187099) (**20€ reward**) * [Alternative.me](https://alternative.me/configcat) * [AlternativeTo](https://alternativeto.net/software/configcat/reviews) *** ## Visual Studio Code Extension[​](#visual-studio-code-extension "Direct link to Visual Studio Code Extension") #### May 06, 2021[​](#may-06-2021 "Direct link to May 06, 2021") Turn your features On / Off and manage your Feature Flags from Visual Studio Code. * [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=ConfigCat.configcat-feature-flags) *** ## Detailed Permission Group system[​](#detailed-permission-group-system "Direct link to Detailed Permission Group system") #### Mar 10, 2021[​](#mar-10-2021 "Direct link to Mar 10, 2021") Permission Groups can be customized in more advanced levels: * Resource-based permissions (Configs, Environments, Tags, Webhooks) * Create/Update and Delete permissions are separated * Team member management permission * Product preferences permission * Product Audit Log/Statistics permission * Integration management permission * SDK Key View/Rotate permissions * [Fine-tune Permission Groups on our Dashboard](https://app.configcat.com/product/permission-groups) *** ## Zombie Flags (Stale Flags) Report via email[​](#zombie-flags-stale-flags-report-via-email "Direct link to Zombie Flags (Stale Flags) Report via email") #### Mar 4, 2021[​](#mar-4-2021 "Direct link to Mar 4, 2021") Feature flags have a tendency to multiply rapidly. In order to keep the tech-debt low, we recommend removing the flags no longer needed. You can now set up a regular email report with a list of these zombie or stale flags. * [Set up the Zombie Flags Report on our Dashboard](https://app.configcat.com/zombie-flags-report) *** ## Invoice download[​](#invoice-download "Direct link to Invoice download") #### Feb 8, 2021[​](#feb-8-2021 "Direct link to Feb 8, 2021") You can download all your current and previous invoices from the Billing & Invoices page. * [Open Billing & Invoices on our Dashboard](https://app.configcat.com/organization/billing) *** ## Accepting USD payments[​](#accepting-usd-payments "Direct link to Accepting USD payments") #### Nov 26, 2020[​](#nov-26-2020 "Direct link to Nov 26, 2020") We are accepting payments in USD from now on. * [See plans on our Dashboard](https://app.configcat.com/organization/plans) *** ## ConfigCat & Zoho Flow[​](#configcat--zoho-flow "Direct link to ConfigCat & Zoho Flow") #### Nov 21, 2020[​](#nov-21-2020 "Direct link to Nov 21, 2020") ConfigCat's Zoho Flow integration is now available. * [Detailed Docs and Setup Guide](https://configcat.com/docs/integrations/zoho-flow.md) *** ## Default Permission Group[​](#default-permission-group "Direct link to Default Permission Group") #### Nov 13, 2020[​](#nov-13-2020 "Direct link to Nov 13, 2020") Set a default Permission Group for Team member invites. The chosen group will be the default on the permission group list when inviting others. So you can be sure not to invite someone as an admin by accident. *** ## Amplitude integration[​](#amplitude-integration "Direct link to Amplitude integration") #### Oct 28, 2020[​](#oct-28-2020 "Direct link to Oct 28, 2020") Annotate your setting changes on your Amplitude charts. * [Docs and Setup Guide](https://configcat.com/docs/integrations/amplitude.md) *** ## ConfigCat Feature Flags Provider for Terraform[​](#configcat-feature-flags-provider-for-terraform "Direct link to ConfigCat Feature Flags Provider for Terraform") #### Oct 16, 2020[​](#oct-16-2020 "Direct link to Oct 16, 2020") Configure and access ConfigCat resources via Terraform. * [ConfigCat Feature Flags Provider for Terraform](https://registry.terraform.io/providers/configcat/configcat/latest/docs) *** ## Data Governance - Action required[​](#data-governance---action-required "Direct link to Data Governance - Action required") #### Oct 10, 2020[​](#oct-10-2020 "Direct link to Oct 10, 2020") Addressing global data handling and processing trends, we have introduced the Data Governance feature in ConfigCat. We require all our customers to make a statement if they want to use our: * **Global CDN**: providing geo-location based load balancing on server nodes all around the globe to ensure low response times. * **EU CDN**: Staying compliant with GDPR by using ConfigCat EU CDN. This way your data will never leave the EU. * [Read more on Data Governance and CDN](https://configcat.com/docs/advanced/data-governance.md) *** ## Organization Management[​](#organization-management "Direct link to Organization Management") #### Sep 07, 2020[​](#sep-07-2020 "Direct link to Sep 07, 2020") Featuring: * **Organization Admin** and **Billing Manager** roles. * General **security** preferences for the entire organization. * Customizable **SSO** methods. * Organization level **audit logs** and usage **statistics**. * [See Docs](https://configcat.com/docs/organization.md) *** ## Public Management API v1 released[​](#public-management-api-v1-released "Direct link to Public Management API v1 released") #### Jul 08, 2020[​](#jul-08-2020 "Direct link to Jul 08, 2020") You can programmatically **CREATE**, **UPDATE**, **DELETE** Feature Flags, Configs, Products and Environments from now on! * [See Docs and examples](https://configcat.com/docs/api/reference/configcat-public-management-api.md) *** ## Tags & Filtering[​](#tags--filtering "Direct link to Tags & Filtering") #### May 29, 2020[​](#may-29-2020 "Direct link to May 29, 2020") Add colored tags to your feature flags. *** ## Jira Cloud Plugin[​](#jira-cloud-plugin "Direct link to Jira Cloud Plugin") #### May 28, 2020[​](#may-28-2020 "Direct link to May 28, 2020") Turn your features On / Off right from a Jira Issue. * [ConfigCat Jira Cloud Plugin](https://marketplace.atlassian.com/apps/1222421/configcat-feature-flags?hosting=cloud\&tab=overview) *** ## Slack App[​](#slack-app "Direct link to Slack App") #### April 12, 2020[​](#april-12-2020 "Direct link to April 12, 2020") Get updated via a Slack Channel message when someone changes a feature flag. * [ConfigCat Feature Flags in Slack App Directory](https://configcat.slack.com/apps/A011CN2QZJB-configcat-feature-flags) *** ## API Key --> SDK Key[​](#api-key----sdk-key "Direct link to API Key --> SDK Key") #### April 7, 2020[​](#april-7-2020 "Direct link to April 7, 2020") Renamed API Key to SDK Key since it was more confusing as the Public Management API went to production. The API and the API Key are not related. This is a breaking change in some of the SDKs, released under new major versions. *** ## New JavaScript SDK for SSR[​](#new-javascript-sdk-for-ssr "Direct link to New JavaScript SDK for SSR") #### April 3, 2020[​](#april-3-2020 "Direct link to April 3, 2020") New JavaScript SDK supporting Server Side Rendered (SSR) frameworks like [NuxtJS](https://nuxtjs.org). * [See Documentation](https://configcat.com/docs/sdk-reference/js-ssr.md) *** ## Trello Power-Up[​](#trello-power-up "Direct link to Trello Power-Up") #### March 30, 2020[​](#march-30-2020 "Direct link to March 30, 2020") Turn your features On / Off right from a Trello Card. * [ConfigCat Power-Up](https://trello.com/power-ups/5e694b66d2511a3601ebd0fb) *** ## Integrations[​](#integrations "Direct link to Integrations") #### March 21, 2020[​](#march-21-2020 "Direct link to March 21, 2020") Connect the apps you use everyday and be more productive. Check out the [Integrations tab](https://app.configcat.com/product/integrations) in our Dashboard. *** ## View SDK Key permission[​](#view-sdk-key-permission "Direct link to View SDK Key permission") #### March 21, 2020[​](#march-21-2020-1 "Direct link to March 21, 2020") Visibility of information that is normally useful for developers only - like SDK Keys and code examples - can be set for [Permission Groups](https://app.configcat.com/product/permission-groups) on our Dashboard. *** ## Audit log improvements[​](#audit-log-improvements "Direct link to Audit log improvements") #### March 20, 2020[​](#march-20-2020 "Direct link to March 20, 2020") User friendly Feature Flag or Setting value changes in the [Audit log on our Dashboard](https://app.configcat.com/auditlog) to improve readability. *** ## Long text improvements[​](#long-text-improvements "Direct link to Long text improvements") #### March 20, 2020[​](#march-20-2020-1 "Direct link to March 20, 2020") Feature Flag or Setting text values and Targeting comparison values can be viewed and updated in a `textarea`. *** ## Upper case key generation mode[​](#upper-case-key-generation-mode "Direct link to Upper case key generation mode") #### March 17, 2020[​](#march-17-2020 "Direct link to March 17, 2020") Besides "camelCase" and "lower\_case" we have added an "UPPER\_CASE" key generation mode to preferences. * [Open Preferences on in our Dashboard](https://app.configcat.com/product/preferences) *** ## Statistics[​](#statistics "Direct link to Statistics") #### March 15, 2020[​](#march-15-2020 "Direct link to March 15, 2020") See detailed statistics about the number of config.json downloads made towards ConfigCat CDN. Also a pie-chart of the SDK types and versions being used. * [Open Stats on our Dashboard](https://app.configcat.com/product/statistics) *** ## ConfigCat Zap[​](#configcat-zap "Direct link to ConfigCat Zap") #### March 12, 2020[​](#march-12-2020 "Direct link to March 12, 2020") Zapier integration is now accessible. * [Detailed Docs and Setup Guide](https://configcat.com/docs/integrations/zapier.md) *** ## Public Management API (Beta)[​](#public-management-api-beta "Direct link to Public Management API (Beta)") #### March 11, 2020[​](#march-11-2020 "Direct link to March 11, 2020") Released Public Management API to Beta. From now on you can execute Dashboard management operations programmatically. * [API Documentation](https://configcat.com/docs/api/reference/configcat-public-management-api.md) *** ## Sensitive text comparators[​](#sensitive-text-comparators "Direct link to Sensitive text comparators") #### March 3, 2020[​](#march-3-2020 "Direct link to March 3, 2020") Introduced sensitive text comparators to make sure sensitive info (like email address, user name) is kept hidden in Targeting Rules. Comes handy in front-end applications. * [Detailed Docs about comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#comparator) * [Related blog post](https://configcat.com/blog/2020/03/02/sensitive-comparators/) *** ## Semantic version based user targeting[​](#semantic-version-based-user-targeting "Direct link to Semantic version based user targeting") #### March 3, 2020[​](#march-3-2020-1 "Direct link to March 3, 2020") Especially useful for Mobile developers. * [Detailed Docs about comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#comparator) * [Related blog post](https://configcat.com/blog/2020/01/27/semver) *** ## Ruby SDK[​](#ruby-sdk "Direct link to Ruby SDK") #### Oct 29, 2019[​](#oct-29-2019 "Direct link to Oct 29, 2019") It is out! * [Ruby SDK Docs](https://configcat.com/docs/sdk-reference/ruby.md) * [GitHub repo](https://github.com/configcat/ruby-sdk) * [Blog post](https://configcat.com/blog/2019/10/29/ruby-sdk/) *** --- # Source: https://configcat.com/docs/sdk-reference/openfeature/node.md # Source: https://configcat.com/docs/sdk-reference/node.md # Source: https://configcat.com/docs/sdk-reference/js/node.md # Node.js SDK Copy page [![Star on GitHub](https://img.shields.io/github/stars/configcat/js-unified-sdk.svg?style=social)](https://github.com/configcat/js-unified-sdk/stargazers) [![JS SDK CI](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml/badge.svg?branch=master)](https://github.com/configcat/js-unified-sdk/actions/workflows/js-sdk-ci.yml) [![SonarCloud Coverage](https://img.shields.io/sonar/coverage/configcat_js-unified-sdk?logo=SonarCloud\&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=configcat_js-unified-sdk) [![Known Vulnerabilities](https://snyk.io/test/github/configcat/js-unified-sdk/badge.svg?targetFile=package.json)](https://snyk.io/test/github/configcat/js-unified-sdk?targetFile=package.json) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=configcat_js-sdk\&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=configcat_js-sdk) [![JSDELIVR](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge)](https://data.jsdelivr.com/v1/package/npm/@configcat/sdk/badge) info This SDK supersedes the legacy [Node.js SDK](https://configcat.com/docs/sdk-reference/js.md). [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install and import package[​](#1-install-and-import-package "Direct link to 1. Install and import package") First install the [NPM package](https://npmjs.com/package/@configcat/sdk): ```bash npm i @configcat/sdk ``` Then import it into your application: ```js const configcat = require("@configcat/sdk/node"); ``` or ```js import * as configcat from "@configcat/sdk/node"; ``` info For subpath imports to work **in TypeScript** when using [ts-node](https://www.npmjs.com/package/ts-node), you must set the [moduleResolution](https://www.typescriptlang.org/tsconfig/#moduleResolution) option to `node16` or `nodenext` in your `tsconfig.json`. For TypeScript versions older than 4.7, where these options are not available, you need to fall back to module resolution `node` and importing from the main entry point `@configcat/sdk`. ### 2. Create the *ConfigCat* client with your SDK Key[​](#2-create-the-configcat-client-with-your-sdk-key "Direct link to 2-create-the-configcat-client-with-your-sdk-key") ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); ``` ### 3. Get your setting value[​](#3-get-your-setting-value "Direct link to 3. Get your setting value") The async/await way: ```js const value = await configCatClient.getValueAsync( 'isMyAwesomeFeatureEnabled', false, ); if (value) { do_the_new_thing(); } else { do_the_old_thing(); } ``` info Please note that [top-level await in modules](https://exploringjs.com/js/book/ch_modules.html#top-level-await) is available only if your project is [set up to use the ECMAScript module system](https://nodejs.org/api/esm.html). Otherwise you will need to use Promises or wrap your code in an async function as shown [here](https://github.com/configcat/js-unified-sdk/blob/master/samples/node-console/index.js). The Promise way: ```js configCatClient .getValueAsync('isMyAwesomeFeatureEnabled', false) .then((value) => { if (value) { do_the_new_thing(); } else { do_the_old_thing(); } }); ``` The *ConfigCat SDK* also offers a synchronous API for feature flag evaluation. Read more [here](#snapshots-and-synchronous-feature-flag-evaluation). ### 4. Dispose the *ConfigCat* client[​](#4-dispose-the-configcat-client "Direct link to 4-dispose-the-configcat-client") You can safely dispose all clients at once or individually and release all associated resources on application exit. ```js configcat.disposeAllClients(); // disposes all clients // -or- configCatClient.dispose(); // disposes a specific client ``` ## Creating the *ConfigCat* Client[​](#creating-the-configcat-client "Direct link to creating-the-configcat-client") *ConfigCat Client* is responsible for: * managing the communication between your application and ConfigCat servers. * caching your setting values and feature flags. * serving values quickly in a failsafe way. `configcat.getClient('')` returns a client with default options. The `getClient` function has optional parameters, which can be used to adjust the behavior of the client. | Parameters | Description | Default | | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | | `sdkKey` | **REQUIRED.** SDK Key to access your feature flags and settings. Get it from *ConfigCat Dashboard*. | - | | `pollingMode` | Optional. The polling mode to use to fetch the config data from the ConfigCat CDN. [More about polling modes](#polling-modes). | `PollingMode.AutoPoll` | | `options` | Optional. The options object. See the table below. | - | The available options depends on the chosen polling mode. However, there are some common options which can be set in the case of every polling mode: | Option Parameter | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `configFetcher` | Custom [`IConfigCatConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigFetcher.ts) instance for downloading a config. | [`NodeHttpConfigFetcher`](https://github.com/configcat/js-unified-sdk/blob/master/src/node/NodeHttpConfigFetcher.ts) | | `cache` | Custom [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) implementation for caching the downloaded config. | [`InMemoryConfigCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) | | `logger` | Custom [`IConfigCatLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) implementation for tracing. | [`ConfigCatConsoleLogger`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatLogger.ts) (with WARN level) | | `logFilter` | Sets a custom log filter. [More about log filtering](#log-filtering). | `undefined` (none) | | `baseUrl` | Sets the CDN base url (forward proxy, dedicated subscription) from where the SDK will download the config JSON. | | | `httpAgent` | The [`http.Agent`](https://nodejs.org/api/http.html#class-httpagent) instance to use for non-secure HTTP communication. Can be used to route `http://...` requests made by the SDK through an HTTP, HTTPS or SOCKS proxy (see also [this section](#using-configcat-behind-a-proxy)). | | | `httpsAgent` | The [`https.Agent`](https://nodejs.org/api/https.html#class-httpsagent) instance to use for secure HTTP communication. Can be used to route `https://...` requests made by the SDK through an HTTP, HTTPS or SOCKS proxy (see also [this section](#using-configcat-behind-a-proxy)). | | | `requestTimeoutMs` | The amount of milliseconds the SDK waits for a response from the ConfigCat servers before returning values from the cache. | 30000 | | `flagOverrides` | Local feature flag & setting overrides. [More about feature flag overrides](#flag-overrides). | | | `dataGovernance` | Describes the location of your feature flag and setting data within the ConfigCat CDN. This parameter needs to be in sync with your Data Governance preferences. [More about Data Governance](https://configcat.com/docs/advanced/data-governance.md). Available options: `DataGovernance.Global`, `DataGovernance.EuOnly`. | `DataGovernance.Global` | | `defaultUser` | Sets the default user. [More about default user](#default-user). | `undefined` (none) | | `offline` | Determines whether the client should be initialized to offline mode. [More about offline mode](#online--offline-mode). | `false` | Options also include a property named `setupHook`, which you can use to subscribe to the hooks (events) at the time of initialization. [More about hooks](#hooks). For example: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { setupHooks: (hooks) => hooks.on('clientReady', function() { const keys = this.configCatClient.snapshot().getAllKeys(); console.log(`Client is ready! Number of available feature flags: ${keys.length}`); }), }, ); ``` info You can acquire singleton client instances for your SDK keys using the `configcat.getClient(sdkKey: "")` factory function. (However, please keep in mind that subsequent calls to `getClient()` with the *same SDK Key* return a *shared* client instance, which was set up by the first call.) You can close all open clients at once using the `configcat.disposeAllClients()` function or do it individually using the `configCatClient.dispose()` method. ## Anatomy of `getValueAsync()`[​](#anatomy-of-getvalueasync "Direct link to anatomy-of-getvalueasync") Returns a Promise with the value. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((value) => { console.log(value); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to the following table for the corresponding types. ### Setting type mapping[​](#setting-type-mapping "Direct link to Setting type mapping") | Setting Kind | `typeof defaultValue` | | -------------- | --------------------- | | On/Off Toggle | `boolean` | | Text | `string` | | Whole Number | `number` | | Decimal Number | `number` | In addition to the types mentioned above, you also have the option to provide `null` or `undefined` for the `defaultValue` parameter regardless of the setting kind. However, if you do so, the return type of the `getValue` method will be * `boolean | string | number | null` when `defaultValue` is `null` or * `boolean | string | number | undefined` when `defaultValue` is `undefined`. This is because in these cases the exact return type cannot be determined at compile-time as the TypeScript compiler has no information about the setting type. It's important to note that providing any other type for the `defaultValue` parameter will result in a `TypeError`. If you specify an allowed type but it mismatches the setting kind, an error message will be logged and `defaultValue` will be returned. ## Anatomy of `getValueDetailsAsync()`[​](#anatomy-of-getvaluedetailsasync "Direct link to anatomy-of-getvaluedetailsasync") `getValueDetailsAsync()` is similar to `getValueAsync()` but instead of returning the evaluated value only, it provides more detailed information about the evaluation result. | Parameters | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | **REQUIRED.** The key of a specific setting or feature flag. Set on *ConfigCat Dashboard* for each setting. | | `defaultValue` | **REQUIRED.** This value will be returned in case of an error. | | `user` | Optional, *User Object*. Essential when using Targeting. [Read more about Targeting.](https://configcat.com/docs/targeting/targeting-overview.md) | ```js const details = await configCatClient.getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ); ``` or ```js configCatClient .getValueDetailsAsync( 'keyOfMyFeatureFlag', // Setting Key false, // Default value { identifier: '#UNIQUE-USER-IDENTIFIER#' }, // Optional User Object ) .then((details) => { console.log(details); }); ``` caution It is important to provide an argument for the `defaultValue` parameter that matches the type of the feature flag or setting you are evaluating. Please refer to [this table](#setting-type-mapping) for the corresponding types. The `details` result contains the following information: | Field | Type | Description | | ------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `key` | `string` | The key of the evaluated feature flag or setting. | | `value` | `boolean` / `string` / `number` | The evaluated value of the feature flag or setting. | | `user` | `User` | The User Object used for the evaluation. | | `isDefaultValue` | `boolean` | True when the default value passed to `getValueDetailsAsync()` is returned due to an error. | | `errorCode` | `EvaluationErrorCode` | In case of an error, this property contains a code that identifies the reason for the error. | | `errorMessage` | `string` | In case of an error, this property contains the error message. | | `errorException` | `any` | In case of an error, this property contains the related exception object (if any). | | `matchedTargetingRule` | `TargetingRule` | The Targeting Rule (if any) that matched during the evaluation and was used to return the evaluated value. | | `matchedPercentageOption` | `PercentageOption` | The Percentage Option (if any) that was used to select the evaluated value. | | `fetchTime` | `Date` | The last download time (UTC) of the current config. | ## User Object[​](#user-object "Direct link to User Object") The [User Object](https://configcat.com/docs/targeting/user-object.md) is essential if you'd like to use ConfigCat's [Targeting](https://configcat.com/docs/targeting/targeting-overview.md) feature. For simple targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; ``` ```js const userObject = { identifier: 'john@example.com' }; ``` | Parameters | Description | | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `identifier` | **REQUIRED.** Unique identifier of a user in your application. Can be any `string` value, even an email address. | | `email` | Optional parameter for easier Targeting Rule definitions. | | `country` | Optional parameter for easier Targeting Rule definitions. | | `custom` | Optional dictionary for custom attributes of a user for advanced Targeting Rule definitions. E.g. User role, Subscription type. | For advanced targeting: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#', email: 'john@example.com', country: 'United Kingdom', custom: { SubscriptionType: 'Pro', UserRole: 'Admin', }, }; ``` The `custom` dictionary also allows attribute values other than `string` values: ```js const userObject = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; userObject.custom = { Rating: 4.5, RegisteredAt: new Date('2023-11-22T12:34:56.000Z'), Roles: ['Role1', 'Role2'], }; ``` ### User Object Attribute Types[​](#user-object-attribute-types "Direct link to User Object Attribute Types") All comparators support `string` values as User Object attribute (in some cases they need to be provided in a specific format though, see below), but some of them also support other types of values. It depends on the comparator how the values will be handled. The following rules apply: **Text-based comparators** (EQUALS, IS ONE OF, etc.) * accept `string` values, * all other values are automatically converted to `string` (a warning will be logged but evaluation will continue as normal). **SemVer-based comparators** (IS ONE OF, <, >=, etc.) * accept `string` values containing a properly formatted, valid semver value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Number-based comparators** (=, <, >=, etc.) * accept `number` values, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **Date time-based comparators** (BEFORE / AFTER) * accept `Date` values, which are automatically converted to a second-based Unix timestamp, * accept `number` values representing a second-based Unix timestamp, * accept `string` values containing a properly formatted, valid `number` value, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). **String array-based comparators** (ARRAY CONTAINS ANY OF / ARRAY NOT CONTAINS ANY OF) * accept arrays of `string`, * accept `string` values containing a valid JSON string which can be deserialized to an array of `string`, * all other values are considered invalid (a warning will be logged and the currently evaluated Targeting Rule will be skipped). ### Default user[​](#default-user "Direct link to Default user") It's possible to set a default User Object that will be used on feature flag and setting evaluation. It can be useful when your application has a single user only or rarely switches users. You can set the default User Object either on SDK initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { defaultUser: { identifier: 'john@example.com' }, }, ); ``` ...or using the `setDefaultUser()` method of the `configCatClient` object: ```js configCatClient.setDefaultUser({ identifier: 'john@example.com' }); ``` Whenever the evaluation methods like `getValueAsync()`, `getValueDetailsAsync()`, etc. are called without an explicit `user` parameter, the SDK will automatically use the default user as a User Object. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); // The default user will be used in the evaluation process. const value = await configCatClient.getValueAsync('keyOfMyFeatureFlag', false); ``` When a `user` parameter is passed to the evaluation methods, it takes precedence over the default user. ```js const user = { identifier: 'john@example.com' }; configCatClient.setDefaultUser(user); const otherUser = { identifier: 'brian@example.com' }; // otherUser will be used in the evaluation process. const value = await configCatClient.getValueAsync( 'keyOfMyFeatureFlag', false, otherUser, ); ``` You can also remove the default user by doing the following: ```js configCatClient.clearDefaultUser(); ``` ## Polling Modes[​](#polling-modes "Direct link to Polling Modes") The *ConfigCat SDK* supports 3 different polling strategies to fetch feature flags and settings from the ConfigCat CDN. Once the latest data is downloaded, it is stored in the cache, then calls to `getValueAsync()` use the cached data to evaluate feature flags and settings. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. [More about polling modes.](https://configcat.com/docs/advanced/caching.md) ### Auto polling (default)[​](#auto-polling-default "Direct link to Auto polling (default)") The *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN automatically every 60 seconds and stores it in the cache. Use the `pollIntervalSeconds` option parameter to change the polling interval. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { pollIntervalSeconds: 95, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `pollIntervalSeconds` | Polling interval in seconds. | 60s | | `maxInitWaitTimeSeconds` | Maximum waiting time between the client initialization and the first config acquisition in seconds. | 5s | ### Lazy loading[​](#lazy-loading "Direct link to Lazy loading") When calling `getValueAsync()`, the *ConfigCat SDK* downloads the latest config data from the ConfigCat CDN only if it is not already present in the cache, or if the cache has expired. In this case `getValueAsync()` will return the setting value after the cache is updated. Use `cacheTimeToLiveSeconds` option parameter to set cache lifetime. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.LazyLoad, { cacheTimeToLiveSeconds: 600, }, ); ``` Available options (in addition to the [common ones](#creating-the-configcat-client)): | Option Parameter | Description | Default | | ------------------------ | --------------------- | ------- | | `cacheTimeToLiveSeconds` | Cache TTL in seconds. | 60s | ### Manual polling[​](#manual-polling "Direct link to Manual polling") Manual polling gives you full control over when the config data is downloaded from the ConfigCat CDN. The *ConfigCat SDK* will not download it automatically. Calling `forceRefreshAsync()` is your application's responsibility. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); await configCatClient.forceRefreshAsync(); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` > `getValueAsync()` returns `defaultValue` if the cache is empty. Call `forceRefreshAsync()` to update the cache. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, ); const value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); // console: "my default value" await configCatClient.forceRefreshAsync(); value = await configCatClient.getValueAsync( 'keyOfMyTextSetting', 'my default value', ); console.log(value); ``` ## Hooks[​](#hooks "Direct link to Hooks") The SDK provides several hooks (events), by means of which you can get notified of its actions. You can subscribe to the following events emitted by the *ConfigCat* client: * `clientReady: [cacheState: ClientCacheState]`: This event is emitted when the client reaches the ready state, i.e. completes initialization. * If Lazy Loading or Manual Polling is used, it's considered ready right after the initial sync with the external cache (if any) completes. * If Auto Polling is used, the ready state is reached as soon as * the initial sync with the external cache yields up-to-date config data, * otherwise, if the client is online (i.e. HTTP requests are allowed), the first config fetch operation completes (regardless of success or failure), * or the time specified via Auto Polling's `maxInitWaitTimeSeconds` option has passed. Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the `cacheState` argument. * `configFetched: [result: RefreshResult, isInitiatedByUser: boolean]`: This event is emitted each time the client attempts to refresh the cached config by fetching the latest version from the ConfigCat CDN. It is emitted not only when `ForceRefreshAsync` is called but also when the refresh is initiated by the client automatically. Thus, this event allows you to observe potential network issues that occur under the hood. * `configChanged: [newConfig: IConfig]`: This event is emitted first when the client's internal cache gets populated. Afterwards, it is emitted again each time the internally cached config is updated to a newer version, either as a result of synchronization with the external cache, or as a result of fetching a newer version from the ConfigCat CDN. * `flagEvaluated: [evaluationDetails: IEvaluationDetails]`: This event is emitted each time the client evaluates a feature flag or setting. The event provides the same evaluation details that you would get from [`getValueDetailsAsync()`](#anatomy-of-getvaluedetailsasync). * `clientError: [message: string, exception?: any]`: This event is emitted when an error occurs within the client. You can subscribe to these events either on initialization: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.ManualPoll, { setupHooks: (hooks) => hooks.on('flagEvaluated', function() { /* handle the event */ }), }, ); ``` ...or directly on the `ConfigCatClient` instance: ```js configCatClient.on('flagEvaluated', function() { /* handle the event */ }); ``` caution Some events (e.g. `clientReady`, `configChanged` and `clientError`) may be emitted before `getClient` returns. This means you may miss them unless you subscribe on initialization. However, even if you do, there's another gotcha: it's not safe to use the outer `configCatClient` variable in your event handler because it may not yet be assigned when the handler is called. Instead, you can safely access the client instance via `this.configCatClient` - provided that the event handler is a normal function, not an arrow function. ## Snapshots and synchronous feature flag evaluation[​](#snapshots-and-synchronous-feature-flag-evaluation "Direct link to Snapshots and synchronous feature flag evaluation") On JavaScript platforms, the *ConfigCat* client provides only asynchronous methods for evaluating feature flags and settings because these operations may involve network communication (e.g. downloading config data from the ConfigCat CDN servers), which is necessarily an asynchronous operation in JavaScript. However, there can be circumstances where synchronous evaluation is preferable, thus, since v8.1.0, the JavaScript SDK provides a way to synchronously evaluate feature flags and settings via *snapshots*. Using the `snapshot()` method, you can capture the current state of the *ConfigCat* client (including the latest downloaded config data) and use the resulting snapshot object to synchronously evaluate feature flags and settings based on the captured state: ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, ); // Wait for the client to initialize. await configCatClient.waitForReady(); const snapshot = configCatClient.snapshot(); const user = { identifier: '#UNIQUE-USER-IDENTIFIER#' }; for (const key of snapshot.getAllKeys()) { const value = snapshot.getValue(key, null, user); console.log(`${key}: ${value}`); } ``` Creating a snapshot is a cheap operation. This is possible because snapshots capture the client's internal (in-memory) cache. No attempt is made to refresh the internal cache, even if it's empty or expired. caution Please note that creating and using a snapshot * won't trigger a sync with the external cache when working with [shared caching](https://configcat.com/docs/advanced/caching.md#shared-cache), * won't fetch the latest config data from the ConfigCat CDN when the internally cached config data is empty or expired. For the above reasons, it's recommended to use snapshots in conjunction with the Auto Polling mode, where the SDK automatically updates the internal cache in the background. (For other polling modes, you'll need to manually initiate a cache refresh by calling `forceRefreshAsync`.) Because of this behavior, it's important to make sure that the client has completed initialization and populated its internal cache before creating snapshots. Otherwise the snapshot's evaluation methods won't have the data to do actual evaluation, but will just return the default value you pass to them. Which behavior is usually not what you want in your application. In Auto Polling mode, you can use the `waitForReady` method to wait for the latest config data to become available locally. This is an asynchronous operation, which completes as soon as the client reaches the ready state, i.e. completes initialization (or the time specified via the `maxInitWaitTimeSeconds` option passes). (Please note that this doesn't apply to other polling modes. In those cases, the client doesn't contact the ConfigCat CDN during initialization, so the ready state is reached as soon as the first sync with the external cache completes.) Typically, you call `waitForReady` and wait for its completion only once, in the initialization phase of your application. caution Reaching the ready state usually means the client is ready to evaluate feature flags and settings. However, please note that this is not guaranteed. In case of initialization failure or timeout, the internal cache may be empty or expired even after the ready state is reported. You can verify this by checking the return value. ```js const clientCacheState = await configCatClient.waitForReady(); if (clientCacheState === configcat.ClientCacheState.NoFlagData) { // Handle initialization failure (see below). console.warn('ConfigCat client failed to obtain the config data during initialization.'); } ``` You have the following options to handle unsuccessful initialization: * If it's acceptable for your application to start up and use the default values passed to the evaluation methods, you may log some warning (or skip the check altogether as the client will log warnings anyway), and let the application continue. * Otherwise, you need to either terminate the application or continue waiting. The latter is an option because the client might be able to obtain the config data later, in the case of a transient problem like some temporary network issue. However, the *ConfigCat SDK* doesn't provide out-of-the-box support for this case currently. You can implement this logic by subscribing to the `configChanged` hook and waiting for the first event. ## Online / Offline mode[​](#online--offline-mode "Direct link to Online / Offline mode") In cases where you want to prevent the SDK from making HTTP calls, you can switch it to offline mode: ```js configCatClient.setOffline(); ``` In offline mode, the SDK won't initiate HTTP requests and will work only from its cache. To switch the SDK back to online mode, do the following: ```js configCatClient.setOnline(); ``` Using the `configCatClient.isOffline` property you can check whether the SDK is in offline mode. ## Flag Overrides[​](#flag-overrides "Direct link to Flag Overrides") With flag overrides you can overwrite the feature flags & settings downloaded from the ConfigCat CDN with local values. Moreover, you can specify how the overrides should apply over the downloaded values. The following 3 behaviours are supported: * **Local only** (`OverrideBehaviour.LocalOnly`): When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use all feature flags & settings that are loaded from local-override sources. * **Local over remote** (`OverrideBehaviour.LocalOverRemote`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the local-override version will take precedence. * **Remote over local** (`OverrideBehaviour.RemoteOverLocal`): When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN, plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is defined both in the downloaded and the local-override source then the downloaded version will take precedence. You can set up the SDK to load your feature flag & setting overrides from a `{ [key: string]: boolean | string | number }` object or from a custom flag override data source. ### Map[​](#map "Direct link to Map") You can specify simple feature flag & setting overrides using a `{ [key: string]: boolean | string | number }` map. ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: configcat.createFlagOverridesFromMap( { enabledFeature: true, disabledFeature: false, intSetting: 5, doubleSetting: 3.14, stringSetting: 'test', }, configcat.OverrideBehaviour.LocalOnly, ), }, ); ``` ### Custom data source implementation[​](#custom-data-source-implementation "Direct link to Custom data source implementation") You can create a custom flag override data source by implementing `IOverrideDataSource`. The SDK provides the `createSettingFromValue` function to create `Setting` objects from simple `boolean`, `string` and `number` values. In case you need complex (full-featured) flag overrides, you can use the `deserializeConfig` function to obtain `Setting` objects from a config JSON conforming to the [config JSON v6 format](https://github.com/configcat/config-json/blob/main/V6/config.schema.json). ```ts class MyCustomOverrideDataSource implements IOverrideDataSource { private settings: Record; constructor(configJson: string) { this.settings = deserializeConfig(configJson).f ?? {}; } getOverrides(): Record { return this.settings; } } ``` or ```js function MyCustomOverrideDataSource(configJson) { this.settings = deserializeConfig(configJson).f ?? {}; } MyCustomOverrideDataSource.prototype.getOverrides = function () { return this.settings; }; ``` then ```js // Set the `MyCustomOverrideDataSource` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { flagOverrides: { dataSource: new MyCustomOverrideDataSource('{ "f": { ... } }'), behaviour: configcat.OverrideBehaviour.LocalOnly, } }, ); ``` ## Logging[​](#logging "Direct link to Logging") ### Setting log levels[​](#setting-log-levels "Direct link to Setting log levels") ```js const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: configcat.createConsoleLogger(configcat.LogLevel.Info), // Setting log level to Info }, ); ``` Available log levels: | Level | Description | | ----- | ------------------------------------------------------- | | Off | Nothing gets logged. | | Error | Only error level events are logged. | | Warn | Default. Errors and Warnings are logged. | | Info | Errors, Warnings and feature flag evaluation is logged. | | Debug | All of the above plus debug info is logged. | Info level logging helps to inspect the feature flag evaluation process: ```bash ConfigCat - INFO - [5000] Evaluating 'isPOCFeatureEnabled' for User '{"Identifier":"#SOME-USER-ID#","Email":"configcat@example.com"}' Evaluating targeting rules and applying the first match if any: - IF User.Email CONTAINS ANY OF ['@something.com'] THEN 'false' => no match - IF User.Email CONTAINS ANY OF ['@example.com'] THEN 'true' => MATCH, applying rule Returning 'true'. ``` ### Custom logger implementation[​](#custom-logger-implementation "Direct link to Custom logger implementation") The SDK provides a simple logger implementation that logs to [the debugging console](https://developer.mozilla.org/en-US/docs/Web/API/console) (`configcat.createConsoleLogger(...)`) but it also allows you to inject any custom implementation of `IConfigCatLogger`. ```ts class MyCustomLogger implements IConfigCatLogger { /** * Writes an event into the log. * @param level Event severity level. * @param eventId Event identifier. * @param message Message. * @param exception The exception object related to the message (if any). */ log( level: LogLevel, eventId: LogEventId, message: LogMessage, exception?: any, ): void { // insert your custom log logic } } ``` or ```js function MyCustomLogger() {} MyCustomLogger.prototype.log = function (level, eventId, message, exception) { // insert your custom log logic }; ``` then ```js // Set the `MyCustomLogger` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { logger: new MyCustomLogger(), }, ); ``` ### Log Filtering[​](#log-filtering "Direct link to Log Filtering") You can define a custom log filter by providing a callback function via the `logFilter` option. The callback will be called by the *ConfigCat SDK* each time a log event occurs (and the event passes the minimum log level specified by the `IConfigCatLogger.level` property). That is, the callback allows you to filter log events by `level`, `eventId`, `message` or `exception`. The formatted message string can be obtained via `message.toString()`. If the callback function returns `true`, the event will be logged, otherwise it will be skipped. ```js // Filter out events with id 1001 from the log. const logFilter = (level, eventId, message, exception) => eventId != 1001; const configCatClient = configcat.getClient( "#YOUR-SDK-KEY#", configcat.PollingMode.AutoPoll, { logFilter: logFilter } ); ``` caution Please make sure that your log filter logic doesn't perform heavy computation. A complex or incorrectly implemented log filter can degrade the performance of the SDK. ## `getAllKeysAsync()`[​](#getallkeysasync "Direct link to getallkeysasync") You can get the keys for all available feature flags and settings by calling the `getAllKeysAsync()` method. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); const keys = await configCatClient.getAllKeysAsync(); console.log(keys); ``` ## `getAllValuesAsync()`[​](#getallvaluesasync "Direct link to getallvaluesasync") Evaluates and returns the values of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValuesAsync(); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValuesAsync(userObject); settingValues.forEach((i) => console.log(i.settingKey + ' -> ' + i.settingValue), ); ``` ## `getAllValueDetailsAsync()`[​](#getallvaluedetailsasync "Direct link to getallvaluedetailsasync") Evaluates and returns the values along with evaluation details of all feature flags and settings. Passing a [User Object](#user-object) is optional. ```js const configCatClient = configcat.getClient('#YOUR-SDK-KEY#'); let settingValues = await configCatClient.getAllValueDetailsAsync(); settingValues.forEach((details) => console.log(details)); // invoke with User Object const userObject = { identifier: 'john@example.com' }; settingValues = await configCatClient.getAllValueDetailsAsync(userObject); settingValues.forEach((details) => console.log(details)); ``` ## Using custom cache implementation[​](#using-custom-cache-implementation "Direct link to Using custom cache implementation") The *ConfigCat SDK* stores the downloaded config data in a local cache to minimize network traffic and enhance client performance. If you prefer to use your own cache solution, such as an external or distributed cache in your system, you can implement the [`IConfigCatCache`](https://github.com/configcat/js-unified-sdk/blob/master/src/ConfigCatCache.ts) interface and set the `cache` property in the options passed to `getClient`. This allows you to seamlessly integrate ConfigCat with your existing caching infrastructure. ```ts class MyCustomCache implements IConfigCatCache { set(key: string, value: string): Promise | void { // insert your cache write logic here } get( key: string, ): Promise | string | null | undefined { // insert your cache read logic here } } ``` or ```js function MyCustomCache() {} MyCustomCache.prototype.set = function (key, value) { // insert your cache write logic here }; MyCustomCache.prototype.get = function (key) { // insert your cache read logic here }; ``` then ```js // Set the `MyCustomCache` implementation on client creation. const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { cache: new MyCustomCache(), }, ); ``` info The JavaScript SDK supports *shared caching*. You can read more about this feature and the required minimum SDK versions [here](https://configcat.com/docs/advanced/caching.md#shared-cache). ## Using ConfigCat behind a proxy[​](#using-configcat-behind-a-proxy "Direct link to Using ConfigCat behind a proxy") It is possible to set up the SDK to route HTTP requests through a HTTP, HTTPS or SOCKS proxy. ```bash npm i https-proxy-agent ``` ```js import { HttpsProxyAgent } from 'https-proxy-agent'; const configCatClient = configcat.getClient( '#YOUR-SDK-KEY#', configcat.PollingMode.AutoPoll, { httpsAgent: new HttpsProxyAgent("http://192.168.1.1:8080"), }, ); ``` info By default, you need to specify the `httpsAgent` option because the SDK always uses HTTPS to access the ConfigCat CDN. However, if you set the `baseUrl` to a `http://...` URL, you will need to install `http-proxy-agent` and set the `httpAgent` option instead. ## Sensitive information handling[​](#sensitive-information-handling "Direct link to Sensitive information handling") The frontend/mobile SDKs are running in your users' browsers/devices. The SDK is downloading a [config JSON](https://configcat.com/docs/requests.md) file from ConfigCat's CDN servers. The URL path for this config JSON file contains your SDK key, so the SDK key and the content of your config JSON file (feature flag keys, feature flag values, Targeting Rules, % rules) can be visible to your users. In ConfigCat, all SDK keys are read-only. They only allow downloading your config JSON files, but nobody can make any changes with them in your ConfigCat account. If you do not want to expose the SDK key or the content of the config JSON file, we recommend using the SDK in your backend components only. You can always create a backend endpoint using the *ConfigCat SDK* that can evaluate feature flags for a specific user, and call that backend endpoint from your frontend/mobile applications. Also, we recommend using [confidential targeting comparators](https://configcat.com/docs/targeting/targeting-rule/user-condition.md#confidential-text-comparators) in the Targeting Rules of those feature flags that are used in the frontend/mobile SDKs. ## Platform compatibility[​](#platform-compatibility "Direct link to Platform compatibility") The SDK should be compatible with latest versions of Node.js. The SDK is [tested](https://github.com/configcat/js-unified-sdk/blob/master/.github/workflows/js-sdk-ci.yml) against the following runtimes: * Node.js (v14.x, v16.x, v18.x, v20.x, v22.x) on Windows / Ubuntu / macOS The SDK is compatible with TypeScript v4.0.2 or newer. Earlier versions may work but those are not tested, thus, not supported officially. These tests are running on each pull request, before each deploy, and on a daily basis. You can view a sample run [here](https://github.com/configcat/js-unified-sdk/actions/runs/11745259578). ## Best practices[​](#best-practices "Direct link to Best practices") ### Choosing polling mode for serverless functions[​](#choosing-polling-mode-for-serverless-functions "Direct link to Choosing polling mode for serverless functions") In most cases, Auto polling is a good choice, but it's not ideal for short-lived serverless functions like AWS Lambdas, Azure Functions, Cloudflare Workers, etc. For example, if the SDK is running in a Next.js application that is hosted on Vercel (AWS Lambda), or your application is hosted directly in AWS Lambdas, it is recommended to use the SDK in Lazy loading or Manual polling mode instead of the default Auto polling mode. As AWS Lambdas try to minimize their uptime, the applications are terminated as soon as the sytem detects inactivity in the application. Auto polling mode is implemented using an asynchronous background loop to periodically get the config data from the ConfigCat servers, however the AWS Lambda doesn't detect it as a running application and terminates it. So it can easily happen that there is an ongoing HTTP GET request towards our servers and this termination can cause errors. The most likely error message in this case is `Request timed out while trying to fetch config JSON.` ## Sample Applications[​](#sample-applications "Direct link to Sample Applications") * [Sample Node.js console application](https://github.com/configcat/js-unified-sdk/tree/master/samples/node-console) * [Sample Node.js console application using ECMAScript module system](https://github.com/configcat/js-unified-sdk/tree/master/samples/node-console-esm) * [Sample Node.js console application using TypeScript](https://github.com/configcat/js-unified-sdk/tree/master/samples/ts-node-console) * [Sample Node.js console application using TypeScript and ECMAScript module system](https://github.com/configcat/js-unified-sdk/tree/master/samples/ts-node-console-esm) * [Sample Node.js application using Express and Docker](https://github.com/configcat/js-unified-sdk/tree/master/samples/node-expresswithdocker) * [Sample Node.js application on how to get real time updates on feature flag changes](https://github.com/configcat/js-unified-sdk/tree/master/samples/node-realtimeupdate) ## Guides[​](#guides "Direct link to Guides") See the guides on how to use ConfigCat's JavaScript SDK with the following libraries and frameworks: info Some of these guides may use legacy SDKs. However, the parts beyond NPM package installation and import should still work with modern SDKs. * [NestJS](https://configcat.com/blog/2022/08/19/how-to-use-feature-flags-in-nestjs/) * [Express](https://configcat.com/blog/2022/09/02/how-to-use-feature-flag-in-expressjs/) ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [ConfigCat SDK for JavaScript on GitHub](https://github.com/configcat/js-unified-sdk) * [ConfigCat SDK for JavaScript in NPM](https://www.npmjs.com/package/@configcat/sdk) --- # Source: https://configcat.com/docs/advanced/notifications-webhooks.md # Notifications - Webhooks Copy page ConfigCat Webhooks can notify your applications when a feature flag or other Setting changes by calling a public HTTP endpoint on your end. This allows your applications to react almost immediately to updates. Webhooks add the speed of near real-time updates to the reliability of Polling, giving your applications a fast and robust way to stay in sync. To enable Webhooks, simply tell us which HTTP endpoint to call. ConfigCat will send a request to that URL whenever a change occurs. ## Adding a Webhook[​](#adding-a-webhook "Direct link to Adding a Webhook") 1. Go to the [Webhooks](https://app.configcat.com/webhook) screen. 2. Click the **+ ADD WEBHOOK** button. 3. Choose **when** webhook notifications should be sent by selecting the **Config** and **Environment** where changes should trigger the Webhook. 4. Define **how** to notify your system by setting the **URL** and the **HTTP METHOD**. This tells us which endpoint to call. 5. (Optional) Add custom HTTP headers and a request body if needed. ## Request body with variables[​](#request-body-with-variables "Direct link to Request body with variables") You can customize the request body that will be sent with each Webhook call. ConfigCat will replace certain placeholders in the body with real values at runtime. | Variable | Replaced with | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | **##ConfigName##** | The name of the Config where the change happened. | | **##ConfigId##** | ID of the Config where the change happened. | | **##EnvironmentName##** | The name of the Environment where the change happened. | | **##EnvironmentId##** | ID of the Environment where the change happened. | | **##URL##** | A direct link to the Config in the *ConfigCat Dashboard.* | | **##ChangeNotes##** | The **Mandatory notes** added to the actual changeset. | | **##ChangedBy##** | The name and email address of the user who made the changes. | | **##ChangeDetails##** | Detailed change info in JSON format, including the name of the Setting or feature flag, old and new values and Targeting Rules. | | **##ChangeDetailsTeams##** | Change details formatted for Microsoft Teams. | | **##ChangeDetailsSlack##** | Change details formatted for Slack. | The ##ChangeDetails## variable is replaced with a JSON array in the following format: ```text [ { "settingKey":"myAwesomeFeature1", "event":"changed", "details":"\r\nmyAwesomeFeature1: false ➔ true" }, { "settingKey":"myAwesomeFeature2", "event":"changed", "details":"\r\nmyAwesomeFeature2:\r\n Rollout percentage items changed:\r\n + 20% true\r\n + 80% false" } ] ``` ## Testing your Webhook[​](#testing-your-webhook "Direct link to Testing your Webhook") 1. Change some of your settings in the *ConfigCat Dashboard.* 2. Click **SAVE & PUBLISH CHANGES**. 3. Check if your Webhook was called correctly. info **Developer Tip** * Running your Webhook on `localhost`? Expose it to the public internet temporarily by using a tool like [ngrok](https://ngrok.com/). This enables ConfigCat to call your webhook even in your local development environment. * Just interested in what ConfigCat sends? Try [Webhhok.site](https://webhook.site/). This allows you to catch HTTP requests and see their content without requiring your to run anything anywhere. ## Verifying Webhook requests[​](#verifying-webhook-requests "Direct link to Verifying Webhook requests") To make sure the requests you receive are actually sent by ConfigCat, we strongly recommend verifying the signature included in the request headers. You can do this by comparing the received signature with one you compute using your signing key. Each webhook request includes the following headers: | Header | Description | | ---------------------------------- | -------------------------------------------------------------------------------------------- | | `X-ConfigCat-Webhook-ID` | A unique ID for the webhook request. This is different for every request. | | `X-ConfigCat-Webhook-Timestamp` | The time the request was sent, in Unix timestamp format (seconds since epoch). | | `X-ConfigCat-Webhook-Signature-V1` | A comma-separated list of base64-encoded HMAC-SHA-256 signatures (one for each signing key). | Currently, the latest (and the only) signature header version is `V1`. If the signing process changes in the future, new headers will be added with incremented version numbers. Example request: ```text POST /path HTTP/1.1 Host: X-ConfigCat-Webhook-ID: b616ca659d154a5fb907dd8475792eeb X-ConfigCat-Webhook-Timestamp: 1669580020 X-ConfigCat-Webhook-Signature-V1: RoO/UMvSRqzJ0OolMMuhHBbM8/Vjn+nTh+SKyLcQf0M=,heIrGPw6aylAZEX6xmSLrxIWVif5injeBCxWQ+0+b2U= ``` ### Content to sign[​](#content-to-sign "Direct link to Content to sign") The signature is calculated from the content constructed by concatenating the webhook's `id`, `timestamp`, and raw `body` together. ```js const contentToSign = `${webhookId}${timestamp}${body}`; ``` | Content part | Description | | ------------ | ------------------------------------------------------------------------------------------------------------ | | `webhookId` | The webhook's identifier received in the `X-ConfigCat-Webhook-ID` request header. | | `timestamp` | The timestamp value received in the `X-ConfigCat-Webhook-Timestamp` request header. | | `body` | The raw body of the received webhook request. If the webhook doesn't have a request body it can be left out. | caution The signature calculation is sensitive to any changes on the signed content, so it's important to not change the request body before the verification. Otherwise, the calculated signature could be completely different from the value received in the
`X-ConfigCat-Webhook-Signature-V1` header. ### Calculating signature[​](#calculating-signature "Direct link to Calculating signature") ConfigCat uses `HMAC` with `SHA-256` to sign webhooks. You can retrieve the **signing key(s)** required for the signature calculation from the [ConfigCat Dashboard's webhook page](https://app.configcat.com/product/webhooks). ![signing keys](/docs/assets/whsk.png) info For **key rotation** purposes, you can generate a secondary signing key. In this case ConfigCat sends two signatures (one signed with the *primary* and one signed with the *secondary* key) in the `X-ConfigCat-Webhook-Signature-V1` header separated by a comma (`,`): ```text X-ConfigCat-Webhook-Signature-V1: RoO/UMvSRqzJ0OolMMuhHBbM8/Vjn+nTh+SKyLcQf0M=,heIrGPw6aylAZEX6xmSLrxIWVif5injeBCxWQ+0+b2U= ``` * Node.js * Python * Ruby * PHP * Go * .NET * Java ```js const crypto = require('crypto'); // retrieved from the ConfigCat Dashboard const signingKey = 'configcat_whsk_VN3juirnVh5pNvCKd81RYRYchxUX4j3NykbZG2fAy88='; // retrieved from the the X-ConfigCat-Webhook-Signature-V1 request header const receivedSignature = 'Ks3cYsu9Lslfo+hVxNC3oQWnsF9e5d73TI5t94D9DRA='; // retrieved from the the X-ConfigCat-Webhook-ID request header const requestId = 'b616ca659d154a5fb907dd8475792eeb'; // retrieved from the the X-ConfigCat-Webhook-Timestamp request header const timestamp = 1669629035; // the webhook request's raw body const body = 'examplebody'; const contentToSign = `${requestId}${timestamp}${body}`; const calculatedSignature = crypto .createHmac('sha256', signingKey) .update(contentToSign) .digest('base64'); console.log(calculatedSignature == receivedSignature); // must be true ``` ```python import hmac import base64 # retrieved from the ConfigCat Dashboard signing_key = "configcat_whsk_VN3juirnVh5pNvCKd81RYRYchxUX4j3NykbZG2fAy88=" # retrieved from the X-ConfigCat-Webhook-Signature-V1 request header received_signature = "Ks3cYsu9Lslfo+hVxNC3oQWnsF9e5d73TI5t94D9DRA=" # retrieved from the X-ConfigCat-Webhook-ID request header request_id = "b616ca659d154a5fb907dd8475792eeb" # retrieved from the X-ConfigCat-Webhook-Timestamp request header timestamp = 1669629035 # the webhook request's raw body body = "examplebody" content_to_sign = request_id+str(timestamp)+body signing_key_bytes = bytes(signing_key, 'utf-8') calculated_signature = base64.b64encode(hmac.new(signing_key_bytes, bytes(content_to_sign, 'utf-8'), 'sha256').digest()) print(calculated_signature.decode() == received_signature) # must be true ``` ```ruby require 'openssl' require 'base64' # retrieved from the ConfigCat Dashboard signing_key = "configcat_whsk_VN3juirnVh5pNvCKd81RYRYchxUX4j3NykbZG2fAy88=" # retrieved from the X-ConfigCat-Webhook-Signature-V1 request header received_signature = "Ks3cYsu9Lslfo+hVxNC3oQWnsF9e5d73TI5t94D9DRA=" # retrieved from the X-ConfigCat-Webhook-ID request header request_id = "b616ca659d154a5fb907dd8475792eeb" # retrieved from the X-ConfigCat-Webhook-Timestamp request header timestamp = 1669629035 # the webhook request's raw body body = "examplebody" content_to_sign = "#{request_id}#{timestamp}#{body}" calculated_signature = Base64.strict_encode64(OpenSSL::HMAC.digest("sha256", signing_key, content_to_sign)) puts calculated_signature == received_signature # must be true ``` ```php changed in ConfigCat: \n\n##ChangeDetailsSlack##" } ``` ## Connecting to Microsoft Teams[​](#connecting-to-microsoft-teams "Direct link to Connecting to Microsoft Teams") A few steps to set up Microsoft Teams and get a message when a setting changes: 1. In Microsoft Teams, create an [Incoming Webhook](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook#create-incoming-webhook-1) and copy the **Webhook URL**. 2. In ConfigCat, go to the [Webhooks](https://app.configcat.com/webhook) screen, and click **+ ADD WEBHOOK**. 3. Paste Microsoft Teams' **Webhhok URL** to ConfigCat's **URL** field. 4. Select **POST** as the **HTTP METHOD**. 5. Add the following request body: ```text { "@context": "https://schema.org/extensions", "@type": "MessageCard", "themeColor": "0072C6", "title": "##ConfigName## - ##EnvironmentName##", "text": "##ChangeDetailsTeams##", "potentialAction": [ { "@type": "OpenUri", "name": "Open Config in ConfigCat Dashboard", "targets": [ { "os": "default", "uri": "##URL##" } ] } ] } ``` --- # Source: https://configcat.com/docs/advanced/team-management/scim/identity-providers/okta.md # Source: https://configcat.com/docs/advanced/team-management/saml/identity-providers/okta.md # Okta Identity Provider Copy page Connect ConfigCat with Okta via SAML. ## Introduction[​](#introduction "Direct link to Introduction") Each SSO Identity Provider requires specific information to configure a SAML integration. The following guide will walk you through how you can connect ConfigCat with Okta as a SAML Identity Provider. ## 1. Create an Application in Okta[​](#1-create-an-application-in-okta "Direct link to 1. Create an Application in Okta") * Log in to [Okta](https://login.okta.com/), go to the admin Dashboard, and select `Applications`. ![Okta applications](/docs/assets/saml/okta/applications.png) * Click on `Create App Integration`. ![Okta create app](/docs/assets/saml/okta/create_app.png) * Select `SAML 2.0` as the Sign-in method. ![Okta select SAML](/docs/assets/saml/okta/select_saml.png) * Enter a descriptive `App name`, then click `Next`. ![Okta app name](/docs/assets/saml/okta/app_name.png) The next step will guide you on how to collect the information required for the appearing `Configure SAML` section. ## 2. Configure SAML for the Okta Application[​](#2-configure-saml-for-the-okta-application "Direct link to 2. Configure SAML for the Okta Application") * Open your organization's authentication settings on the [ConfigCat Dashboard](https://app.configcat.com/organization/authentication). ![ConfigCat authentication settings](/docs/assets/saml/dashboard/authentication.png) * Click `ADD SAML IDENTITY PROVIDER`. ![ConfigCat Add Identity Provider](/docs/assets/saml/dashboard/add_idp.png) * Give a name for your Identity Provider, and click `Create`. ![ConfigCat Name Identity Provider](/docs/assets/saml/dashboard/okta_name.png) * From the next section of the dialog, copy the following values and paste them into the Okta application. * `Entity ID` -> `Audience URI (SP Entity ID)` * `Assertion Consumer Service` -> `Single sign on URL` ![ConfigCat SAML configuration](/docs/assets/saml/dashboard/acs_entity_id_1.png) ![Okta SAML url EID](/docs/assets/saml/okta/okta_acs_eid.png) * Set the `Name ID format` to `EmailAddress`, then click `Next`. ![Okta SAML nameid](/docs/assets/saml/okta/okta_name_id.png) * Select `I'm an Okta customer adding an internal app`. Complete the form with any comments and click `Finish`. ![Okta SAML feedback](/docs/assets/saml/okta/feedback.png) ## 3. Configure ConfigCat with SAML Details from Okta[​](#3-configure-configcat-with-saml-details-from-okta "Direct link to 3. Configure ConfigCat with SAML Details from Okta") You can choose one of the following options to configure ConfigCat with SAML Identity Provider metadata. * Metadata URL * Manual Configuration - Select the `Sign On` tab. ![Okta sign on tab](/docs/assets/saml/okta/metadata_url1.png) - Copy the URL of `View IdP metadata`. ![Okta metadata url](/docs/assets/saml/okta/metadata_url2.png) - Paste the copied value into the `Metadata URL` field at ConfigCat. ![ConfigCat metadata url](/docs/assets/saml/okta/cc_metadata_new.png) - Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) - Click on `Save`. * Select the `Sign On` tab, and click on `View SAML setup instructions`. ![Okta SAML setup](/docs/assets/saml/okta/manual_setup.png) * Copy the value of the `Identity Provider Single Sign-On URL` and `X.509 Certificate` fields and paste them into the Configuration dialog at ConfigCat. ![Okta manual configuration](/docs/assets/saml/okta/manual.png)![ConfigCat manual configuration](/docs/assets/saml/okta/manual_cc_new.png) * Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) * Click on `Save`. ## 4. Assign Users to Okta Application[​](#4-assign-users-to-okta-application "Direct link to 4. Assign Users to Okta Application") To let users authenticate via SAML, you need to assign individual users or groups to the Okta application. * Select the `Assignments` tab, and select either the `Assign to People` or the `Assign to Groups` option. ![Okta assign to groups](/docs/assets/saml/okta/assign.png) ## 5. Sign In[​](#5-sign-in "Direct link to 5. Sign In") * Go to the [ConfigCat Log In](https://app.configcat.com) page, and click `COMPANY ACCOUNT - SAML`. ![ConfigCat SAML login](/docs/assets/saml/dashboard/saml_login.png) * Sign in with your company email address assigned to the Okta application. ![ConfigCat SAML company login](/docs/assets/saml/dashboard/company_email.png) * ConfigCat will redirect you to Okta's sign in page. Type your credentials, and click `Sign In`. ![Okta sign in](/docs/assets/saml/okta/okta_sign_in.png) * You should be redirected to ConfigCat signed in with your company account. ## 6. Next Steps[​](#6-next-steps "Direct link to 6. Next Steps") * Configure [User provisioning (SCIM)](https://configcat.com/docs/advanced/team-management/scim/scim-overview.md) * or configure the [auto-assignment of users](https://configcat.com/docs/advanced/team-management/auto-assign-users.md) if you don't want to provision your users with your Identity Provider. --- # Source: https://configcat.com/docs/advanced/team-management/scim/identity-providers/onelogin.md # Source: https://configcat.com/docs/advanced/team-management/saml/identity-providers/onelogin.md # OneLogin Identity Provider Copy page Connect ConfigCat with OneLogin via SAML. ## Introduction[​](#introduction "Direct link to Introduction") Each SSO Identity Provider requires specific information to configure a SAML integration. The following guide will walk you through how you can connect ConfigCat with OneLogin as a SAML Identity Provider. ## 1. Create an Application in OneLogin[​](#1-create-an-application-in-onelogin "Direct link to 1. Create an Application in OneLogin") * Log in to [OneLogin](https://app.onelogin.com/login), and select `Applications`. ![OneLogin applications](/docs/assets/saml/onelogin/applications.png) * Click on `Add App`. ![OneLogin add application](/docs/assets/saml/onelogin/add_app.png) * Type `SAML` into the search bar, and select `SAML Custom Connector (Advanced)`. ![OneLogin select APP](/docs/assets/saml/onelogin/select_app.png) * Enter a descriptive `Display Name`, then click `Save`. ![OneLogin app name](/docs/assets/saml/onelogin/app_name.png) The next step will guide you on how to collect the information required for the appearing `Configuration` page. ## 2. Configure SAML for the OneLogin Application[​](#2-configure-saml-for-the-onelogin-application "Direct link to 2. Configure SAML for the OneLogin Application") * Open your organization's authentication settings on the [ConfigCat Dashboard](https://app.configcat.com/organization/authentication). ![ConfigCat authentication settings](/docs/assets/saml/dashboard/authentication.png) * Click `ADD SAML IDENTITY PROVIDER`. ![ConfigCat Add Identity Provider](/docs/assets/saml/dashboard/add_idp.png) * Give a name for your Identity Provider, and click `Create`. ![ConfigCat Name Identity Provider](/docs/assets/saml/dashboard/onelogin_name.png) * From the next section of the dialog, copy the following values and paste them into the OneLogin application's configuration page. * Copy `Entity ID` and paste it into the `Audience (EntityID)` field. * Copy `Assertion Consumer Service` and paste it into the `ACS (Consumer) URL` field. * Paste the same `Assertion Consumer Service` into the `ACS (Consumer) URL Validator` field in regex format e.g. `^https:\/\/dashboard\-api\.configcat\.com\/saml\/acs\/08db93fc\-c4e7\-441f\-834f\-17c804385c29$` ![ConfigCat SAML configuration](/docs/assets/saml/dashboard/acs_entity_id_1.png) ![OneLogin SML configuration](/docs/assets/saml/onelogin/onelogin_acs_eid.png) * Scroll down a bit on this page and configure the following: * Select `OneLogin` as `SAML Initiator`. * Select `Email` as `SAML nameID format`. * Select `Both` as `SAML signature element`. ![OneLogin SAML initiator](/docs/assets/saml/onelogin/saml_config2.png) * Select `Parameters`, and make sure there is a `NameID value` entry under the `SAML Custom Connector (Advanced) Field` with the value `Email`. ![OneLogin nameID](/docs/assets/saml/onelogin/name_id.png) * Select `SSO`, then select `SHA-256` as `SAML Signature Algorithm`. ![OneLogin SAML Signature Algorithm](/docs/assets/saml/onelogin/sso_signing_algo.png) ## 3. Configure ConfigCat with SAML Details from OneLogin[​](#3-configure-configcat-with-saml-details-from-onelogin "Direct link to 3. Configure ConfigCat with SAML Details from OneLogin") You can choose one of the following options to configure ConfigCat with SAML Identity Provider metadata. * Metadata URL * Manual Configuration - Select `SSO`, and copy the value of `Issuer URL`. ![OneLogin SAML SSO configuration](/docs/assets/saml/onelogin/sso_config.png) - Paste the copied value into the `Metadata URL` field at ConfigCat. ![ConfigCat SAML configuration](/docs/assets/saml/onelogin/cc_meta_url_new.png) - Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) - Click on `Save`. * Select `SSO`, and copy the value of `SAML 2.0 Endpoint (HTTP)`, then click `View Details` under the `X.509 Certificate`. ![OneLogin manual SAML SSO configuration](/docs/assets/saml/onelogin/sso_config_manual.png) * Copy the value of the `X.509 Certificate`. ![OneLogin certificate](/docs/assets/saml/onelogin/cert.png) * Paste the value of the `SAML 2.0 Endpoint (HTTP)` and the `X.509 Certificate` into the Configuration dialog at ConfigCat ![ConfigCat manual configuration](/docs/assets/saml/onelogin/cc_manual_new.png) * Select the **trusted domains**. Only user accounts from trusted domains can login with SAML SSO. You can bind multiple verified domains to a SAML Identity Provider. ![Select trusted domains](/docs/assets/saml/dashboard/select_trusted_domains.png) * Click on `Save`. ## 4. Assign the OneLogin Application to Users[​](#4-assign-the-onelogin-application-to-users "Direct link to 4. Assign the OneLogin Application to Users") To let users authenticate via SAML, you need to assign the newly created application to them. * Select `Users`. ![OneLogin users](/docs/assets/saml/onelogin/users.png) * Select the user you want to get access to the application. ![OneLogin select user](/docs/assets/saml/onelogin/select_user.png) * Select `Applications`, then click on the `+` sign. ![OneLogin add application](/docs/assets/saml/onelogin/add_application.png) * Select your application, then click `Continue`. ![OneLogin application added](/docs/assets/saml/onelogin/app_added.png) * Click `Save`. ![OneLogin application details](/docs/assets/saml/onelogin/app_details.png) ## 5. Sign In[​](#5-sign-in "Direct link to 5. Sign In") * Go to the [ConfigCat Log In](https://app.configcat.com) page, and click `COMPANY ACCOUNT - SAML`. ![ConfigCat SAML login](/docs/assets/saml/dashboard/saml_login.png) * Sign in with your company email address assigned to the OneLogin application. ![ConfigCat SAML company login](/docs/assets/saml/dashboard/company_email.png) * ConfigCat will redirect you to OneLogin's sign in page. Type your credentials, and click `Continue`. ![OneLogin SAML login](/docs/assets/saml/onelogin/login.png) * You should be redirected to ConfigCat signed in with your company account. ## 6. Next Steps[​](#6-next-steps "Direct link to 6. Next Steps") * Configure [User provisioning (SCIM)](https://configcat.com/docs/advanced/team-management/scim/scim-overview.md) * or configure the [auto-assignment of users](https://configcat.com/docs/advanced/team-management/auto-assign-users.md) if you don't want to provision your users with your Identity Provider. --- # Source: https://configcat.com/docs/organization.md # Organization & Roles Copy page An *Organization* represents a collection of preferences that apply to all your *Products* and *Members* in that *Organization*. This includes things like billing information, sign-in methods, and data privacy settings. The *Manage Organization* menu is only available for *Organization Admins*. ![Organization-menu](/docs/assets/organization-menu.png) ## Organization Admin role[​](#organization-admin-role "Direct link to Organization Admin role") *Organization Admins* have full access to the entire organization and all products. For example, they can: * Add or remove members * Set up security settings * Change sign-in methods * Create or delete products, feature flags, and environments They **do not** have access to billing or subscription settings unless they are also *Billing Managers*. Only *Organization Admins* can assign or remove the *Organization Admin* role from others. ## Billing Manager role[​](#billing-manager-role "Direct link to Billing Manager role") Only *Billing Managers* can: * View and update billing information * Change the subscription plan * Assign or remove the *Billing Manager* role from others *Billing Managers* **cannot** access products, environments, configs, or feature flags, unless they are also *Organization Admins*. --- # Source: https://configcat.com/docs/api/reference/organizations.md # Organizations Copy page With these endpoints you can get useful information about your Organizations. This also can be used to manage your [Products](https://configcat.com/docs/api/reference/products.md). [Here](https://configcat.com/docs/organization.md) you can read more about the Organizations. ## [📄️ List Organizations](https://configcat.com/docs/api/reference/get-organizations.md) [This endpoint returns the list of the Organizations that belongs to the user.](https://configcat.com/docs/api/reference/get-organizations.md) ## [📄️ Get Organization limitations](https://configcat.com/docs/api/reference/get-organization-limitations.md) [This endpoint returns the limitations of an Organization identified by the \`organizationId\`.](https://configcat.com/docs/api/reference/get-organization-limitations.md) --- # Source: https://configcat.com/docs/integrations/overview.md # Source: https://configcat.com/docs/sdk-reference/overview.md # Source: https://configcat.com/docs/sdk-reference/openfeature/overview.md # Source: https://configcat.com/docs/sdk-reference/js/overview.md # Source: https://configcat.com/docs/advanced/code-references/overview.md # Scan & Upload Code References Overview Copy page ConfigCat's [CLI](https://configcat.com/docs/advanced/cli.md) has the ability to scan your source code for feature flag and setting usages and upload the found code references to ConfigCat. This feature makes the elimination of the technical debt easier, as it can show which repositories reference your feature flags and settings in one centralized place on your [Dashboard](https://app.configcat.com). You can integrate the CLI into your CI/CD pipeline or use it with other execution mechanisms like scheduled jobs or VCS push triggered workflows. ## Scan[​](#scan "Direct link to Scan") The following example shows a simple scan execution that prints the scan result to the console. The `scan` command searches for every feature flag and setting key defined within a selected Config. ![ConfigCat scan command in action](/docs/assets/cli/cli-scan.gif) If you want to see this in action on your project, run the following command in its root folder: ```bash configcat scan . --print ``` See the `scan` command's [reference documentation](https://configcat.github.io/cli/configcat-scan.html) for all available command parameters. ### Deleted Flags[​](#deleted-flags "Direct link to Deleted Flags") As part of the scanning operation, the CLI gathers all deleted feature flags and settings from the last 180 days and looks for their usage in your source code. When it finds a reference to a deleted feature flag or setting, it prints a warning that lists their keys. ```bash [warning]: 5 deleted feature flag/setting reference(s) found in 4 file(s). Keys: [featureThatWasDeleted1, featureThatWasDeleted2] ``` ### Exclude Flags from Scanning[​](#exclude-flags-from-scanning "Direct link to Exclude Flags from Scanning") There's an option to exclude feature flags or settings from the scanning operation by their keys. ```bash configcat scan --exclude-flag-keys featureFlagToExclude1 featureFlagToExclude2 ``` ## Config ID[​](#config-id "Direct link to Config ID") In non-interactive environments, like in a CI/CD pipeline, you have to pass the ID of your ConfigCat Config that you want to scan against. The scanner will use this ID to determine which feature flags & settings to search for in your source code. To get the ID of a Config, follow the steps below: 1. Go to your [ConfigCat Dashboard](https://app.configcat.com), select the desired Config, and click the code references icon on one of your feature flags. ![ConfigCat code references button](/docs/assets/cli/scan/code_ref.png) 2. Copy the Config ID from the highlighted box. ![ConfigCat Config ID](/docs/assets/cli/scan/config_id.png) ## How Scanning Works[​](#how-scanning-works "Direct link to How Scanning Works") The scanner looks for feature flag and setting keys between quotation marks (`'` `"` `` ` ``) in the first place. info There's an option to extend the feature flag and setting key usage regex patterns with the `--usage-patterns` argument of the `scan` command. ```bash configcat scan --usage-patterns "" "" ``` Usage patterns can also be set via the `CONFIGCAT_USAGE_PATTERNS` environment variable as a comma delimited list. ```bash export CONFIGCAT_USAGE_PATTERNS=","; ``` The regex pattern must include the `CC_KEY` placeholder that represents the actual feature flag or setting key in your code. For example, the following pattern allows the recognition of Ruby symbols as flag key usages: ```bash configcat scan --usage-patterns ":CC_KEY" ``` It will match the following usage: ```ruby if FeatureFlags.enabled(:my_feature_key) #... end ``` ### Aliases[​](#aliases "Direct link to Aliases") The found keys' context is examined for **aliases**, like variables, constants, or enumerations used to store these keys. **Aliases** are treated as indirect references and are included in the searching process. For example, the following `C#` constant's name (`MyAwesomeFeature`) will be recognized as an alias: ```csharp public static class FeatureFlagKeys { public const string MyAwesomeFeature = "my_awesome_feature"; } ``` The scanner will treat this constant's usage as an indirect reference to the flag. ```csharp if (await configCatClient.GetValueAsync(FeatureFlagKeys.MyAwesomeFeature, false)) { // the feature is on. } ``` info The alias recognition **adapts to the characteristics of different languages**.
For example, it can find aliases in `Go` constants/variable assignments: ```go const ( myAwesomeFeature string = "my_awesome_feature" ) myAwesomeFeature := "my_awesome_feature" ``` And in `Swift` enums/variable assignments as well: ```swift enum FlagKeys : String { case MyAwesomeFeature = "my_awesome_feature" } let myAwesomeFeature: String = "my_awesome_feature" ``` You can check [here](https://raw.githubusercontent.com/configcat/cli/main/test/ConfigCat.Cli.Tests/alias.txt) a bunch of other samples that we tested. info An alias must be at least **30% identical to the feature flag/setting key**. The similarity check is case insensitive and ignores `_` characters. This behavior prevents false recognitions in expressions like `` where `value` shouldn't be treated as alias. ### Custom alias match patterns[​](#custom-alias-match-patterns "Direct link to Custom alias match patterns") There's an option to set custom regex patterns for identifying additional aliases. The `scan` command accepts a list of patterns via the `--alias-patterns` argument. ```bash configcat scan --alias-patterns "" "" ``` The CLI also accepts patterns from the `CONFIGCAT_ALIAS_PATTERNS` environment variable as a comma delimited list. ```bash export CONFIGCAT_ALIAS_PATTERNS=","; ``` #### Match pattern format[​](#match-pattern-format "Direct link to Match pattern format") The regex pattern must include at least one capture group that represents the actual alias. When more than one group is defined, the first one is selected. To bind the actual flag keys to aliases, the CLI uses a `CC_KEY` placeholder to inject the known keys into the pattern. For example, the following pattern allows to find aliases that point to Ruby symbols: ```bash configcat scan --alias-patterns "(\w+) = client\.get_value\(:CC_KEY" ``` It will match to the following usage: ```ruby # 'my_feature_enabled' is now treated as an alias to the 'my_feature_key' flag. my_feature_enabled = client.get_value(:my_feature_key, false) ``` note The CLI implicitly adds the optional `` ` ``, `'`, `"` wrapping around flag keys, so you don't have to wrap the `CC_KEY` placeholder manually. For example, the pattern `(\w+) = CC_KEY` will either match to `alias = flag_key`, `alias = "flag_key"`, `alias = 'flag_key'`, or ``alias = `flag_key` ``. ### Wrappers[​](#wrappers "Direct link to Wrappers") In addition to aliases, the scanner also looks for different feature flag/setting key usage patterns. This helps to recognize functions and properties used to wrap direct ConfigCat SDK calls as indirect references. Aliases are also included in this search. For example, the scanner will treat the `IsMyAwesomeFeatureEnabled` function of the following `C#` wrapper class as an indirect reference: ```csharp public class FeatureFlagProvider { public async Task IsMyAwesomeFeatureEnabled(bool defaultValue = false) { return await configCatClient.GetValueAsync("my_awesome_feature", defaultValue); } } ``` And will include its usage in the scan report: ```csharp if (await featureFlagProvider.IsMyAwesomeFeatureEnabled()) { // the feature is on. } ``` info The scanner uses the following patterns to look for wrapper usages (case insensitive): * `[.|->|::]{settingKeyOrAlias}` * `[.|->|::]get{settingKeyOrAlias}` * `[.|->|::]is{settingKeyOrAlias}` * `[.|->|::]is{settingKeyOrAlias}enabled` Given the key/alias `my_awesome_feature`, the scanner will find any of the following usage examples: * `.my_awesome_feature` (also: `->my_awesome_feature` / `::my_awesome_feature`) * `.MY_AWESOME_FEATURE` (also: `->MY_AWESOME_FEATURE` / `::MY_AWESOME_FEATURE`) * `.get_my_awesome_feature` (also: `->get_my_awesome_feature` / `::get_my_awesome_feature`) * `.GET_MY_AWESOME_FEATURE` (also: `->GET_MY_AWESOME_FEATURE` / `::GET_MY_AWESOME_FEATURE`) * `.is_my_awesome_feature` (also: `->is_my_awesome_feature` / `::is_my_awesome_feature`) * `.is_my_awesome_feature_enabled` (also: `->is_my_awesome_feature_enabled` / `::is_my_awesome_feature_enabled`) * `.myAwesomeFeature` (also: `->myAwesomeFeature` / `::myAwesomeFeature`) * `.getMyAwesomeFeature` (also: `->getMyAwesomeFeature` / `::getMyAwesomeFeature`) * `.isMyAwesomeFeature` (also: `->isMyAwesomeFeature` / `::isMyAwesomeFeature`) * `.isMyAwesomeFeatureEnabled` (also: `->isMyAwesomeFeatureEnabled` / `::isMyAwesomeFeatureEnabled`) * `.IsMyAwesomeFeatureEnabled` (also: `->IsMyAwesomeFeatureEnabled` / `::IsMyAwesomeFeatureEnabled`) ## Upload Scan Reports[​](#upload-scan-reports "Direct link to Upload Scan Reports") You have the option to upload scan reports for each branch of your repository to ConfigCat. Each scan report is associated to one of these branches. The following screenshot shows how an uploaded report looks like. ![ConfigCat code references report](/docs/assets/cli/scan/scan_report.png) ### Scanning Git Repositories[​](#scanning-git-repositories "Direct link to Scanning Git Repositories") The `scan` command automatically detects when it's being executed on a git repository. It collects additional information from Git like the current **branch name**, the actual **commit hash**, and each active **remote branch**. These extra details are used to enrich the uploaded report on the ConfigCat Dashboard with links to your actual source code. info If you are not using Git as VCS, you have to set at least the `--branch` parameter of the `scan` command. ### Template URLs[​](#template-urls "Direct link to Template URLs") The `scan` command's `--file-url-template` and `--commit-url-template` parameters are used for generating links to your repository. Based on the information available during the scanning, the CLI replaces the corresponding template parameters to generate the actual links. * **File URL template**: Used to generate VCS file links.
Available template parameters: * `commitHash` * `filePath` * `lineNumber` With the following example template URL: `https://github.com/my/repo/blob/{commitHash}/{filePath}#L{lineNumber}`
For the file `src/example.js`, the result is: `https://github.com/my/repo/blob/4451d61b63a4b4499ed5c607be6c40ce9eeadb9c/src/example.js#L69` * **Commit URL template**: Used to generate VCS commit links.
Available template parameters: * `commitHash` With the following example template URL: `https://github.com/my/repo/commit/{commitHash}`
For the commit hash `4451d61b63a4b4499ed5c607be6c40ce9eeadb9c`, the result is: `https://github.com/my/repo/commit/4451d61b63a4b4499ed5c607be6c40ce9eeadb9c` info When these template URLs are not set, the uploaded report will not contain VCS links. ### Stale Branches[​](#stale-branches "Direct link to Stale Branches") When the scan is executed on a Git repository, the CLI attaches the currently active remote branches to the uploaded report. This information is used for cleaning up each stale report that belongs to a deleted branch. ### CI/CD Integrations[​](#cicd-integrations "Direct link to CI/CD Integrations") We prepared the following integrations to simplify the usage of the scanner in your CI/CD workflow: * [GitHub Action](https://configcat.com/docs/advanced/code-references/github-action.md) * [CircleCI Orb](https://configcat.com/docs/advanced/code-references/circleci-orb.md) * [GitLab CI/CD](https://configcat.com/docs/advanced/code-references/gitlab-ci.md) * [Azure DevOps](https://configcat.com/docs/advanced/code-references/azure-devops.md) * [Bitbucket Pipe](https://configcat.com/docs/advanced/code-references/bitbucket-pipe.md) * [Bitrise Step](https://configcat.com/docs/advanced/code-references/bitrise-step.md) ### Manual Integration[​](#manual-integration "Direct link to Manual Integration") If your workflow doesn't have an integration, you can follow the instructions [here](https://configcat.com/docs/advanced/code-references/manual.md) to set scan executions directly with the ConfigCat CLI. ## Ignore Files[​](#ignore-files "Direct link to Ignore Files") The `scan` command respects all include and exclude patterns listed inside `.gitignore` and `.ignore` files within the scanned directory. In addition, you can create an extra `.ccignore` file with patterns that the scanner must take into account. Each pattern must follow the [gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format). --- # Source: https://configcat.com/docs/targeting/percentage-options.md # Percentage Options Copy page ## What are Percentage Options?[​](#what-are-percentage-options "Direct link to What are Percentage Options?") Using *Percentage Options*, you can define that a certain percentage of users should receive a specific value. This way, you can gradually release a new feature to a subset of users. Instead of releasing a feature to all users simultaneously, a specific percentage of users are selected to receive access to the feature. This allows developers to control and monitor the impact of the new feature in a controlled manner. ## How to add Percentage Options?[​](#how-to-add-percentage-options "Direct link to How to add Percentage Options?") You can add Percentage Options to a feature flag by clicking the **+%** button on the Dashboard. ![Add percentage options](/docs/assets/targeting/percentage-options/add-percentage-options_192dpi.png) ## How does it work? - Anatomy of Percentage Options[​](#how-does-it-work---anatomy-of-percentage-options "Direct link to How does it work? - Anatomy of Percentage Options") Percentage Options is a list of *% value* and *served value* pairs, where % values add up to 100. It divides users into groups according to the percentage split defined by the % values. The grouping is random and based on the [Percentage Evaluation Attribute](#percentage-evaluation-attribute). By default, this is the [User Object's](https://configcat.com/docs/targeting/user-object.md) **Identifier** attribute. However, you can use any other user attribute as the basis of the grouping. info If the Percentage Evaluation Attribute is not present in the [User Object](https://configcat.com/docs/targeting/user-object.md), the ["To unidentified" value](https://configcat.com/docs/targeting/targeting-overview.md#to-all-users--to-all-other--to-unidentified-value) will be returned. (Read more about the feature flag evaluation algorithm [here](https://configcat.com/docs/targeting/feature-flag-evaluation.md).) Percentage Options are designed to be [sticky](#stickiness) and [consistent](#consistency) across all SDKs, ensuring a reliable experience. ### % value[​](#-value "Direct link to % value") Any number between 0 and 100 that represents a randomly allocated group of your users. ### Served value[​](#served-value "Direct link to Served value") The value to return when the user falls into the group determined by the % value. ### Number of Percentage Options[​](#number-of-percentage-options "Direct link to Number of Percentage Options") In the case of a feature flag (boolean setting), there must be two options. One for the **ON** and one for the **OFF** state. In the case of a string, integer or double setting, the maximum number of options [depends on your subscription plan](https://configcat.com/docs/subscription-plan-limits.md). You can add options by clicking the **+% OPTION** button. ## Percentage Options within Targeting Rules[​](#percentage-options-within-targeting-rules "Direct link to Percentage Options within Targeting Rules") Percentage Options can be used in combination with Targeting Rules. In this case, the Percentage Options will be evaluated only if the Targeting Rule matches. In other words, the Percentage Options apply only to the users that matched the Targeting Rule. info If the Percentage Evaluation Attribute is not present in the [User Object](https://configcat.com/docs/targeting/user-object.md), the targeting rule will be skipped - despite the matching Targeting Rule. Read more about the feature flag evaluation algorithm [here](https://configcat.com/docs/targeting/feature-flag-evaluation.md). ![Percentage options within targeting rules](/docs/assets/targeting/percentage-options/percentage-options-within-targeting-rule_192dpi.png) ## Percentage Evaluation Attribute[​](#percentage-evaluation-attribute "Direct link to Percentage Evaluation Attribute") The *Percentage Evaluation Attribute* (sometimes called *percentage attribute*) is the user attribute by which users are grouped. By default, it is the [User Object's](https://configcat.com/docs/targeting/user-object.md) **Identifier** attribute. However, you can use any other user attribute as the basis of the grouping (see the example use case [below](#percentage-options-based-on-other-user-attributes)). ### How to change the Percentage Evaluation Attribute?[​](#how-to-change-the-percentage-evaluation-attribute "Direct link to How to change the Percentage Evaluation Attribute?") In the top right corner of the feature flag, open the kebab (3 dots) menu and choose the **Change percentage attribute** item. info The selected Percentage Evaluation Attribute applies to all Percentage Options within the feature flag - but only in the current ConfigCat environment. ![Change percentage attribute](/docs/assets/targeting/percentage-options/change-percentage-attribute_192dpi.png) ## Stickiness[​](#stickiness "Direct link to Stickiness") *Stickiness* means that the same user will always get the same value for the same percentage split in the case of a specific feature flag, regardless of the history of the feature flag. This is achieved by implementing a deterministic hashing algorithm based on the feature flag's key and the Percentage Evaluation Attribute. For example, if you have a feature flag with a Percentage Option of **20% ON**, then you change the Percentage Option to **40% ON**, and then back to **20% ON**, the same 20% of users will get the **ON** value for the feature flag just like the first time. For a demonstration of this concept, see this [example scenario](https://configcat.com/docs/targeting/feature-flag-evaluation.md#example-scenarios-for-percentage-options). ## Consistency[​](#consistency "Direct link to Consistency") *Consistency* means that the same user will always get the same value for the same percentage split in the case of a specific feature flag, no matter which SDK is used. This is achieved by using the same hashing algorithm across all SDKs. For example, if you have a feature flag with a Percentage Option of **20% ON**, then the same 20% of users will get the **ON** value across all SDKs. No matter if a user is on iOS, Android, or Web, they will always get the same value for the feature flag. ## Randomness[​](#randomness "Direct link to Randomness") The same user might get different values for the same percentage split in the case of different feature flags. This is because the hashing algorithm is based on the combination of the feature flag's key and the Percentage Evaluation Attribute. Since feature flag keys are unique, the resulting hashes will usually be different as well. For example, if you have two feature flags with Percentage Options of **20% ON**, then a different 20% of users will get the **ON** value for each feature flag. ## Examples[​](#examples "Direct link to Examples") ### Simple phased rollout / Canary release / Percentage rollout scenario[​](#simple-phased-rollout--canary-release--percentage-rollout-scenario "Direct link to Simple phased rollout / Canary release / Percentage rollout scenario") #### Context[​](#context "Direct link to Context") Our demo company, Whisker Co. is about to release a new feature called **Park Weather Info**. The stakeholders want to make sure that the new feature is received well by the customers. #### Goal[​](#goal "Direct link to Goal") To get some feedback from our customers before releasing it to everyone, we initially want to make the feature available to 20% of the customers only. #### Solution[​](#solution "Direct link to Solution") Let's create a feature flag called **Enable Park Weather Info** with Percentage Options set to **20% ON** and **80% OFF**. ![Simple phased rollout example](/docs/assets/targeting/percentage-options/simple-phased-rollout-example_192dpi.png) ### A/B/n testing scenario[​](#abn-testing-scenario "Direct link to A/B/n testing scenario") #### Context[​](#context-1 "Direct link to Context") The marketing specialists at Whisker Co. want to introduce a discount strategy to boost webshop purchases. They have several ideas but lack the statistical data needed to determine which would be most effective. #### Goal[​](#goal-1 "Direct link to Goal") To learn which is the most effective discount strategy, we want to perform an A/B/C test. #### Solution[​](#solution-1 "Direct link to Solution") We need a string or integer setting for this task because we need to represent 3 different variations. Let's create a string setting named **Discount Type** (as textual values tell more than numbers). The go-to feature for A/B testing is Percentage Options. So let's add one with 3 options, each covering 1/3rd of our customers. ![A/B/n testing example](/docs/assets/targeting/percentage-options/abn-testing-example_192dpi.png) info To make all this useful, that is, to measure the effectiveness of the different strategies, we also need to integrate with an analytics service like [Amplitude](https://configcat.com/docs/integrations/amplitude.md) or [Mixpanel](https://configcat.com/docs/integrations/mixpanel.md) and update our application to send feature flag evaluation results to it. ### Complex phased rollout / Canary release / Percentage rollout scenario[​](#complex-phased-rollout--canary-release--percentage-rollout-scenario "Direct link to Complex phased rollout / Canary release / Percentage rollout scenario") #### Context[​](#context-2 "Direct link to Context") Whisker Co. is about to release a new feature called **Park Weather Info**. The stakeholders want to make sure that the release of the new feature goes smoothly and it is received well by the customers. #### Goal[​](#goal-2 "Direct link to Goal") To do some in-house testing and also get some feedback from our customers before releasing it to everyone, we initially want to make the feature available to the employees and to 20% of the customers only. #### Solution[​](#solution-2 "Direct link to Solution") Let's create a feature flag called **Enable Park Weather Info** with a Targeting Rule that matches the employees at Whisker Co. and Percentage Options set to **20% ON** and **80% OFF** for the rest of the users (i.e. for the customers). ![Complex phased rollout example](/docs/assets/targeting/percentage-options/complex-phased-rollout-example_192dpi.png) ### Platform-specific phased rollout[​](#platform-specific-phased-rollout "Direct link to Platform-specific phased rollout") #### Context[​](#context-3 "Direct link to Context") Whisker Co. is about to release a new feature called **Cafe Notifications** in their mobile app, which has an Android and an iOS version. We know that the userbase of the iOS app is much larger than the Android app. The stakeholders want to make sure that the new feature is received well by the customers. #### Goal[​](#goal-3 "Direct link to Goal") To get some feedback from our customers before releasing it to everyone, we initially want to make the feature available to a limited number of customers only. We also want to release the feature to roughly the same number of Android and iOS users. #### Solution[​](#solution-3 "Direct link to Solution") Let's create a feature flag called **Cafe Notifications** with two Targeting Rules: one that matches Android users and one that matches iOS users. Then change the THEN part of both to Percentage Options. Finally, let's set the percentages so that the feature is enabled for roughly the same number of users (e.g. 60% for Android users, 20% for iOS users). ![Platform-specific phased rollout example](/docs/assets/targeting/percentage-options/platform-specific-phased-rollout-example_192dpi.png) ### Percentage Options based on other user attributes[​](#percentage-options-based-on-other-user-attributes "Direct link to Percentage Options based on other user attributes") #### Context[​](#context-4 "Direct link to Context") Let's imagine that at Whisker Co., we have a custom attribute named **Tenant ID** that is used to identify the tenants of our customers. #### Goal[​](#goal-4 "Direct link to Goal") We want to release a new feature, **Park Weather Info**, to 20% of our customers based on their **Tenant ID**. #### Solution[​](#solution-4 "Direct link to Solution") Let's create a feature flag called **Enable Park Weather Info** with Percentage Options set to **20% ON** and **80% OFF**. Finally, let's set the Percentage Evaluation Attribute to **Tenant ID** as described [here](#percentage-evaluation-attribute). ![Custom percentage attribute example](/docs/assets/targeting/percentage-options/custom-percentage-attribute-example_192dpi.png) --- # Source: https://configcat.com/docs/api/reference/permission-groups.md # Permission Groups Copy page With these endpoints you can manage your Permission Groups. [Here](https://configcat.com/docs/advanced/team-management/team-management-basics.md) you can read more about Permissions. ## [📄️ List Permission Groups](https://configcat.com/docs/api/reference/get-permission-groups.md) [This endpoint returns the list of the Permission Groups that belongs to the given Product identified by the](https://configcat.com/docs/api/reference/get-permission-groups.md) ## [📄️ Create Permission Group](https://configcat.com/docs/api/reference/create-permission-group.md) [This endpoint creates a new Permission Group in a specified Product](https://configcat.com/docs/api/reference/create-permission-group.md) ## [📄️ Get Permission Group](https://configcat.com/docs/api/reference/get-permission-group.md) [This endpoint returns the metadata of a Permission Group](https://configcat.com/docs/api/reference/get-permission-group.md) ## [📄️ Update Permission Group](https://configcat.com/docs/api/reference/update-permission-group.md) [This endpoint updates a Permission Group identified by the \`permissionGroupId\` parameter.](https://configcat.com/docs/api/reference/update-permission-group.md) ## [📄️ Delete Permission Group](https://configcat.com/docs/api/reference/delete-permission-group.md) [This endpoint removes a Permission Group identified by the \`permissionGroupId\` parameter.](https://configcat.com/docs/api/reference/delete-permission-group.md) --- # Source: https://configcat.com/docs/sdk-reference/php.md # Source: https://configcat.com/docs/sdk-reference/openfeature/php.md # OpenFeature Provider for PHP Copy page [![Build Status](https://github.com/configcat/openfeature-php/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/configcat/openfeature-php/actions/workflows/ci.yml) [![Latest Stable Version](https://poser.pugx.org/configcat/openfeature-provider/version)](https://packagist.org/packages/configcat/openfeature-provider) [![Total Downloads](https://poser.pugx.org/configcat/openfeature-provider/downloads)](https://packagist.org/packages/configcat/openfeature-provider) [ConfigCat OpenFeature Provider for PHP on GitHub](https://github.com/configcat/openfeature-php) ## Requirements[​](#requirements "Direct link to Requirements") * PHP >= 8.1 ## Getting started[​](#getting-started "Direct link to Getting started") ### 1. Install the provider with [Composer](https://getcomposer.org/)[​](#1-install-the-provider-with-composer "Direct link to 1-install-the-provider-with-composer") ```bash composer require configcat/openfeature-provider ``` ### 2. Initialize the provider[​](#2-initialize-the-provider "Direct link to 2. Initialize the provider") The `ConfigCatProvider` constructor takes the SDK key and an optional `array` argument containing the additional configuration options for the [ConfigCat PHP SDK](https://configcat.com/docs/sdk-reference/php.md#creating-the-configcat-client): ```php use ConfigCat\ClientOptions; use ConfigCat\Log\LogLevel; use ConfigCat\OpenFeature\ConfigCatProvider; use OpenFeature\implementation\flags\Attributes; use OpenFeature\implementation\flags\EvaluationContext; use OpenFeature\OpenFeatureAPI; // Acquire an OpenFeature API instance. $api = OpenFeatureAPI::getInstance(); // Build options for the ConfigCat SDK. $options = [ ClientOptions::LOG_LEVEL => LogLevel::WARNING, ClientOptions::CACHE_REFRESH_INTERVAL => 5, //... ]; // Configure the provider. $api->setProvider(new ConfigCatProvider('#YOUR-SDK-KEY#', $options)); // Create a client. $client = $api->getClient(); ``` For more information about all the configuration options, see the [PHP SDK documentation](https://configcat.com/docs/sdk-reference/php.md#creating-the-configcat-client). ### 3. Evaluate your feature flag[​](#3-evaluate-your-feature-flag "Direct link to 3. Evaluate your feature flag") ```php $isAwesomeFeatureEnabled = $client->getBooleanValue('isAwesomeFeatureEnabled', false); if (is_bool($isAwesomeFeatureEnabled) && $isAwesomeFeatureEnabled) { doTheNewThing(); } else { doTheOldThing(); } ``` ## Evaluation Context[​](#evaluation-context "Direct link to Evaluation Context") An [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context) in the OpenFeature specification is a container for arbitrary contextual data that can be used as a basis for feature flag evaluation. The ConfigCat provider translates these evaluation contexts to ConfigCat [User Objects](https://configcat.com/docs/sdk-reference/php.md#user-object). The following table shows how the different context attributes are mapped to User Object attributes. | Evaluation context | User Object | Required | | ------------------ | ------------ | -------- | | `targetingKey` | `identifier` | ☑ | | `Email` | `email` | | | `Country` | `country` | | | Any other | `custom` | | To evaluate feature flags for a context, use the [OpenFeature Evaluation API](https://openfeature.dev/docs/reference/concepts/evaluation-api/): ```php $context = new EvaluationContext('#SOME-USER-ID#', new Attributes([ 'Email' => 'configcat@example.com', 'Country' => 'CountryID', 'Rating' => 4.5, 'RegisteredAt' => new DateTimeImmutable('2023-11-22T12:34:56.0000000Z'), 'Roles' => ['Role1', 'Role2'] ])); $isAwesomeFeatureEnabled = $client->getBooleanValue('isAwesomeFeatureEnabled', false, $context); ``` ## Look under the hood[​](#look-under-the-hood "Direct link to Look under the hood") * [Sample PHP App](https://github.com/configcat/openfeature-php/tree/main/samples/ConfigCatProvider) * [ConfigCat OpenFeature Provider's repository on GitHub](https://github.com/configcat/php-openfeature) * [ConfigCat OpenFeature Provider on packagist.org](https://packagist.org/packages/configcat/openfeature-provider) --- # Source: https://configcat.com/docs/api/reference/post-setting-values-v-2.md # Post values Copy page This endpoint batch updates the Feature Flags and Settings of a Config identified by the `configId` parameter in a specified Environment identified by the `environmentId` parameter. Only those Feature Flags and Settings are updated which are part of the request, all the others are left untouched. **Important:** As this endpoint is doing a complete replace on those Feature Flags and Settings, which are set in the request. It's important to set every other field that you don't want to change in its original state. Not listing a field means that it will reset. For example: We have the following resource of a Feature Flag. ```json { "settingFormulas": [ { "defaultValue": { "boolValue": false }, "targetingRules": [ { "conditions": [ { "userCondition": { "comparisonAttribute": "Email", "comparator": "sensitiveTextEquals", "comparisonValue": { "stringValue": "test@example.com" } } } ], "percentageOptions": [], "value": { "boolValue": true } } ], "settingId": 1 } ] } ``` If we send a batch replace request body as below: ```json { "updateFormulas": [ { "defaultValue": { "boolValue": false }, "settingId": 1 } ] } ``` Then besides that the default value is set to `true`, all Targeting Rules of the related Feature Flag are deleted. So we get a response like this: ```json { "settingFormulas": [ { "defaultValue": { "boolValue": false }, "targetingRules": [], "setting": { "settingId": 1 } } ] } ``` ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the updated setting values returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/api/reference/post-setting-values.md # Post values Copy page This endpoint replaces the values of a specified Config's Feature Flags or Settings identified by the `configId` parameter in a specified Environment identified by the `environmentId` parameter. Only the `value`, `rolloutRules` and `percentageRules` attributes are modifiable by this endpoint. **Important:** As this endpoint is doing a complete replace, it's important to set every other attribute that you don't want to change in its original state. Not listing one means it will reset. For example: We have the following resource. ```json { "settingValues": [ { "rolloutPercentageItems": [ { "percentage": 30, "value": true }, { "percentage": 70, "value": false } ], "rolloutRules": [], "value": false, "settingId": 1 } ] } ``` If we send a replace request body as below: ```json { "settingValues": [ { "value": true, "settingId": 1 } ] } ``` Then besides that the default value is set to `true`, all the Percentage Rules are deleted. So we get a response like this: ```json { "settingValues": [ { "rolloutPercentageItems": [], "rolloutRules": [], "value": true, "setting": { "settingId": 1 } } ] } ``` The `rolloutRules` property describes two types of rules: * **Targeting rules**: When you want to add or update a targeting rule, the `comparator`, `comparisonAttribute`, and `comparisonValue` members are required. * **Segment rules**: When you want to add add or update a segment rule, the `segmentId` which identifies the desired segment and the `segmentComparator` members are required. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 * 400 * 404 * 429 When everything is ok, the updated setting values returned. Bad request. Not found. Too many requests. In case of the request rate exceeds the rate limits. --- # Source: https://configcat.com/docs/glossary/product-lifecycle-manager.md # Product Lifecycle Manager – Steering Projects to Success Copy page ## Introduction[​](#introduction "Direct link to Introduction") In the dynamic world of product development, the trajectory from an idea to a market-ready product is intricate and layered with challenges. A Product Lifecycle Manager is the maestro of this journey, synchronizing each movement to create a symphony of efficiency and success. Dive into the role of these pivotal professionals and how they are integral to a product's evolution. ## Who is a Product Lifecycle Manager?[​](#who-is-a-product-lifecycle-manager "Direct link to Who is a Product Lifecycle Manager?") A Product Lifecycle Manager is a strategic orchestrator responsible for overseeing the progression of a product through its lifecycle. They are the guardians of the project timeline, ensuring that every stage, from conception to release, adheres to the planned schedule and quality standards. ## Responsibilities of a Product Lifecycle Manager[​](#responsibilities-of-a-product-lifecycle-manager "Direct link to Responsibilities of a Product Lifecycle Manager") * **Strategic Planning**: Crafting a comprehensive plan that outlines each stage of the product's lifecycle. * **Team Coordination**: Leading and motivating the project team to achieve the set objectives. * **Milestone Tracking**: Monitoring the progress and ensuring that key deliverables are met on time. * **Quality Assurance**: Upholding the highest standards of quality at each phase of the product's development. * **Risk Management**: Identifying potential issues and implementing strategies to mitigate risks. ## The Lifecycle of a Product[​](#the-lifecycle-of-a-product "Direct link to The Lifecycle of a Product") * **Conceptualization**: Ideation and initial planning of the product's vision. * **Development**: Transforming the concept into a tangible prototype or early version. * **Testing**: Rigorous evaluation to refine the product and prepare it for market. * **Launch**: Introducing the product to the market with strategic marketing and distribution. * **Evaluation**: Analyzing the product's performance and gathering feedback for improvement. ## The Impact of a Product Lifecycle Manager[​](#the-impact-of-a-product-lifecycle-manager "Direct link to The Impact of a Product Lifecycle Manager") * **Project Efficiency**: Streamlining processes to minimize waste and optimize resources. * **Timely Delivery**: Ensuring that products are developed and launched within the expected timelines. * **Market Relevance**: Keeping the product aligned with market needs and consumer expectations. * **Continuous Improvement**: Leveraging feedback for ongoing product enhancement and evolution. ## Conclusion[​](#conclusion "Direct link to Conclusion") The role of a Product Lifecycle Manager is indispensable in navigating the complex waters of product development. With their expertise, products don't just reach completion; they do so with a competitive edge and in alignment with market demands. They ensure that the lifecycle of a project is not just a passage of time but a curated path towards excellence. --- # Source: https://configcat.com/docs/api/reference/products.md # Products Copy page With these endpoints you can manage your Products. By gathering the right `productId`, you can also manage [Environments](https://configcat.com/docs/api/reference/environments.md), [Configs](https://configcat.com/docs/api/reference/configs.md), [Tags](https://configcat.com/docs/api/reference/tags.md), [Webhooks](https://configcat.com/docs/api/reference/webhooks.md), and [Permission Groups](https://configcat.com/docs/api/reference/permission-groups.md) through the API. [Here](https://configcat.com/docs/main-concepts.md#product) you can read more about the concept of Products. ## [📄️ List Products](https://configcat.com/docs/api/reference/get-products.md) [This endpoint returns the list of the Products that belongs to the user.](https://configcat.com/docs/api/reference/get-products.md) ## [📄️ Get Product](https://configcat.com/docs/api/reference/get-product.md) [This endpoint returns the metadata of a Product](https://configcat.com/docs/api/reference/get-product.md) ## [📄️ Update Product](https://configcat.com/docs/api/reference/update-product.md) [This endpoint updates a Product identified by the \`productId\` parameter.](https://configcat.com/docs/api/reference/update-product.md) ## [📄️ Delete Product](https://configcat.com/docs/api/reference/delete-product.md) [This endpoint removes a Product identified by the \`productId\` parameter.](https://configcat.com/docs/api/reference/delete-product.md) ## [📄️ Get Product Preferences](https://configcat.com/docs/api/reference/get-product-preferences.md) [This endpoint returns the preferences of a Product](https://configcat.com/docs/api/reference/get-product-preferences.md) ## [📄️ Update Product Preferences](https://configcat.com/docs/api/reference/update-product-preferences.md) [This endpoint updates the preferences of a Product identified by the \`productId\` parameter.](https://configcat.com/docs/api/reference/update-product-preferences.md) ## [📄️ Create Product](https://configcat.com/docs/api/reference/create-product.md) [This endpoint creates a new Product in a specified Organization](https://configcat.com/docs/api/reference/create-product.md) --- # Source: https://configcat.com/docs/advanced/proxy/proxy-overview.md # ConfigCat Proxy Copy page The [ConfigCat Proxy](https://github.com/configcat/configcat-proxy) allows you to host a feature flag evaluation service in your own infrastructure. It's a small Go application that communicates with ConfigCat's CDN network and caches/proxies *config JSON* files for your frontend and backend applications. The *config JSON* contains all the data that is needed for ConfigCat SDKs to evaluate feature flags. The Proxy provides the following: * **Performance**: The Proxy can be deployed close to your applications and can serve the downloaded *config JSON* files from memory. ConfigCat SDKs then can operate on the [proxied *config JSON*](https://configcat.com/docs/advanced/proxy/endpoints.md#cdn-proxy). This can reduce the duration of feature flag evaluation for stateless or short lived applications. * **Reliability**: The Proxy can store the downloaded *config JSON* files in an external [cache](#cache). It can fall back to operating on the cached *config JSON* if the ConfigCat CDN network becomes inaccessible. * **Security**: The Proxy can act as a [server side flag evaluation](https://configcat.com/docs/advanced/proxy/endpoints.md#api) component. Using it like that can prevent the exposure of *config JSON* files to frontend and mobile applications. * **Scalability**: Horizontal scaling allows you to align with the load coming from your applications accordingly. * **Streaming**: The Proxy provides real-time feature flag change notifications via [Server-Sent Events (SSE)](https://configcat.com/docs/advanced/proxy/endpoints.md#sse) and [gRPC](https://configcat.com/docs/advanced/proxy/grpc.md). ## Architecture[​](#architecture "Direct link to Architecture") The following diagram shows the high level architecture of the Proxy. ![High level Proxy architecture](/docs/assets/proxy/proxy_arch.png) ### How It Works[​](#how-it-works "Direct link to How It Works") The Proxy wraps one or more SDK instances for handling feature flag evaluation requests. It also serves the related *config JSON* files that can be consumed by other ConfigCat SDKs running in your applications. Within the Proxy, the underlying SDK instances can run in the following modes: * **Online**: In this mode, the underlying SDK has an active connection to the ConfigCat CDN network through the internet. * **Offline**: In [this mode](#offline-mode), the underlying SDK doesn't have an active connection to ConfigCat. Instead, it uses the configured cache or a file as a source of its *config JSON*. With the combination of the above modes, you can construct a cluster of proxies where only one node is responsible for the communication with ConfigCat, and all the other nodes are working from a central cache. ![Load balanced Proxy architecture](/docs/assets/proxy/load_balanced.png) ### Communication[​](#communication "Direct link to Communication") There are three ways how the Proxy is informed about the availability of new feature flag evaluation data: * **Polling**: The ConfigCat SDKs within the Proxy are regularly polling the ConfigCat CDN for new *config JSON* versions. * **Webhook**: The Proxy has [webhook endpoints](https://configcat.com/docs/advanced/proxy/endpoints.md#webhook) (for each underlying SDK) which can be set on the [ConfigCat Dashboard](https://app.configcat.com/product/webhooks) to be invoked when someone saves & publishes new feature flag changes. * **Cache polling / file watching**: In [offline mode](#offline-mode), the Proxy can regularly poll a cache or watch a file for new *config JSON* versions. These are the ports used by the Proxy by default: * **8050**: for standard HTTP communication. ([API](https://configcat.com/docs/advanced/proxy/endpoints.md#api), [CDN proxy](https://configcat.com/docs/advanced/proxy/endpoints.md#cdn-proxy), [Webhook](https://configcat.com/docs/advanced/proxy/endpoints.md#webhook), [SSE](https://configcat.com/docs/advanced/proxy/endpoints.md#sse)) * **8051**: for providing diagnostic data ([status](https://configcat.com/docs/advanced/proxy/monitoring.md#status), [prometheus metrics](https://configcat.com/docs/advanced/proxy/monitoring.md#prometheus-metrics)). * **50051**: for [gRPC](https://configcat.com/docs/advanced/proxy/grpc.md) communication. ## Installation[​](#installation "Direct link to Installation") You can install the ConfigCat Proxy from the following sources: **Docker** The docker image is available on DockerHub. You can run the image either as a standalone docker container or via `docker-compose`. * Standalone * docker-compose Pull the docker image: ```shell docker pull configcat/proxy ``` Run the ConfigCat Proxy: ```shell docker run -d --name configcat-proxy \ -p 8050:8050 -p 8051:8051 -p 50051:50051 \ -e CONFIGCAT_SDKS='{"":""}' \ configcat/proxy ``` docker-compose.yml ```yaml services: configcat_proxy: image: configcat/proxy environment: - CONFIGCAT_SDKS={"":""} ports: - "8050:8050" - "8051:8051" - "50051:50051" ``` To start docker services, execute the following command: ```shell docker-compose up -f docker-compose.yml -d ``` **Standalone executable** You can download the executables directly from [GitHub Releases](https://github.com/configcat/configcat-proxy/releases) for your desired platform. You can then check the [status endpoint](https://configcat.com/docs/advanced/proxy/monitoring.md#status) of the Proxy to ensure it's working correctly: `http://localhost:8051/status` ## Usage Scenarios[​](#usage-scenarios "Direct link to Usage Scenarios") This section describes the possible ways of how you can use the Proxy from your application. You can decide where you want the actual feature flag evaluation to happen. * **Local evaluation**: Feature flags are evaluated by a ConfigCat SDK running in your application. The Proxy only provides the data required for the evaluation process. * **Remote evaluation**: Feature flags are evaluated within the Proxy, your application only gets the result of the evaluation process. ### 1. Local evaluation using a ConfigCat SDK connected to the Proxy[​](#1-local-evaluation-using-a-configcat-sdk-connected-to-the-proxy "Direct link to 1. Local evaluation using a ConfigCat SDK connected to the Proxy") The Proxy has the ability to forward all information required for feature flag evaluation to ConfigCat SDKs via its [CDN proxy](https://configcat.com/docs/advanced/proxy/endpoints.md#cdn-proxy) endpoint. This means that you can set up your ConfigCat SDK instances to use the Proxy as their data source. To do this, you have to set the SDK's `baseUrl` option to the Proxy's host. example.js (Initializing the ConfigCat JS SDK to use the Proxy with SDK Key) ```js import * as configcat from "@configcat/sdk"; const configCatClient = configcat.getClient( "#YOUR-SDK-KEY#", configcat.PollingMode.AutoPoll, { baseUrl: "http://localhost:8050" } // Proxy URL ); ``` Additionally, as the Proxy maps [unique identifiers to each configured SDK key](#sdk-identifier--sdk-key) it works with, you can use that identifier prefixed with `configcat-proxy/` as the SDK key at the ConfigCat SDK's initialization. example.js (Initializing the ConfigCat JS SDK to use the Proxy with SDK identifier) ```js import * as configcat from "@configcat/sdk"; var configCatClient = configcat.getClient( "configcat-proxy/#SDK-IDENTIFIER#", // SDK identifier prefixed with 'configcat-proxy/' configcat.PollingMode.AutoPoll, { baseUrl: "http://localhost:8050" } // Proxy URL ); ``` ### 2. Remote evaluation with the Proxy's API endpoints[​](#2-remote-evaluation-with-the-proxys-api-endpoints "Direct link to 2. Remote evaluation with the Proxy's API endpoints") You can leverage the Proxy's server side feature flag evaluation feature by sending simple HTTP requests to the Proxy's API endpoints. example.js (Evaluating a feature flag with API using SDK key) ```js const url = "http://localhost:8050/api/eval"; // Proxy API URL with SDK identifier const data = { key: "isMyAwesomeFeatureEnabled", // Feature flag key user: { // User Object for evaluation Identifier: "#UNIQUE-USER-IDENTIFIER#" } }; const requestOptions = { method: "POST", headers: { "X-ConfigCat-SdkKey": "#YOUR-SDK-KEY#", "Content-Type": "application/json", }, body: JSON.stringify(data), }; try { const response = await fetch(url, requestOptions); const responseData = await response.json(); console.log(responseData); // {"value":,"variationId":""} } catch (error) { console.error("Error:", error) } ``` Additionally, as the Proxy maps [unique identifiers to each configured SDK key](#sdk-identifier--sdk-key) it works with, you can use that identifier in the API endpoint's path instead of the SDK key header. example.js (Evaluating a feature flag with API using SDK identifier) ```js const url = "http://localhost:8050/api/#SDK-IDENTIFIER#/eval"; // Proxy API URL const data = { key: "isMyAwesomeFeatureEnabled", // Feature flag key user: { // User Object for evaluation Identifier: "#UNIQUE-USER-IDENTIFIER#" } }; const requestOptions = { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }; try { const response = await fetch(url, requestOptions); const responseData = await response.json(); console.log(responseData); // {"value":,"variationId":""} } catch (error) { console.error("Error:", error) } ``` You can find the available API endpoints with their HTTP request/response schemas [here](https://configcat.com/docs/advanced/proxy/endpoints.md#api). ### 3. Remote evaluation with OpenFeature Remote Evaluation Protocol (OFREP)[​](#3-remote-evaluation-with-openfeature-remote-evaluation-protocol-ofrep "Direct link to 3. Remote evaluation with OpenFeature Remote Evaluation Protocol (OFREP)") info OFREP compatibility is only available from Proxy version [`v2.0.0`](https://github.com/configcat/configcat-proxy/releases/tag/v2.0.0). info The OFREP feature of the Proxy is turned OFF by default, to use it, you have to turn it ON with the [OFREP endpoint options](https://configcat.com/docs/advanced/proxy/endpoints.md#available-options-2). The Proxy conforms to the [OpenFeature Remote Evaluation Protocol](https://github.com/open-feature/protocol), which means it can be used with OFREP compatible OpenFeature providers. example.js (Initializing the OFREP JS Web provider to use the Proxy with SDK key) ```js import { OpenFeature } from "@openfeature/web-sdk"; import { OFREPWebProvider } from '@openfeature/ofrep-web-provider'; OpenFeature.setProvider( new OFREPWebProvider({ baseUrl: "http://localhost:8050", // Proxy URL headers: [ ["X-ConfigCat-SdkKey", "#YOUR-SDK-KEY#"], ], }), ); ``` Additionally, as the Proxy maps [unique identifiers to each configured SDK key](#sdk-identifier--sdk-key) it works with, you can use that identifier in the `X-ConfigCat-SdkId` HTTP header. example.js (Initializing the OFREP JS Web provider to use the Proxy with SDK identifier) ```js import { OpenFeature } from "@openfeature/web-sdk"; import { OFREPWebProvider } from "@openfeature/ofrep-web-provider"; OpenFeature.setProvider( new OFREPWebProvider({ baseUrl: "http://localhost:8050", // Proxy URL headers: [ ["X-ConfigCat-SdkId", "#SDK-IDENTIFIER#"], ], }), ); ``` You can find the available OFREP endpoints with their HTTP request/response schemas [here](https://configcat.com/docs/advanced/proxy/endpoints.md#openfeature-remote-evaluation-protocol-ofrep). ### 4. Remote evaluation and streaming with SSE[​](#4-remote-evaluation-and-streaming-with-sse "Direct link to 4. Remote evaluation and streaming with SSE") The Proxy has the ability to evaluate feature flags and send notifications about subsequent evaluated flag value changes through [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) connections. example.js (Evaluating a feature flag and listening to changes with SDK key) ```js const rawData = { sdkKey: "#YOUR-SDK-KEY#", key: "isMyAwesomeFeatureEnabled", // Feature flag key user: { // User Object for evaluation Identifier: "#UNIQUE-USER-IDENTIFIER#" } } const data = btoa(JSON.stringify(rawData)) const url = "http://localhost:8050/sse/eval/k"; // Proxy SSE URL const evtSource = new EventSource(url + "/" + data); evtSource.onmessage = (event) => { console.log(event.data); // {"value":,"variationId":""} }; ``` Additionally, as the Proxy maps [unique identifiers to each configured SDK key](#sdk-identifier--sdk-key) it works with, you can use that identifier in the SSE endpoint's path. example.js (Evaluating a feature flag and listening to changes with SDK identifier) ```js const rawData = { key: "isMyAwesomeFeatureEnabled", // Feature flag key user: { // User Object for evaluation Identifier: "#UNIQUE-USER-IDENTIFIER#" } } const data = btoa(JSON.stringify(rawData)) const url = "http://localhost:8050/sse/#SDK-IDENTIFIER#/eval"; // Proxy SSE URL with SDK identifier const evtSource = new EventSource(url + "/" + data); evtSource.onmessage = (event) => { console.log(event.data); // {"value":,"variationId":""} }; ``` For more information and usage examples, see the related [SSE endpoints documentation](https://configcat.com/docs/advanced/proxy/endpoints.md#sse). ### 5. Remote evaluation and streaming with gRPC[​](#5-remote-evaluation-and-streaming-with-grpc "Direct link to 5. Remote evaluation and streaming with gRPC") The Proxy supports both unary feature flag evaluation RPCs and server streaming of evaluated flag value changes. For more information and usage examples, see the [gRPC section of this documentation](https://configcat.com/docs/advanced/proxy/grpc.md). ## Configuration Options[​](#configuration-options "Direct link to Configuration Options") You can specify options for the Proxy either via a YAML file or with environment variables. When an option is defined in both places, the environment variable's value takes precedence. By default, the Proxy reads the options YAML from the following default locations: * **Windows**: `%PROGRAMDATA%\configcat\proxy\options.yml`, usually `C:\ProgramData\configcat\proxy\options.yml` * **macOS**: `/Library/Application Support/configcat/proxy/options.yml` * **Linux**: `/etc/configcat/proxy/options.yml` When the default location is not suitable, you can specify a custom location for your options YAML file via the `-c` argument. * YAML * Environment variables **Docker** When running the Proxy in docker, you can mount the options YAML file as a volume. ```shell docker run -d --name configcat-proxy \ -p 8050:8050 -p 8051:8051 -p 50051:50051 \ -v /options.yml:/etc/configcat/proxy/options.yml ``` (Optional) With the `-c` argument to specify a custom path for your options YAML file: ```shell docker run -d --name configcat-proxy \ -p 8050:8050 -p 8051:8051 -p 50051:50051 \ -v /options.yml:/cnf/options.yml \ configcat/proxy -c /cnf/options.yml ``` **Standalone executable** Run the Proxy as a standalone executable with the options YAML file in its default location: * macOS / Linux * Windows ```shell ./configcat-proxy ``` ```powershell .\configcat-proxy.exe ``` (Optional) With the `-c` argument to specify a custom path for your options YAML file: * macOS / Linux * Windows ```shell ./configcat-proxy -c /path-to-file/options.yml ``` ```powershell .\configcat-proxy.exe -c \path-to-file\options.yml ``` **Docker** When running the Proxy in docker, you can pass environment variables to the executing container. ```shell docker run -d --name configcat-proxy \ -p 8050:8050 -p 8051:8051 -p 50051:50051 \ -e CONFIGCAT_SDKS='{"":""}' \ configcat/proxy ``` **Standalone executable** Make sure the related environment variables are available for the Proxy's hosting process. * shell * PowerShell ```shell export CONFIGCAT_SDKS='{"":""}' ``` Then start the Proxy: ```shell ./configcat-proxy ``` ```powershell $Env:CONFIGCAT_SDKS='{"":""}' ``` Then start the Proxy: ```powershell .\configcat-proxy.exe ``` The following sections will go through each available option in detail. ## How does the Proxy learn about feature flags?[​](#sdk "Direct link to How does the Proxy learn about feature flags?") In order to make the Proxy work properly, it must be set up with one or more [SDK keys](https://app.configcat.com/sdkkey). It creates one SDK instance per SDK key internally and uses those for feature flag evaluation. ### SDK Identifier[​](#sdk-identifier--sdk-key "Direct link to SDK Identifier") Within the Proxy, [SDK keys](https://app.configcat.com/sdkkey) are mapped to unique SDK identifiers. The *SDK key* identifies a config-environment pair and is used to configure an SDK instance to fetch the config JSON of that config-environment pair. The *SDK identifier* identifies an SDK instance running within the Proxy and configured to use the associated SDK key. That is, the SDK identifier is effectively an alias for the associated SDK key and is used in [endpoint routes](https://configcat.com/docs/advanced/proxy/endpoints.md) to avoid exposing the SDK Key. There are two ways to let the Proxy know which SDK Keys it should use: ### 1. Automatic configuration with Proxy profiles[​](#1-automatic-configuration-with-proxy-profiles "Direct link to 1. Automatic configuration with Proxy profiles") info **Beta Feature**: Automatic configuration with Proxy profiles is in public beta. We're now collecting feedback from real-world usage to fine-tune the experience. Share your feedback [here](https://configcat.com/support). info The automatic configuration with Proxy profiles feature is only available from Proxy version [`v2.0.0`](https://github.com/configcat/configcat-proxy/releases/tag/v2.0.0). The Proxy has the ability to use *Proxy profiles* to determine which SDK keys to download and distribute. It periodically checks for profile changes, allowing it to pick up the changes on the fly, without needing a restart. By using Proxy profiles, your deployed Proxy instances can detect and react to: * SDK key rotation. * Data governance change. * Product, config and environment state changes, such as creation, renaming and deletion. You can set up Proxy profiles under the `Manage organization` -> `Proxy Profiles` menu on the [ConfigCat Dashboard](https://app.configcat.com/organization/proxy-profiles). ![Proxy Profiles menu](/docs/assets/proxy/profile-menu.png)

To connect a Proxy instance to a Proxy profile, follow these steps: * #### Create a new Proxy profile[​](#create-a-new-proxy-profile "Direct link to Create a new Proxy profile") Click on the `+ ADD PROFILE` button. ![Add Profile](/docs/assets/proxy/profile-add2.png) Give the profile a meaningful name and description, then click `CREATE`. ![Create Profile](/docs/assets/proxy/profile-create2.png)

* #### Configure your Proxy instance[​](#configure-your-proxy-instance "Direct link to Configure your Proxy instance") Grab the `Key` and `Secret` from the profile creation dialog and put them into the Proxy's configuration. ![Configure Proxy with key and secret](/docs/assets/proxy/profile-key-secret2.png) * YAML * Environment variables options.yml ```yaml profile: key: secret: ``` ```shell CONFIGCAT_PROFILE_KEY="" CONFIGCAT_PROFILE_SECRET="" ```
* #### Select which SDK Keys your Proxy should use[​](#select-which-sdk-keys-your-proxy-should-use "Direct link to Select which SDK Keys your Proxy should use") Click on the edit icon in the `SDK Keys` column. ![Click on Select SDK Keys](/docs/assets/proxy/profile-sdk-keys-configure2.png) You can choose SDK Keys in two ways: by creating selection rules or by choosing individual SDK Keys manually. Your applications will have access to all feature flags in the config-environment pairs whose SDK Keys you select. * ##### Selection rules[​](#selection-rules "Direct link to Selection rules") With selection rules, you can describe which existing and future config-environment pairs should be distributed to Proxy instances. Rules can be based on products, configs and environments with the following filtering options: * **Exact** (by selecting an exact product, config or environment): This option filters for the ID of the selected product, config or environment. It's not sensitive to renaming. * **Any**: This option is similar to a single wildcard (`*`) expression. It filters for every product, config or environment. * **Match expression** (by selecting `Matches`): This option matches the given pattern to the name of products/configs/environments, accepting wildcards (`*`). It's sensitive to renaming. Whenever a config-environment pair matches both an **Include** and an **Exclude** rule, the **Exclude** rule will always take precedence. ![Select SDK Keys](/docs/assets/proxy/profile-selection-rules2.png)

* ##### Manual selection[​](#manual-selection "Direct link to Manual selection") You can manually select the config-environment pairs whose SDK key you want to make available for your Proxy instance. ![Select SDK Keys](/docs/assets/proxy/profile-sdk-keys-select2.png) info You can click config names in the first column to toggle all SDK keys in a row, or environment names in the column headers to toggle all SDK keys in a column.
* #### Locate SDK identifiers for the selected SDK Keys[​](#locate-sdk-identifiers-for-the-selected-sdk-keys "Direct link to Locate SDK identifiers for the selected SDK Keys") You can find the SDK identifiers generated for the selected config-environment pairs on the ConfigCat Dashboard right where you find their SDK Key. ![Click on view SDK identifiers for ConfigCat Proxy](/docs/assets/proxy/profile-sdk-ids-arrow.png) In the dialog that appears, you can find the SDK identifiers for the current config-environment pair, listed for each available Proxy profile. ![Click on view SDK identifiers for ConfigCat Proxy](/docs/assets/proxy/profile-sdk-ids-dialog.png)

* #### (Optional) Set up how your Proxy should learn about feature flag changes[​](#optional-set-up-how-your-proxy-should-learn-about-feature-flag-changes "Direct link to (Optional) Set up how your Proxy should learn about feature flag changes") There are two ways a Proxy can detect feature flag changes. Each config-environment pair identified by each SDK key is automatically monitored for changes by periodic polling of the corresponding config JSON file at a configured frequency. Besides polling, the Proxy can receive change notifications over HTTP, via its [webhook endpoint](https://configcat.com/docs/advanced/proxy/endpoints.md#webhook). * ##### Config JSON poll interval[​](#config-json-poll-interval "Direct link to Config JSON poll interval") You have the option to control how frequently the Proxy should poll for config JSON changes.
Click on the configure icon in the `Connection preferences` column, set the poll interval and click on `SAVE POLL INTERVAL`. ![Set config JSON poll interval](/docs/assets/proxy/profile-sdk-poll-interval2.png)

* ##### Webhook notification[​](#webhook-notification "Direct link to Webhook notification") You can set up automatic webhook notifications about feature flag changes for your Proxy by providing its public URL.
Click on the configure icon in the `Connection preferences` column and select `Webhook notification`. Then, enter your Proxy instance's public URL and click `ADD PROXY URL`. ![Set Proxy webhook URL](/docs/assets/proxy/profile-webhook-url2.png) Put the displayed webhook signing key(s) into your Proxy's configuration. Signing keys are for making sure that webhook requests received by your Proxy are sent by ConfigCat. Signatures are automatically [verified](https://configcat.com/docs/advanced/notifications-webhooks.md#verifying-webhook-requests) by the Proxy. ![Copy webhook signing key](/docs/assets/proxy/profile-webhook-signing-key2.png) * YAML * Environment variables options.yml ```yaml profile: webhook_signing_key: ``` ```shell CONFIGCAT_PROFILE_WEBHOOK_SIGNING_KEY="" ``` Test the connection to your Proxy instance. ![Test the webhook configuration](/docs/assets/proxy/profile-webhook-test2.png)

* #### All configuration options related to Proxy profiles[​](#all-configuration-options-related-to-proxy-profiles "Direct link to All configuration options related to Proxy profiles") | Option | Default | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | - YAML
- Environment variable```yaml profile: key: "" ``````shell CONFIGCAT_PROFILE_KEY="" ``` | - | The Proxy profile's key. | | - YAML
- Environment variable```yaml profile: secret: "" ``````shell CONFIGCAT_PROFILE_SECRET="" ``` | - | The Proxy profile's secret used by the Proxy to authenticate requests to the Public Management API. | | - YAML
- Environment variable```yaml profile: base_url: "" ``````shell CONFIGCAT_PROFILE_BASE_URL="" ``` | ConfigCat Public Management API URL | The base URL from where the Proxy should fetch the SDK Keys selected in the connected Proxy profile. | | - YAML
- Environment variable```yaml profile: poll_interval: 300 ``````shell CONFIGCAT_PROFILE_POLL_INTERVAL=300 ``` | 300 | The interval (in seconds) specifying how frequently the Proxy should poll for changes in the connected Proxy profile. | | - YAML
- Environment variable```yaml profile: webhook_signing_key: "" ``````shell CONFIGCAT_PROFILE_WEBHOOK_SIGNING_KEY="" ``` | - | The [key used to sign](https://configcat.com/docs/advanced/notifications-webhooks.md#calculating-signature) the webhook requests sent to the Proxy. [More about how to set up webhooks for a Proxy profile](#webhook-notification). | | - YAML
- Environment variable```yaml profile: webhook_signature_valid_for: 300 ``````shell CONFIGCAT_PROFILE_WEBHOOK_SIGNATURE_VALID_FOR=300 ``` | 300 | The time period (in seconds) within which webhook requests are considered valid. [More about how to set up webhooks for a Proxy profile](#webhook-notification). | | - YAML
- Environment variable```yaml profile: log: level: "" ``````shell CONFIGCAT_PROFILE_LOG_LEVEL="" ``` | `warn` | The verbosity level for Proxy profile-related logging.
Possible values: `error`, `warn`, `info`, or `debug`. | | - YAML
- Environment variable```yaml profile: sdks: base_url: "" ``````shell CONFIGCAT_PROFILE_SDKS_BASE_URL="" ``` | ConfigCat's CDN URL. | The CDN base URL (forward proxy, dedicated subscription) from where the ConfigCat SDKs should download the config JSON. | | - YAML
- Environment variable```yaml profile: sdks: log: level: "" ``````shell CONFIGCAT_PROFILE_SDKS_LOG_LEVEL="" ``` | `warn` | The verbosity level for logging performed by the ConfigCat SDKs spawned for the connected Proxy profile.
Possible values: `error`, `warn`, `info`, or `debug`. |
#### Profile caching[​](#profile-caching "Direct link to Profile caching") Proxy instances running in online mode are caching their connected profile if they have a [cache](#cache) configured. This means that other Proxy instances running with [global offline mode](#global-offline-mode) enabled can use those cached profiles from the same shared cache. info Offline Proxy instances only need the profile's `key` to read the connected profile from the cache, the `secret` option is not mandatory in this mode. ### 2. Manual configuration[​](#2-manual-configuration "Direct link to 2. Manual configuration") When using environment variables, the SDK keys can be specified as a JSON object, where the **property name is the SDK identifier** (the identifier of the config-environment pair whose SDK Key the underlying SDK instance is configured to use) and the **property value is the actual SDK key**. The **SDK identifier** part is later used in [endpoint routes](https://configcat.com/docs/advanced/proxy/endpoints.md) to recognize which SDK must serve the given flag evaluation request. Furthermore, when configuring the Proxy **via environment variables**, the identifier becomes a **part of the SDK specific environment variable's name** in the following format: `CONFIGCAT__