<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>ConfigCat Blog Blog</title>
        <link>https://configcat.com/blog/</link>
        <description>ConfigCat Blog Blog</description>
        <lastBuildDate>Fri, 06 Sep 2024 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>Copyright © 2024 ConfigCat.</copyright>
        <item>
            <title><![CDATA[Decision Makers vs. User Personas]]></title>
            <link>https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/</link>
            <guid>https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/</guid>
            <pubDate>Fri, 06 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Explore the dynamics between decision makers and user personas, and discover how they shape successful product development and marketing.]]></description>
            <content:encoded><![CDATA[<p>In business and marketing, decision-makers and user personas are like chess pieces. One, the decision maker, holds the power, making key moves that decide the fate of products and strategies. The other, the user persona, embodies the target audience, guiding the direction of marketing efforts and product development.</p>
<p><img decoding="async" loading="lazy" alt="Decision makers vs user personas cover" src="https://configcat.com/blog/assets/images/decision-makers-vs-user-personas-cover-c31fd5d1a96bf40039e41c72a70cb741.png" width="1200" height="630" class="img_ev3q"></p>
<p>Understanding the differences, interplay, and synergies between decision-makers and user personas is more than just a marketing tactic; it's a strategic imperative. By balancing the insights from both, businesses can create more effective products, services, and marketing strategies, ultimately driving success and growth.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="understanding-user-personas">Understanding User Personas<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#understanding-user-personas">​</a></h2>
<p>A user persona is similar to a detailed character sketch in a novel or screenplay. Just as a character sketch provides a vivid, descriptive portrayal of a character's traits, background, motivations, and behaviors to help writers understand and develop their characters more fully, a user persona serves a similar purpose in product design and marketing.</p>
<p><strong>A user persona is a fictional yet realistic representation of your target audience</strong>. It is a detailed, collective profile of your customer base and includes demographic information, behavioral patterns, motivations, goals, and pain points. This rich, detailed profile helps designers, marketers, product developers, product managers, and other stakeholders understand and empathize with the users they are designing or building for.</p>
<p>It guides decision-making in product development, ensuring that the product aligns with its intended users' needs, expectations, and preferences. In more technical terms, a persona encapsulates a specific customer group's common behaviors and characteristics.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="key-elements-of-user-personas">Key Elements of User Personas<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#key-elements-of-user-personas">​</a></h3>
<p>User personas generally include certain key elements such as:</p>
<ul>
<li><strong>Demographic and sociographic information:</strong> This encompasses basic details like age, gender, occupation, and socio-economic status and helps in understanding who the users are.</li>
<li><strong>Behaviors</strong>: This details how the user interacts with a product or service. What are their habits, preferences, and common activities related to the product?</li>
<li><strong>Challenges and pain points</strong>: Identifying the problems users encounter is crucial. This helps in developing solutions that address these specific issues.</li>
<li><strong>Environment</strong>: The context in which the user interacts with the product, such as the physical, social, or cultural environment, can affect their experience.</li>
<li><strong>Technology usage</strong>: Understanding the user's comfort level and familiarity with the technology can guide the design and functionality of a product.</li>
<li><strong>Motivation, objectives, and goals</strong>: What drives the user? What are they trying to achieve by using the product or service? Understanding their goals helps align the product's features and functionalities with the user's needs.</li>
<li><strong>Usage context:</strong> This aspect covers the specific circumstances under which your customers interact with your service, including the engagement timing, their particular actions, and how frequently they perform these actions.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="importance-of-user-personas">Importance of User Personas<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#importance-of-user-personas">​</a></h3>
<p>The importance of user personas can be understood from various perspectives:</p>
<ul>
<li><strong>Empathy</strong>: They help teams empathize with the users, seeing the product from the user's perspective.</li>
<li><strong>Focus</strong>: Personas keep the user at the forefront of the design process, ensuring that decisions are made with the user's needs in mind.</li>
<li><strong>Communication</strong>: They provide a common language for teams and stakeholders, ensuring everyone has the same understanding of who the users are.</li>
<li><strong>Decision making</strong>: Personas guide feature development, design choices, and prioritization by aligning them with user needs.</li>
<li><strong>Consistency</strong>: They help maintain user-centric consistency across different features and aspects of the product.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="understanding-decision-makers">Understanding Decision Makers<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#understanding-decision-makers">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Understanding decision makers" src="https://configcat.com/blog/assets/images/understanding-decision-makers-89ba322d20fda47f7a07180e0bfff92b.jpg" width="800" height="534" class="img_ev3q"></p>
<p><strong>Decision makers are the key individuals who have the power and authority to green-light a project, approve a budget, or select a product or service for their company</strong>.</p>
<p>They come in various forms - CEOs, product managers, department heads, and even board members. Each one, depending on their role, views decisions through different lenses: financial impact, strategic alignment, operational efficiency, and employee wellbeing.</p>
<p>Decision-makers typically possess a deep understanding of their business's overarching goals and are often under pressure to make decisions that align with these objectives. Their decisions are driven by data, experience, and foresight. They're not just thinking about the immediate impact but also about how their choices will resonate in the long run.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="key-characteristics-of-decision-makers">Key Characteristics of Decision Makers<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#key-characteristics-of-decision-makers">​</a></h3>
<p>To better understand these pivotal figures, let's break down their characteristics:</p>
<ul>
<li><strong>The role of authority and responsibility</strong>: Decision makers often hold positions of significant authority within their organizations. Their decisions can have a profound impact on the organization's direction, profitability, and market position.</li>
<li><strong>Risk assessment and management</strong>: These individuals are often tasked with assessing risks. They weigh the potential benefits of a decision against the possible pitfalls. Decision-makers must discern which opportunities will bear fruit for their organization.</li>
<li><strong>Financial acumen</strong>: Decision makers typically have a keen understanding of financial matters. They need to balance the books, ensuring that their investments today won't sink the company's finances tomorrow. They are like careful householders, guaranteeing the family budget is spent wisely, bringing the most value and benefit.</li>
<li><strong>Vision and foresight</strong>: A critical aspect of a decision-maker's role is the ability to look beyond the immediate horizon. They need to foresee market trends, technological advancements, and shifts in consumer behavior.</li>
<li><strong>Communication and influence</strong>: Decision makers must also be skilled communicators. They need to articulate their vision and decisions clearly to stakeholders, from employees to board members and sometimes even the public. Their ability to persuade and inspire can be crucial in gaining buy-in for their decisions.</li>
<li><strong>Balancing stakeholder interests</strong>: In their decision-making process, they must balance the needs and interests of various stakeholders – employees, shareholders, customers, and suppliers.</li>
<li><strong>Adaptability and learning</strong>: The best decision-makers can adapt to changing circumstances. They are continuous learners, always seeking to update their knowledge and skills. They understand that the business world is not static and that flexibility and adaptability are key to survival and success.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="difference-between-decision-makers-and-user-personas">Difference Between Decision Makers and User Personas<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#difference-between-decision-makers-and-user-personas">​</a></h2>
<p>While user personas and decision-makers are crucial, they have different needs and perspectives. <strong>The user persona cares about experience, usability, and satisfaction, while the decision-maker is concerned with value, ROI, and efficiency</strong>. They're like two sides of a coin.</p>
<p>So, how do you cater to both? Consider a company like Apple. They expertly balance the needs of decision-makers (value, technology, status, profits) and user personas (design, user experience, brand loyalty).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="incorporating-feature-flags-catering-to-user-personas-and-decision-makers">Incorporating Feature Flags: Catering to User Personas and Decision Makers<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#incorporating-feature-flags-catering-to-user-personas-and-decision-makers">​</a></h2>
<p><strong><a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer">Feature flags</a> are a powerful tool in modern software development used to toggle features on or off dynamically</strong>. They play a pivotal role in bridging the gap between user personas and decision-makers, offering unique benefits to both:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="for-user-personas">For User Personas<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#for-user-personas">​</a></h3>
<ul>
<li><strong>Personalized user experience</strong>: Feature flags allow a customized experience for different user personas. Imagine a trading app that can switch between a simplified interface for casual traders (User Persona A) and a more detailed, feature-rich interface for power users (User Persona B). This flexibility ensures that each user persona has an experience tailored to their preferences and needs.</li>
<li><strong>Testing and feedback</strong>: Feature flags enable the rollout of new features to a subset of users for testing. Companies can gather valuable feedback by engaging user personas in the testing phase, ensuring the final product resonates well with the target audience.</li>
<li><strong>Reduced risk of negative impact</strong>: By using feature flags, companies can minimize the risk of introducing a new feature that might not be well-received by all user personas. If something goes wrong, the feature can be turned off instantly without affecting the overall user experience.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="for-decision-makers">For Decision Makers<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#for-decision-makers">​</a></h3>
<ul>
<li><strong>Controlled rollouts and risk management</strong>: Feature flags offer decision-makers control over the release process. They can mitigate risks by <a href="https://configcat.com/blog/2019/11/30/targeting/" target="_blank" rel="noopener noreferrer">gradually rolling out a feature</a> to users. This controlled rollout process reduces the risk of widespread issues and allows for smoother implementation.</li>
<li><strong>Data-driven decisions</strong>: Decision makers thrive on data and insights. Feature flags provide them with real-time data on how new features are performing.</li>
<li><strong>Resource and budget management</strong>: Decision makers can optimize resource allocation and budget with feature flags. Features that don't perform well or resonate with users can be quickly turned off, saving the company from investing further in unfruitful directions.</li>
<li><strong>Long-term strategic planning</strong>: Using feature flags, decision-makers can align software development with long-term business strategies. They can plan for phased feature releases in line with market trends, competitor actions, and overall business goals.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bridging-the-gap">Bridging the Gap<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#bridging-the-gap">​</a></h3>
<p>In the interplay between user personas and decision-makers, feature flags serve as a versatile tool. They allow for a dynamic and responsive approach to software development and product management. The key is in how these flags are utilized:</p>
<ul>
<li><strong>For user personas</strong>, it's about delivering a personalized and satisfying user experience, testing, and refining features based on their feedback.</li>
<li><strong>For decision makers</strong>, it's about managing risks, making informed decisions based on real-time data, and ensuring alignment with broader business objectives.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/09/06/decision-makers-vs-user-personas/#conclusion">​</a></h2>
<p>Mastering the balance between decision-makers and user personas is key to business success. Feature flags are like the adjustable sails of a ship, helping navigate the winds of user needs and business goals, ensuring a journey that's beneficial for both user personas and decision-makers. By leveraging this tool effectively, companies can create products that not only delight their users but also contribute to the strategic success of the business.</p>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a> is a developer-centric feature flag service with unlimited team size, awesome support, and a reasonable price tag. They support simple feature toggles, <a href="https://configcat.com/docs/targeting/targeting-rule/segment-condition/" target="_blank" rel="noopener noreferrer">user segmentation</a>, and <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B testing</a> and has a generous <a href="https://app.configcat.com/signup" target="_blank" rel="noopener noreferrer">free tier</a> for low-volume use cases or those just starting.</p>
<p>For more feature flagging goodies, stay connected to ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>decision maker</category>
            <category>user persona</category>
            <category>feature flag</category>
            <category>business success</category>
            <category>feature management</category>
        </item>
        <item>
            <title><![CDATA[Using Feature Flags to Enhance E-Commerce Shopping]]></title>
            <link>https://configcat.com/blog/2024/08/20/feature-flags-in-ecommerce/</link>
            <guid>https://configcat.com/blog/2024/08/20/feature-flags-in-ecommerce/</guid>
            <pubDate>Tue, 20 Aug 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Explore how feature flags enhance e-commerce with real-time personalization, A/B testing, and tailored customer journeys.]]></description>
            <content:encoded><![CDATA[<p>In a world saturated with e-commerce platforms, the difference between a mere visitor and a loyal customer often hinges on the shopping experience they encounter. Think about it: Why do customers repeatedly flock to giants like Amazon and other online shops with unique offerings? It's the shopping experience, that personal touch—the sensation that the online store knows exactly what they're looking for, even before they do.</p>
<p><img decoding="async" loading="lazy" alt="Feature flags in e-commerce cover" src="https://configcat.com/blog/assets/images/feature-flags-in-ecommerce-cover-7d75cd6da6413572c9dd833aea16e58f.jpg" width="1200" height="630" class="img_ev3q"></p>
<p>The shopping experience of any digital storefront, encompassing everything from site layout to checkout efficiency, plays a pivotal role in growing your business​​. In fact, a staggering number of consumers are typically willing to pay more for superior customer experience​​. So, enhancing the e-commerce shopping experience matters; think of it as the bridge between passive browsing and active purchasing and, more importantly, the foundation of lasting customer relationships.</p>
<p>But how can e-commerce platforms continuously adapt and enhance the shopping experience to better cater to the needs of customers and make their time shopping with you more enjoyable? The answer is <a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer">feature flags</a>. These nifty tools don't just offer a safety net for developers; they can reshape user experiences in real-time, ensuring that their online experience is smooth, tailored, and memorable.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-role-of-feature-flags-in-e-commerce-platforms">The Role of Feature Flags in E-commerce Platforms<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/20/feature-flags-in-ecommerce/#the-role-of-feature-flags-in-e-commerce-platforms">​</a></h2>
<p>At its core, <strong>a feature flag is a tool or code wrapper that allows developers to turn certain features or functionalities on and off without re-deploying any new code</strong>. They are useful in separating the release of features from code deployment, testing new features in production, fixing bugs in isolation, or rolling out updates with minimal disruption to end users. But it's more than just a switch; it's a strategic instrument for implementing adaptive features that can improve business agility and customer's shopping experience in e-commerce platforms. Furthermore, <strong>they facilitate customer segmentation by grouping individuals based on behavior, preferences, or similar characteristics</strong>, which enhances the ability to deploy targeted marketing campaigns.</p>
<p>Feature flags <strong>can also be <a href="https://configcat.com/docs/integrations/overview/" target="_blank" rel="noopener noreferrer">integrated with analytics tools</a> to gain insight into user interactions and track user behaviors, purchases, demographics, and gather real-time feedback</strong>, and iterate based on this data or feedback. This not only enhances the online shopping experience but builds rich customer profiles from a diverse customer base, making it easier to introduce customers to a relevant range of product offerings, which directly impacts an e-commerce or retail website's profitability and customer satisfaction.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="personalized-shopping-tailoring-user-experiences-in-real-time">Personalized Shopping: Tailoring User Experiences in Real-Time<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/20/feature-flags-in-ecommerce/#personalized-shopping-tailoring-user-experiences-in-real-time">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Personalized shopping experiences in e-commerce" src="https://configcat.com/blog/assets/images/personalized-shopping-a0d677020819bfeba6c556cff7e029f8.jpg" width="800" height="450" class="img_ev3q"></p>
<p>Gone are the days when one-size-fits-all content would suffice; today's savvy online shoppers demand more. They seek a personalized journey, a reflection of their preferences, and a testament to how well a brand knows them. <strong>Personalization in e-commerce platforms revolves around crafting unique experiences for customers</strong> by offering suggestions and recommendations tailored to their individual preferences.</p>
<p><strong>This involves analyzing various data, such as their search patterns, product browsing behavior, past purchases, and even their geographic location</strong>. However, personalization isn't just about product recommendations. It's a dynamic approach that shapes a visitor's digital shopping journey based on their unique needs and preferences.This strategy goes beyond the generic retail experience, making each user feel valued by offering a personal touch.</p>
<p>Brands that excel in personalization stand to benefit significantly, as when businesses tailor their shopping experiences and recommendations to individual customers, they tap into the potential for impulse purchases, which are spontaneous, unplanned buying decisions based on relevance. Interestingly, despite the spontaneous nature of these purchases, most consumers feel satisfied with their decisions and are often encouraged to spend more. This indicates that <strong>personalized marketing, when done effectively, not only drives sales but also resonates positively with consumers</strong>, making them feel content with their purchases.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="enhancing-personalization-with-feature-flags">Enhancing Personalization with Feature Flags<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/20/feature-flags-in-ecommerce/#enhancing-personalization-with-feature-flags">​</a></h3>
<p>Feature flags allow retailers to tailor this journey in real time, offering a personalized experience to each user. For instance, if data shows that a customer frequently purchases pet supplies, the e-commerce platform can dynamically adjust its interface to highlight pet-related products or discounts, making the shopping experience more relevant and engaging.</p>
<p>Similarly, if a customer is a first-time visitor, the platform can trigger a different set of features, like introductory offers and helpful navigation tips. It can also welcome back returning customers with tailored offers based on their shopping history, thereby enhancing the likelihood of conversion. <strong>Localization using feature flags can also play a particularly pivotal role in personalization</strong>. Localization, in essence, is personalization attuned to geographic nuances, where content can be adjusted according to a user's location or IP address to make it more region-specific.</p>
<p>For example, most consumers desire to shop for products in their local currency and often gravitate towards websites that list prices in their local currency, emphasizing the influential role of localization in influencing purchasing decisions. <strong>By offering geo-targeted offers and custom-tailoring the shopping experience using feature flags, brands not only differentiate themselves from the competition but also cultivate deeper connections with their audience</strong>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ab-testing-optimizing-product-displays-and-checkout-processes">A/B Testing: Optimizing Product Displays and Checkout Processes<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/20/feature-flags-in-ecommerce/#ab-testing-optimizing-product-displays-and-checkout-processes">​</a></h2>
<p><img decoding="async" loading="lazy" alt="A/B testing using feature flags" src="https://configcat.com/blog/assets/images/ab-testing-58061b63397c32c46834bc73136b8bf0.jpg" width="800" height="533" class="img_ev3q"></p>
<p><strong><a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B testing</a> is another powerful way to optimize the e-commerce experience, and feature flags are integral to this process</strong>. They allow platforms to show different variations of a page to different groups of users. This capability is invaluable in refining product displays, checkout processes, and overall site functionality. For example, an e-commerce site can use feature flags to test two different checkout processes: one that's a single-page checkout and another that's a multi-step process. <strong>By analyzing metrics such as completion rate and time to purchase, the platform can determine which process is more efficient and leads to higher customer satisfaction</strong>.</p>
<p>Similarly, feature flags can be used <strong>to test different product display layouts, recommendation algorithms, or even search functionalities</strong>. The insights gleaned from these tests help create a user-centric digital storefront that's optimized for both conversion and customer retention. Running these controlled experiments using feature flags allows businesses to fine-tune their user experience by presenting different variations of site elements, such as calls to action, layout, imagery, and color schemes, to determine what resonates most with their audience.</p>
<p>This data-driven approach replaces guesswork with customer-preferred designs, optimizing the shopping journey based on actual user behavior. <strong>The goal is to streamline the path from initial interest to purchase</strong>, ensuring that potential customers find what they're looking for easily and quickly.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/20/feature-flags-in-ecommerce/#conclusion">​</a></h2>
<p>As e-commerce continues to evolve, the platforms that embrace adaptability will thrive. Feature flags are at the forefront of this evolution, providing a way for e-commerce sites to innovate continuously. They allow for a level of customization and optimization that was previously difficult to achieve, ensuring that every user's shopping experience can be unique and tailored.</p>
<p>In conclusion, feature flags are more than just a development tool—they are a crucial component of a modern e-commerce strategy. By enabling real-time personalization, robust A/B testing, and continuous improvement, feature flags empower e-commerce platforms to create shopping experiences that are as unique as the customers they serve. As we look to the future, the role of feature flags will only grow, helping to shape an e-commerce landscape that's adaptive, innovative, and, above all, customer-centric.</p>
<p>If you're looking for a service to support dynamic <a href="https://configcat.com/docs/main-concepts/#feature-flag-or-setting" target="_blank" rel="noopener noreferrer">feature toggles</a> (and bear in mind that simple feature toggles work well too), check out <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a>. We'd describe it as "like LaunchDarkly but cheaper and a bit less fancy" and find that it does most of what we need. ConfigCat supports simple feature toggles, <a href="https://configcat.com/docs/targeting/targeting-rule/segment-condition/" target="_blank" rel="noopener noreferrer">user segmentation</a>, and <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B testing</a> and has a generous <a href="https://app.configcat.com/signup" target="_blank" rel="noopener noreferrer">free tier</a> for low-volume use cases or those just starting out.</p>
<p>For more feature flagging goodies, stay connected to ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>feature management</category>
            <category>AB testing</category>
            <category>e-commerce</category>
            <category>user experience</category>
        </item>
        <item>
            <title><![CDATA[Managing Feature Flags in Large-Scale Applications]]></title>
            <link>https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/</link>
            <guid>https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/</guid>
            <pubDate>Sat, 10 Aug 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn about the effective strategies and challenges of managing feature flags in large-scale applications within enterprise-level businesses.]]></description>
            <content:encoded><![CDATA[<p>Large-scale applications are extensive software applications engineered to handle vast amounts of data, a high number of concurrent users, and complex transactions. They often encompass distributed systems, utilize microservices architecture, and are deployed across various platforms and environments. However, managing large-scale applications presents a unique set of challenges akin to orchestrating a symphony. Like a musical note, each line of code plays a critical role in their grand performance.</p>
<p><img decoding="async" loading="lazy" alt="Managing feature flags in large-scale applications cover" src="https://configcat.com/blog/assets/images/managing-feature-flags-in-large-scale-applications-cover-2a9f98c50a5905923ddda6f12ab39be4.png" width="1200" height="630" class="img_ev3q"></p>
<p>These large-scale applications are typically found in enterprise-level businesses, handling critical operations that demand reliability, scalability, and high performance. The complexity of these systems arises not only from their size but also from the diversity of their components and the intricate interactions between them and operational requirements.</p>
<p>From the architectural nuances that shape the foundation to the dynamic interplay of services, complex ecosystems of features, and numerous users, managing large-scale applications demands not just technical prowess but also a strategic approach -- and this is where feature flags become invaluable.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="feature-flags-and-their-role-in-large-scale-applications">Feature Flags and Their Role in Large-Scale Applications<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#feature-flags-and-their-role-in-large-scale-applications">​</a></h2>
<p><a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer">Feature flags</a>, or feature toggles, are a dynamic method employed in software development that allows teams to modify system behavior without changing the code. These flags act as control mechanisms, turning features on or off in a live environment. They are crucial tools for continuous integration and delivery, allowing developers to test new features, perform <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/#so-what-is-ab-testing" target="_blank" rel="noopener noreferrer">A/B testing</a>, and <a href="https://configcat.com/blog/2022/01/14/progressive-delivery/" target="_blank" rel="noopener noreferrer">roll out updates progressively</a>.</p>
<p>Feature flags provide a safety net, offering the ability to quickly revert changes if issues arise, thereby minimizing risk in deployment. In large-scale applications, feature flags are more than just tools for managing releases; they are integral to maintaining the flexibility and stability of these complex systems. They allow for precise control over feature rollouts, facilitate experimentation, and enable a more agile response to market changes.</p>
<p>Feature flags can be used to segment functionality for different user groups, test new features under real-world conditions, and gather valuable feedback. They also play a major role in risk management, allowing teams to analyze and identify performance risks associated with feature releases and assess their probability and impact on the application and user base.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="challenges-of-managing-feature-flags-in-large-scale-applications">Challenges of Managing Feature Flags in Large-Scale Applications<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#challenges-of-managing-feature-flags-in-large-scale-applications">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Challenges of managing feature flags in large-scale applications" src="https://configcat.com/blog/assets/images/challenges-0fb0a636f8f9007454832efa9f1dfed9.png" width="795" height="454" class="img_ev3q"></p>
<p>Despite their numerous advantages, managing feature flags in large-scale applications presents its own set of challenges.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="technical-challenges">Technical Challenges<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#technical-challenges">​</a></h3>
<p>Technical challenges are at the forefront of managing feature flags in large-scale applications. These include the complexity of integrating feature flags into existing systems, ensuring consistency across different environments, languages, and tech stacks, as well as managing feature dependencies and interactions.</p>
<p>With numerous features and services being developed, tested, and deployed simultaneously, there's the risk of feature flags causing unforeseen side effects or conflicts, particularly in systems with intertwined dependencies and interconnected components.</p>
<p>Each environment may have its own database, connecting strings, and flags. Managing these configurations, especially in homegrown feature flag solutions, becomes increasingly complex and time-consuming as the application scales.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="organizational-challenges">Organizational Challenges<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#organizational-challenges">​</a></h3>
<p>The organizational challenges in managing feature flags stem from the need to align the use of feature flags with broader company goals and strategies. Ensuring that all team members are aligned in understanding the purpose and use of each feature flag is crucial here, as multiple teams may use the same flags in large organizations, requiring clear communication and careful coordination.</p>
<p>There's a need for transparency and strict policies and procedures regarding creating, deploying, and retiring feature flags. Teams must understand the purpose and impact of each feature flag, which necessitates comprehensive training and clear documentation.</p>
<p>Additionally, managing access controls and permissions for who can create, modify, or delete feature flags is crucial to prevent unauthorized or unintended changes that could disrupt the application.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="scalability-challenges">Scalability Challenges<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#scalability-challenges">​</a></h3>
<p>As the system scales, the complexity of managing these flags grows exponentially. Over time, unused or forgotten flags can accumulate, leading to codebase clutter and potential technical debt. Managing an escalating number of feature flags without proper tools and strategies can become cumbersome, leading to an increased risk of errors.</p>
<p>As applications also grow in size and complexity, the sheer volume of feature flags can lead to difficulty tracking or managing each flag's lifecycle and ensuring that feature flags do not conflict with each other or existing system functionalities, which is critical to maintaining system stability and performance.</p>
<p>Performance degradation may also arise as the sheer number of feature flags can lead to increased load times and resource consumption. Hence, there is a need to regularly audit and clean up old or unused flags to prevent clutter and potential <a href="https://configcat.com/blog/2024/01/30/feature-flag-retirement/#code-hygiene-and-technical-debt" target="_blank" rel="noopener noreferrer">technical debt</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="best-practices-for-managing-feature-flags-in-large-scale-applications">Best Practices for Managing Feature Flags in Large-Scale Applications<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#best-practices-for-managing-feature-flags-in-large-scale-applications">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Best practices for managing feature flags in large-scale applications" src="https://configcat.com/blog/assets/images/best-practices-5d1514e989764b64972ffed77fb2fff3.png" width="800" height="457" class="img_ev3q"></p>
<p>The inherent nature of large-scale systems adds a layer of complication to managing feature flags, requiring a few best practices to streamline this process, enhance operational efficiency, and ensure that feature flags serve their intended purpose without causing disruption or technical debt.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="clear-and-consistent-flag-naming-conventions">Clear and Consistent Flag Naming Conventions<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#clear-and-consistent-flag-naming-conventions">​</a></h3>
<p>The foundation of effective feature flag management is establishing clear and consistent naming conventions. This practice is crucial for maintaining clarity and avoiding confusion, especially in a large-scale system with numerous flags.</p>
<p>A standardized naming convention aids in quickly identifying the purpose, scope, and ownership of each flag. This approach should be coupled with comprehensive documentation that details the naming structure, ensuring new and existing team members can easily understand and adhere to the convention.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="proper-flag-categorization">Proper Flag Categorization<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#proper-flag-categorization">​</a></h3>
<p>Organizing feature flags into logical categories is vital for maintaining an orderly system. Categories can be based on various criteria, such as the feature's purpose (e.g., performance, user experience), the stage of the development cycle (e.g., testing, production), or the flag's intended lifespan (e.g., short-term experiment, long-term feature).</p>
<p>Categorization also provides a framework for organizing and understanding the role of each feature flag. It not only simplifies flag management but also aids in analyzing the impact and usage of flags across different aspects of the application.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="regular-auditing-of-feature-flags">Regular Auditing of Feature Flags<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#regular-auditing-of-feature-flags">​</a></h3>
<p>Conducting regular audits of feature flags is essential for ensuring their ongoing relevance and effectiveness. These audits involve reviewing each flag's usage, performance impact, alignment with current development goals, and its associated lifecycle.</p>
<p>Flags that are no longer needed or have become redundant should be retired to prevent clutter and potential conflicts or technical dept. Regular audits help maintain a lean and efficient feature flagging system. You can learn more about retiring your feature flags <a href="https://configcat.com/blog/2024/01/30/feature-flag-retirement/" target="_blank" rel="noopener noreferrer">here</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="use-of-automated-flag-removal-tools">Use of Automated Flag Removal Tools<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#use-of-automated-flag-removal-tools">​</a></h3>
<p>Integrating automated tools for flag management can significantly enhance the efficiency of the flag lifecycle process. These tools can automate tasks such as flag removal, alerting teams about outdated or unused flags, and enforcing naming and categorization standards.</p>
<p>This automation helps reduce the risk of human error and frees up valuable resources, allowing teams to focus on more strategic tasks. With ConfigCat, you can keep track of all feature flags, especially those that have become stale, in an easy-to-use <a href="https://configcat.com/docs/advanced/code-references/overview/#scan" target="_blank" rel="noopener noreferrer">tool</a>.</p>
<p>Adhering to these best practices in feature flag management can significantly mitigate the challenges associated with large-scale applications. By fostering a disciplined, organized, and automated approach, organizations can leverage the full potential of feature flags to drive innovation, reduce risks, and enhance the agility and responsiveness of their software development processes.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="example-of-a-company-not-managing-feature-flags-in-large-scale-applications">Example of a Company Not Managing Feature Flags in Large-Scale Applications<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#example-of-a-company-not-managing-feature-flags-in-large-scale-applications">​</a></h2>
<p>The incident involving <a href="https://en.wikipedia.org/wiki/Knight_Capital_Group" target="_blank" rel="noopener noreferrer">Knight Capital</a> is a stark example of the dangers of mismanaging feature flags in large-scale applications. Knight Capital, once a leading high-frequency trader on Wall Street, experienced a catastrophic loss due to mishandled feature flags. The series of errors began when they reused an existing flag for a new project. This flag was associated with obsolete code that was still present in their codebase. When this flag was activated, it triggered rapid, unintended trades on one of their eight servers.</p>
<p>The situation worsened when a panicked update, intended to resolve the issue, inadvertently activated the obsolete flag on all servers. This sequence of events led to a loss of $465 million in just 30 minutes. The primary mistakes that led to this disaster were reusing an old feature flag, not removing obsolete code, and the inability to quickly turn off the flag without a full deployment.</p>
<p>Knight Capital could have averted this crisis by either avoiding the reuse of the feature flag, cleaning up its codebase to remove obsolete code, or ensuring that the flag could be deactivated independently of a deployment process.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/08/10/managing-feature-flags-in-large-scale-applications/#conclusion">​</a></h2>
<p>The management of feature flags in large-scale applications presents a unique challenge that necessitates a blend of technical acumen, strategic foresight, and disciplined practices. The road ahead for feature flag management in large-scale applications is one of continual evolution, learning, and adaptation.</p>
<p>It's a journey towards more resilient, agile, and user-centric software development practices, where feature flags play a central role in navigating the ever-changing tides of technology and market demands.</p>
<p>ConfigCat supports simple feature toggles, user segmentation, and A/B testing and has a generous <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">free tier</a> for low-volume use cases or those just starting out.</p>
<p>For more feature flagging goodies, stay connected to ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>feature management</category>
            <category>large-scale applications</category>
            <category>best practices</category>
            <category>software development</category>
        </item>
        <item>
            <title><![CDATA[Integrating ConfigCat and Mixpanel Analytics for Business Success]]></title>
            <link>https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/</link>
            <guid>https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/</guid>
            <pubDate>Mon, 29 Jul 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Explore how to integrate ConfigCat and Mixpanel, and the how this integration can help businesses to make data-driven decisions confidently.]]></description>
            <content:encoded><![CDATA[<p>Experimentation is key to successful product development, helping businesses innovate and stay competitive by testing and refining ideas. User actions like page views, clicks, and scrolls provide valuable data about what works and what doesn't. To improve products, businesses need tools that make it easy to understand this data. Using feature flags with analytics tools is a great approach. ConfigCat and Mixpanel, when used together, help businesses roll out new features smoothly and gain important insights for making better decisions.</p>
<p><img decoding="async" loading="lazy" alt="ConfigCat and Mixpanel integration" src="https://configcat.com/blog/assets/images/configcat-mixpanel-integration-cover-9b92b16b144c2f3ab4d531dcc829d722.png" width="1200" height="630" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="configcat-as-a-feature-flag-management-service">ConfigCat as a Feature Flag Management Service<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#configcat-as-a-feature-flag-management-service">​</a></h2>
<p>Manually implementing feature flags can be time-consuming and complex. ConfigCat simplifies this with remote management and configuration, reducing technical debt and easing the engineering workload.</p>
<p>Some key features of ConfigCat include:</p>
<ul>
<li><strong>Feature Flags:</strong> Create and control feature flags remotely.</li>
<li><strong>Configuration Management:</strong> Manage and update configurations centrally without redeploying the application.</li>
<li><strong>Targeting Rules:</strong> Use advanced targeting rules based on user attributes, allowing precise control over who gets access to specific features.</li>
<li><strong>User Segmentation:</strong> Deliver personalized experiences to different user segments.</li>
<li><strong>A/B Testing:</strong> Supports A/B testing of feature variants with different user groups to determine which performs better.</li>
<li><strong>Percentage Rollouts:</strong> Gradually roll out features to a percentage of your user base to mitigate risks.</li>
<li><strong>Analytics and Monitoring:</strong> Easily integrate with analytics and monitoring tools to track the usage and performance of feature flags.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="understanding-mixpanel-analytics">Understanding MixPanel Analytics<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#understanding-mixpanel-analytics">​</a></h2>
<p>Mixpanel is a powerful analytics solution that helps businesses understand how users interact with their apps. Each person is a unique user with distinct details like name, age, etc. In Mixpanel, these details are referred to as profile properties, and tracking them helps businesses gain deeper insights into their audience. Any action can be tracked as an event in Mixpanel.</p>
<p>For example, when a customer buys coffee, details about that purchase are captured along with the associated details, called event properties, which are then stitched together. That way, profile properties track who a user is, while events track what a user does. Mixpanel combines this into a comprehensive profile for each user to help you analyze and monitor everything that happens on your app.</p>
<p>Some key points about Mixpanel:</p>
<ul>
<li><strong>Event Tracking:</strong> Track specific user actions like button clicks, page views, or purchases.</li>
<li><strong>User Analytics:</strong> Gain insights into user behavior with segmentation, cohort analysis, and user flows.</li>
<li><strong>Funnels:</strong> Analyze user steps to complete a process, identifying drop-off points and improvement areas.</li>
<li><strong>Retention Analysis:</strong> Measure user retention over time to see how often users return to your app.</li>
<li><strong>A/B Testing:</strong> Experiment with different feature or interface versions to see which performs better.</li>
<li><strong>Feature Impact:</strong> Use the “Impact” tool to compare user behavior before and after launching a new feature.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-to-integrate-configcat-with-mixpanel">How to Integrate ConfigCat with Mixpanel<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#how-to-integrate-configcat-with-mixpanel">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-1-set-up-configcat">Step 1: Set Up ConfigCat<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#step-1-set-up-configcat">​</a></h3>
<ul>
<li>Go to<a href="https://configcat.com/" target="_blank" rel="noopener noreferrer"> ConfigCat</a> and sign up for an account; it’s free.</li>
<li>Create the feature flags for the features you want to manage. For example, create a feature flag named “buttonFeature” or “newFeature”.</li>
<li>Copy your SDK key, as we’d need it to initialize the SDK.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-2-set-up-mixpanel">Step 2: Set Up Mixpanel<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#step-2-set-up-mixpanel">​</a></h3>
<ul>
<li>Go to<a href="https://mixpanel.com/" target="_blank" rel="noopener noreferrer"> Mixpanel</a> and sign up for an account; it’s also free.</li>
<li>Create a new project (A project is considered a container of your analytics data on Mixpanel).</li>
<li>In the onboarding screen, navigate to the “connect data” section or click on the “continue setup” on your project dashboard.</li>
<li>You can copy the Mixpanel project token at the top right or by navigating to the project settings page.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="Mixpanel&amp;#39;s onboarding dashboard" src="https://configcat.com/blog/assets/images/setup-a1fda733213ff55b69fe4cd052bb5d49.png" width="1757" height="1091" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-3-install-both-sdks">Step 3: Install both SDKs<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#step-3-install-both-sdks">​</a></h3>
<p>Install both the ConfigCat SDK and Mixpanel SDK in your application.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">npm install configcat</span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token plain">react mixpanel</span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token plain">browser</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-4-initialize-and-configure-both-sdks">Step 4: Initialize and Configure both SDKs<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#step-4-initialize-and-configure-both-sdks">​</a></h3>
<ul>
<li>Set up the Mixpanel SDK with your project token key that was copied earlier.</li>
</ul>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">//Import Mixpanel SDK and ConfigCat SDK</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports">mixpanel</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'mixpanel-browser'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ConfigCatProvider</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">PollingMode</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'configcat-react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Near entry of your product, init Mixpanel</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">mixpanel</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">init</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'#YOUR_TOKEN'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">debug</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">track_pageview</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>We’ve turned on the page tracking during initialization by default using the <code>track_pageview: true</code> to get the respective page view sent to our Mixpanel dashboard.</p></div></div>
<ul>
<li>Initialize the ConfigCat SDK with your ConfigCat SDK key.</li>
</ul>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">ConfigCatProvider</span><span class="token plain"> sdkKey</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"#YOUR_SDK_KEY#"</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">/* your application code */</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token maybe-class-name">ConfigCatProvider</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-5-sending-feature-flag-evaluation-analytics-to-mixpanel">Step 5: Sending Feature Flag Evaluation Analytics to Mixpanel<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#step-5-sending-feature-flag-evaluation-analytics-to-mixpanel">​</a></h3>
<p>For this phase, during the ConfigCat SDK initialization, we’ll subscribe to the flagEvaluated hook provided by the ConfigCat SDK and send feature flag evaluation data to Mixpanel.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">ConfigCatProvider</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  sdkKey</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"#YOUR_SDK_KEY"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  pollingMode</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token maybe-class-name">PollingMode</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access maybe-class-name">AutoPoll</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  options</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">pollIntervalSeconds</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">setupHooks</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">hooks</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      hooks</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">on</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'flagEvaluated'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">evaluationDetails</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Send an `$experiment_started` event.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        mixpanel</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">track</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'$experiment_started'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token string-property property">'Experiment name'</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> evaluationDetails</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token string-property property">'Variant name'</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> evaluationDetails</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token string-property property">'Variation ID'</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> evaluationDetails</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">variationId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Use the identify API.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        mixpanel</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">people</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'configcat_'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> evaluationDetails</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> evaluationDetails</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Your application or component</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">App</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token maybe-class-name">ConfigCatProvider</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="code-explanation">Code explanation:<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#code-explanation">​</a></h4>
<ul>
<li>**ConfigCatProvider: **The <code>ConfigCatProvider</code> is a context provider from the ConfigCat library used to manage feature flags in your application. It wraps around your application or the specific part that needs feature flagging, providing feature flag configuration and evaluation.</li>
<li><strong>sdkKey:</strong> This is your unique SDK key for accessing ConfigCat services. Replace #YOUR_SDK_KEY with your actual SDK key.</li>
<li><strong>pollingMode:</strong> This determines how the feature flags are updated. <code>PollingMode.AutoPoll</code> means the SDK will automatically fetch the latest feature flag values regularly.</li>
<li>**Options Object: **The <code>options</code> object contains additional configuration settings.</li>
<li><strong>setupHooks</strong>: This function allows you to set up hooks to listen for specific events in specific scenarios. In this case, we subscribe to the flagEvaluated hook.</li>
<li><strong>hooks.on('flagEvaluated', callback)</strong>: This hook is triggered whenever a feature flag is evaluated. Now, once the flag is evaluated, we receive that event. The <code>evaluationDetails</code> object contains information about the evaluated flag event, including the flag’s key, value, and variation ID (optional).</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="mixpanel-integration">Mixpanel Integration<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#mixpanel-integration">​</a></h4>
<p>Inside the flag’s evaluated hook event function, we are using <code>mixpanel.track()</code> function to track and identify user interactions with the feature flag.</p>
<ul>
<li><strong>mixpanel.track('$experiment_started', { ... })</strong>: This sends an event to Mixpanel whenever a feature flag is evaluated. The event name is <code>$experiment_started</code>, and it includes:<!-- -->
<ul>
<li><code>'Experiment name'</code>: The key of the evaluated feature flag.</li>
<li><code>'Variant name'</code>: The value assigned to the feature flag.</li>
<li><code>'Variation ID'</code>: The variation ID of the feature flag (optional but required for A/B testing experiments).</li>
</ul>
</li>
<li><strong>mixpanel.people.set({ ... })</strong>: This enriches Mixpanel’s analytics with the feature metadata. It creates a property named <code>configcat_&lt;feature_flag_key&gt;</code> with the value of the evaluated feature flag. However, this should only be used for troubleshooting or to group/filter your existing Mixpanel events by feature flag evaluations. To identify actual users (unique logged-in users), you’re advised to use the <code>mixpanel.identify(&lt;user_id&gt;)</code> when a user signs up or logs in, passing it the user's known identifier, such as their ID, from your database. This helps identify unique users based on the feature flags they've been exposed to.</li>
</ul>
<p>With this, we can now access the experiment-started event whenever the SDK initializes, and flag evaluation is done, along with the page view event.</p>
<p><img decoding="async" loading="lazy" alt="Analytics of all experiments on Mixpanel" src="https://configcat.com/blog/assets/images/experiments-1-9831cd0a0ebfdbc327a07e8486db5be2.png" width="1737" height="991" class="img_ev3q"></p>
<p>We can also see what flag the user was exposed to and the properties of the event.</p>
<p><img decoding="async" loading="lazy" alt="Properties of an experiment on Mixpanel" src="https://configcat.com/blog/assets/images/experiments-details-8de3cef8de732c5e71997ca272d2448b.png" width="1316" height="537" class="img_ev3q"></p>
<p>As well as a breakdown of the evaluation changes:</p>
<p><img decoding="async" loading="lazy" alt="breakdown of the evaluation changes" src="https://configcat.com/blog/assets/images/evaluation-breakdown-c2b9fe9584b9582a26d3d0cb78dd37eb.png" width="1274" height="787" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="sending-feature-flag-evaluation-for-specific-features-or-experiment-to-mixpanel">Sending Feature Flag Evaluation for Specific Features or Experiment to Mixpanel<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#sending-feature-flag-evaluation-for-specific-features-or-experiment-to-mixpanel">​</a></h3>
<p>Imagine a new feature, say a simple “Buy Now” button, that we wish to add to our app but want to run a release experiment using feature flags and Mixpanel to gain insight into users' interaction with the feature.</p>
<p>For this, we’ll go into the app component and create a button with a click event function that gets called to send an event to Mixpanel each time the button is clicked. This button is then wrapped with a feature flag so the feature is only available to users when toggled on.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> useFeatureFlag </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'configcat-react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports">mixpanel</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'mixpanel-browser'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:rgb(130, 170, 255)">App</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token literal-property property">value</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> buttonFeature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> loading </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useFeatureFlag</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">'buttonFeature'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Track and send feature interaction data to Mixpanel</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">handleClick</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    mixpanel</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">track</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'Button feature'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token literal-property property">button</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Buy Now'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">loading</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">p</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token maybe-class-name">Loading</span><span class="token spread operator" style="color:rgb(137, 221, 255)">...</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">p</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">div className</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"App"</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">/* Show button feature only when its feature flag is toggled on */</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">buttonFeature </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">button className</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"btn"</span><span class="token plain"> onClick</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">handleClick</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token maybe-class-name">Buy</span><span class="token plain"> </span><span class="token maybe-class-name">Now</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">button</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">p</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token maybe-class-name">Feature</span><span class="token plain"> is disabled</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">p</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">div</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">default</span><span class="token plain"> </span><span class="token maybe-class-name">App</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Result:</p>
<p><img decoding="async" loading="lazy" alt="Preview of button feature" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAzoAAACHBAMAAAAsIzGxAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAPUExURf///0Jq4aSw8NPY+HaM6ZyZKdoAAAFySURBVHja7dtBbqswFEBRKCwAQxYQ0y4AkiwAJ/vfU00n/dKfMCqv1TmJlLmv7Kc4pGkAAAAAAAAAAAAAAAAAAAAAAP7TfaQDnouVOkNOh4xW6gR9OmizVmG3js1zytRJh5k8P+7teJ2r1Qo7dgyeE7TH6wxWSx3U+WV15vmfO4Ox7G91wtS5z8v3V5+hTVNWJ06dWxrX7xCdOuHqTGVcH2moIa5lypflMdWPqagT4WQrQ63znt5riGc75a1cn+u2DvZOjLmz19nqLkpDuU/5nqaPdm5f6kQ42S79XqcW2etsr7yfdf3jcVMnQp30VedyW/c6Y7fvnTy3c69OgDplnzXDmrqy10lLnTv1VQePOufXWZquXJq3NV3TV50tj02fhjxkdQLd5MxucuLWebbqxK3zKuoEPtncUcfht9HIPFcQmWdyQvM8258YPMZO4M1j65wzefwHAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPg5n4nYZuifDocTAAAAAElFTkSuQmCC" width="826" height="135" class="img_ev3q"></p>
<p>Now we can control who sees this button and when. Any interaction between our users and this feature is equally sent to Mixpanel.</p>
<p><img decoding="async" loading="lazy" alt="Analytics of unique page views vs users" src="https://configcat.com/blog/assets/images/page-views-to-feature-6d4b8a47bf2076adbe69f957807e026b.png" width="1246" height="674" class="img_ev3q"></p>
<p><em>Analytics of unique page views vs users who interacted with the button.</em></p>
<p><img decoding="async" loading="lazy" alt="Funnel conversion from the experiment" src="https://configcat.com/blog/assets/images/Funnel-conversion-4adc750bbf78f74964b6484ee49e9c09.png" width="1492" height="764" class="img_ev3q"></p>
<p><em>Funnel conversion from the “experiment started” event to users clicking the button feature.</em></p>
<p><img decoding="async" loading="lazy" alt="Feature&amp;#39;s impact" src="https://configcat.com/blog/assets/images/feature-impact-e92871a77565fd130704e74cccee61b3.png" width="1975" height="1119" class="img_ev3q"></p>
<p><em>Feature’s impact</em></p>
<p><img decoding="async" loading="lazy" alt="Country breakdown" src="https://configcat.com/blog/assets/images/country-50a291dce909ca7cbdec9d92ab369feb.png" width="1266" height="778" class="img_ev3q"></p>
<p><em>Country Breakdown of general user interactions.</em></p>
<p>You can find the demo app's <a href="https://github.com/configcat-labs/configcat-mixpanel-integration" target="_blank" rel="noopener noreferrer">source code on Github</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="practical-applications-and-use-cases-for-businesses">Practical Applications and Use Cases for Businesses<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#practical-applications-and-use-cases-for-businesses">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="incremental-rollouts">Incremental Rollouts<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#incremental-rollouts">​</a></h3>
<p>Feature flags enable incremental rollouts, allowing businesses to gradually release a new feature to a subset of users and progressively increase the rollout as confidence in the feature’s performance grows. This reduces the risk of bugs and performance issues. For example, a social media platform might release a new messaging feature to 5% of users, then 20%, 50%, and eventually 100%, while monitoring feedback and performance metrics in Mixpanel to ensure a smooth release.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ab-testing">A/B Testing<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#ab-testing">​</a></h3>
<p>Feature flags are crucial for A/B testing, which involves testing different feature variations to see which performs better. By segmenting and exposing users to variations of a feature, businesses can use Mixpanel to view results and compare metrics to gather data on user preferences. For instance, an e-commerce site can test two checkout processes by splitting users into two groups, analyzing which process leads to higher conversions and lower cart abandonment.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="targeted-rollouts">Targeted Rollouts<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#targeted-rollouts">​</a></h3>
<p>This involves deploying a feature to a specific user segment based on criteria such as location, device type, or user behavior. This allows businesses to tailor experiments to relevant user groups to gather meaningful insights. For instance, a streaming service might test a new recommendation algorithm by deploying it to users frequently watching a particular genre. This targeted rollout ensures the experiment is conducted on a relevant audience, leading to more accurate results.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="beta-testing">Beta Testing<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#beta-testing">​</a></h3>
<p>Feature flags enable businesses to conduct beta testing by allowing a select user group to access new features before they are released to the general public. Beta testing provides valuable feedback and helps identify issues that may not be apparent in a controlled testing environment. E.g., a software company can invite beta testers to use a new productivity tool, gather feedback, and make improvements before a wider launch.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/29/configcat-mixpanel-integration/#conclusion">​</a></h2>
<p>Using feature flags with analytics tools greatly improves your business's ability to innovate and enhance user experience. Combining ConfigCat with Mixpanel helps you make data-driven decisions confidently. This integration optimizes product development and delivers better user experiences. By tracking feature flags and user interactions, you can improve your products, boost user satisfaction, and stay ahead of the competition.</p>
<p>For detailed instructions on how to monitor your feature flag change events and feature flag analytics with Mixpanel, <a href="https://configcat.com/docs/integrations/mixpanel/" target="_blank" rel="noopener noreferrer">check out this guide</a>. For more feature flagging goodies, stay connected to ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flag</category>
            <category>ConfigCat</category>
            <category>mixpanel analytics</category>
            <category>feature management</category>
        </item>
        <item>
            <title><![CDATA[Using Feature Flags for Experimentation and Growth Hacking]]></title>
            <link>https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/</link>
            <guid>https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/</guid>
            <pubDate>Wed, 24 Jul 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Discover how to leverage feature flags for user-centric product development and growth hacking to drive business success and improve user experience]]></description>
            <content:encoded><![CDATA[<p>Experimentation, at its core, is about navigating through the unknown, testing new ideas, and iterating based on feedback and results. It's a practice that could be applied to the business world, where hypotheses are formed, tested, validated, or refuted. This approach is crucial in an environment where customer preferences and market dynamics constantly shift rapidly.</p>
<p><img decoding="async" loading="lazy" alt="Feature flags for experimentation and growth hacking cover" src="https://configcat.com/blog/assets/images/feature-flags-experimentation-growth-hacking-cover-c92c69c2231be5a54605eebc17e28801.jpg" width="1200" height="630" class="img_ev3q"></p>
<p>On the other hand, growth hacking represents a mindset and a set of techniques focused on growing a business, user base, or market presence as quickly and efficiently as possible. It's about leveraging creative, low-cost strategies to acquire and retain customers, often utilizing data-driven and unconventional methods. Growth hacking is prevalent among startups and digital businesses, where resources are limited, and the pressure to grow is high.</p>
<p>The fusion of experimentation and growth hacking creates a potent combination for businesses. It empowers them to be agile, responsive, and innovative. However, effectively executing this fusion requires the right tools and methodologies, and this is where feature flags become invaluable.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-role-of-feature-flags-in-experimentation-and-growth-hacking">The Role of Feature Flags in Experimentation and Growth Hacking<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/#the-role-of-feature-flags-in-experimentation-and-growth-hacking">​</a></h2>
<p><a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer">Feature flags</a> are powerful tools that allow businesses and developers to control the visibility and behavior of features within their applications or websites, enabling them to deploy, test, and iterate on new features without impacting the entire user base, providing a flexible and risk-managed way to introduce changes.</p>
<p>This capability is instrumental in experimentation and growth hacking, as it enables companies to test new features with select user groups, assess outcomes, and make informed decisions without impacting the entire user experience. By facilitating tailored experiences for different user segments, these tools open new possibilities for personalized growth hacking strategies.</p>
<p>Additionally, feature flags facilitate <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/#so-what-is-ab-testing" target="_blank" rel="noopener noreferrer">A/B testing</a>, which is a powerful approach for experimenting and evaluating the impact of new features or changes in a software product.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="using-feature-flags-for-experimentation-and-growth-hacking">Using Feature Flags for Experimentation and Growth Hacking<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/#using-feature-flags-for-experimentation-and-growth-hacking">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Experimenting and growth hacking with feature flags" src="https://configcat.com/blog/assets/images/feature-flags-experimentation-8174a1f0f414e814daee9d172bf9394a.png" width="800" height="458" class="img_ev3q"></p>
<p>Feature flags not only empower businesses to conduct experiments to gauge user response, gather feedback, and refine their offerings but also uncover innovative ways to drive growth, making feature flags an essential toolkit for businesses aiming to navigate and succeed in the ever-evolving market.</p>
<p>A step-by-step implementation of feature flags would include:</p>
<ul>
<li><strong>Identify the Feature for Experimentation</strong>: Choose features likely to impact key metrics like user engagement, retention, or revenue conversion.</li>
<li><strong>Implement the Feature Flag</strong>: Integrate the feature flag into your codebase, ensuring the flags can effectively control the desired features or changes.</li>
<li><strong>Segment Your Audience</strong>: Define which users will experience the feature. This could be based on user demographics, behavior, or other relevant criteria.</li>
<li><strong>Execute Experiment or Controlled Rollout</strong>: Progressively introduce the feature to the selected user segments, starting small to minimize potential risks.</li>
<li><strong>Monitor and Collect Data</strong>: Track how the feature impacts user behavior and other key performance indicators.</li>
<li><strong>Analyze Results and Make Decisions</strong>: Use the collected data to determine the feature's effectiveness and decide whether to roll it out to all users, modify it, or discontinue it.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="best-practices-for-using-feature-flags-for-experimentation-and-growth-hacking">Best Practices for Using Feature Flags for Experimentation and Growth Hacking<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/#best-practices-for-using-feature-flags-for-experimentation-and-growth-hacking">​</a></h2>
<p>To maximize the effectiveness of feature flags in experimentation and growth hacking, it is important to follow some best practices.</p>
<p><img decoding="async" loading="lazy" alt="Best practices for using feature flags" src="https://configcat.com/blog/assets/images/best-practices-a22cc9f7a4c0ca507fdeb55ca177da9f.png" width="800" height="454" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="planning-and-designing-experimentation-with-feature-flags">Planning and Designing Experimentation with Feature Flags<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/#planning-and-designing-experimentation-with-feature-flags">​</a></h3>
<p>Effective use of feature flags in experimentation begins with meticulous planning. It is essential to understand the specific problem or opportunity the experiment addresses. Once the objective is clear, designing the experiment involves deciding on the metrics to track, the user segments to target, and the duration of the experiment.</p>
<p>Establish objectives for each experiment and determine the key performance indicators (KPIs) to measure its success. This involves not just identifying the metrics to measure, but also understanding the potential impact on the user experience and the business.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="efficient-management-and-rollout-strategies">Efficient Management and Rollout Strategies<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/#efficient-management-and-rollout-strategies">​</a></h3>
<p>Develop a systematic approach to roll out new features, starting with a small segment of your user base and gradually expanding to larger groups as you gain confidence in the feature's stability and effectiveness. You can manage your features and configurations without actually deploying new code by using a <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">centralized feature flag management system</a> or platform to streamline the process.</p>
<p>This phased approach aids in assessing user responses and gathering feedback, which is essential for refining product offerings. It also facilitates early identification of issues, allowing for risk mitigation before a full-scale rollout.</p>
<p>Also, maintain clear documentation of each flag, its purpose, and the criteria for its removal or full adoption. Establish a process for the entire lifecycle of a feature flag, from creation to <a href="https://configcat.com/blog/2023/05/10/code-references-feature-introduction/" target="_blank" rel="noopener noreferrer">retirement</a>. This ensures that flags are only active when needed and don't create technical dept or clutter the codebase.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="monitoring-and-analyzing-feature-flag-performance">Monitoring and Analyzing Feature Flag Performance<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/#monitoring-and-analyzing-feature-flag-performance">​</a></h3>
<p>Continuous monitoring is vital to understand the impact of features and experiments on user behavior and system performance. Implement real-time monitoring to track how the features are performing immediately after release. Integrate your feature flags with analytics tools to track and analyze user interactions and the general impact of your experiments.</p>
<p>Utilize the data collected to perform in-depth data-driven analysis. Look for trends, anomalies, and insights that can inform future decisions. Analyze both quantitative data, such as user engagement metrics, and qualitative data, like user feedback, to get a comprehensive view of the feature's performance. This analysis should inform whether to iterate, maintain, or roll back the feature.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="learning-from-results-and-iteration">Learning from Results and Iteration<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/#learning-from-results-and-iteration">​</a></h3>
<p>Every experiment offers valuable insights, regardless of its outcome. It's important to learn from both successes and failures. After analyzing the results, iterate on the feature based on the learnings.</p>
<p>If the feature was successful, consider how it can be optimized further or what other areas could benefit from a similar approach. In cases where the feature didn't perform as expected, analyze the reasons behind this and how they can inform future experiments.</p>
<p>The iterative process is crucial in fine-tuning features and aligning them more closely with user needs and business objectives.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/24/feature-flags-for-experimentation-and-growth/#conclusion">​</a></h2>
<p>As businesses become more data-centric and user-focused, the role of feature flags in facilitating a culture of continuous improvement and innovation becomes increasingly vital. Looking forward, the potential of feature flags extends beyond current applications. As technology advances, we can anticipate even more sophisticated uses of feature flags, further empowering businesses to grow and adapt in an ever-changing digital landscape.</p>
<p>Embracing this tool equips businesses with the means to innovate fearlessly, respond swiftly to market changes, and ultimately drive sustained growth in an increasingly competitive digital ecosystem.</p>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a> supports simple feature toggles, user segmentation, and A/B testing and has a generous <a href="https://app.configcat.com/signup" target="_blank" rel="noopener noreferrer">free tier</a> for low-volume use cases or those just starting out.</p>
<p>For more feature flagging goodies, stay connected to ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flag</category>
            <category>growth hacking</category>
            <category>experiment</category>
            <category>business</category>
            <category>feature management</category>
        </item>
        <item>
            <title><![CDATA[Using Feature Flags in a Next.js Application]]></title>
            <link>https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/</link>
            <guid>https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/</guid>
            <pubDate>Thu, 18 Jul 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[A step-by-step guide on implementing ConfigCat feature flags in a Next.js Application.]]></description>
            <content:encoded><![CDATA[<p>As developers, our job often involves regularly releasing new features. But how can we ensure these new features are working properly before safely releasing them to all users? It's simple: by using feature flags!</p>
<p><img decoding="async" loading="lazy" alt="Feature flags in Next.js cover" src="https://configcat.com/blog/assets/images/using-feature-flags-in-nextjs-cover-3ff95a02f33e8c778117eb32964ff312.jpg" width="1200" height="630" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-are-feature-flags">What are feature flags?<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/#what-are-feature-flags">​</a></h2>
<p>Many companies struggle to roll out new features and functionalities in an incremental way. Feature flagging is a mechanism used to control access to certain features with simple switches called <a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer">feature flags</a>, feature toggles, or feature switches.</p>
<p>Using feature flags, anyone can safely test code in production, perform canary releases, conduct <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/#so-what-is-ab-testing" target="_blank" rel="noopener noreferrer">A/B testing</a>, and more. You can also deliver features and functionalities to specific groups of users by attaching <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer">targeting rules</a> to your feature flags.</p>
<p><img decoding="async" loading="lazy" alt="Feature flags illustration" src="https://configcat.com/blog/assets/images/feature-flags-illustration-28f8b2dd75aa7530006341f6f9e1f7e7.png" width="800" height="394" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="using-feature-flags-in-a-nextjs-app">Using feature flags in a Next.js app<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/#using-feature-flags-in-a-nextjs-app">​</a></h2>
<p><a href="https://github.com/configcat-labs/feature-flags-in-nextjs-sample" target="_blank" rel="noopener noreferrer">Here is the sample code</a> on GitHub if you want to follow along.</p>
<p>Consider this scenario: Suppose we implemented a new feature in a Next.js application that allowed us to generate random user profiles on every page load, and we wanted to roll this out to our user base.</p>
<p>As you may have guessed already, wrapping this feature in a feature flag would give us the perfect control needed to plan a feature release to our users either through incremental roll-out via user segmentation or performing an all-out release.</p>
<p>We will examine how we can accomplish this by creating a Next.js application that incorporates the feature with a feature flag in a step-by-step process.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="requirements">Requirements<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/#requirements">​</a></h3>
<ul>
<li>Basic knowledge of <a href="https://nextjs.org/" target="_blank" rel="noopener noreferrer">Next.js</a>.</li>
<li>A local installation of <a href="https://nodejs.org/" target="_blank" rel="noopener noreferrer">Node</a> and <a href="https://www.npmjs.com/" target="_blank" rel="noopener noreferrer">NPM</a>.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-1-create-a-feature-flag">Step 1: Create a feature flag<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/#step-1-create-a-feature-flag">​</a></h3>
<p>Rather than going through the hassle of building and managing an actual feature flag from scratch, I’ll be using <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat's</a> feature flag service to create and remotely manage our feature flag from its dashboard.</p>
<p>So quickly jump to ConfigCat and <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">create a free account</a>, then:</p>
<ol>
<li>Navigate to your <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer">dashboard</a>.</li>
<li>Click the <strong>Add feature flag</strong> button and provide the required details to create the flag.</li>
<li><a href="https://app.configcat.com/sdkkey" target="_blank" rel="noopener noreferrer">Copy your ConfigCat SDK Key</a> - This will enable the Next.js app to connect to and query the status of your feature flag.</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-2-configure-and-set-up-targeting-rules">Step 2: Configure and set up targeting rules<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/#step-2-configure-and-set-up-targeting-rules">​</a></h3>
<p>As a feature flag management service, ConfigCat provides multiple ways to <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer">target your users</a> with feature flags to achieve a controlled feature release. This can be done by targeting a certain percentage of your users or through user segmentation where you can specify the target audience for your feature release based on a list of predefined (or custom) shared attributes such as location, gender, age, etc.</p>
<p>To keep things simple, I'll be using the default settings, which target all users.</p>
<p><img decoding="async" loading="lazy" alt="Random user feature flag" src="https://configcat.com/blog/assets/images/random-user-feature-flag-on-980a199129a32e8488e8a946b513918e.png" width="800" height="216" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-3-initialize-a-nextjs-app">Step 3: Initialize a Next.js app<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/#step-3-initialize-a-nextjs-app">​</a></h3>
<p>Now that we have our feature flag ready, It's time for us to create a Next.js application. Let's run the <code>create-next-app</code> command to quickly bootstrap a Next.js application:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">npx create-next-app@latest</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Afterwards, run the following command to start the local development server and visit <a href="http://localhost:3000/" target="_blank" rel="noopener noreferrer">http://localhost:3000</a> to view the app in your browser:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">npm run dev</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p><img decoding="async" loading="lazy" alt="Base Next.js demo app" src="https://configcat.com/blog/assets/images/base-nextjs-app-6bf861b0fea9a3670cf88cacf6a25f8d.png" width="800" height="450" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-4-create-the-random-user-generator-feature">Step 4: Create the random user generator feature<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/#step-4-create-the-random-user-generator-feature">​</a></h3>
<p>There are two ways that Next.js pre-renders web pages: Static Generation and Server-side Rendering. In Static Generation, the pages are generated at build time while in Server-side rendering, the page is generated on the server on each request before being sent to the client.</p>
<p>We will be taking the Server-side rendering route. We'll be using a third-party <a href="https://randomuser.me/documentation" target="_blank" rel="noopener noreferrer">Random User API</a> to get new random user data on each user request (whenever the page is loaded/reloaded).</p>
<p>Let's get to it.</p>
<p>I'll start by clearing the code in the <code>pages/index.js</code> file. We'll add a <code>getServerSideProps</code> function that would be responsible for fetching requests on the server before sending the page to the client.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getServerSideProps </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">async</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Create the ConfigCat client with your SDK Key</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> configCatClient </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR-SDK-KEY"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Get your setting value</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> randomUserFeature </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"randomUserFeature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Get a random user</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> randomUser </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getRandomUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Return the data as props </span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">props</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token literal-property property">randomUser</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> randomUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">results</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      randomUserFeature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> satisfies </span><span class="token maybe-class-name">GetServerSideProps</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">randomUser</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token maybe-class-name">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">randomUserFeature</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> boolean</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This random user API returns an array containing an object of randomly generated user details:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  "results": [{</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    "gender": "male",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    "name": {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "title": "Mr",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "first": "Batur",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "last": "Tekand"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    "email": "batur.tekand@example.com",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    "dob": {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "date": "1946-12-12T11:50:21.801Z",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "age": 77</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    "registered": {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "date": "2013-09-20T15:27:53.648Z",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "age": 10</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    "picture": {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "large": "https://randomuser.me/api/portraits/men/71.jpg",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "medium": "https://randomuser.me/api/portraits/med/men/71.jpg",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "thumbnail": "https://randomuser.me/api/portraits/thumb/men/71.jpg"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    "nat": "TR"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  }],</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>After making the request on the server, the next step is to use the data in our component's template to render the random user.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:rgb(130, 170, 255)">Home</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token parameter"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token parameter">  randomUser</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token parameter">  randomUserFeature</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token parameter"></span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">InferGetServerSidePropsType</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token parameter keyword" style="font-style:italic">typeof</span><span class="token parameter"> getServerSideProps</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">Head</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">title</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token maybe-class-name">Feature</span><span class="token plain"> </span><span class="token maybe-class-name">Flags</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> </span><span class="token maybe-class-name">Next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">js</span><span class="token plain"> </span><span class="token maybe-class-name">Sample</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">title</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">meta name</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"description"</span><span class="token plain"> content</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"Generated by create next app"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">meta name</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"viewport"</span><span class="token plain"> content</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"width=device-width, initial-scale=1"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">link rel</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"icon"</span><span class="token plain"> href</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"/favicon.ico"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token maybe-class-name">Head</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">main</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">UserCard</span><span class="token plain"> user</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">randomUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token maybe-class-name">UserCard</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">main</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With that, we have a Next.js app with a feature that displays a random user on each page load/reload:</p>
<p><img decoding="async" loading="lazy" alt="Random user generator page" src="https://configcat.com/blog/assets/images/random-user-page-4d974a87aa730f2d2ad7721d3b2d6c73.png" width="800" height="403" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-5-integrating-the-feature-flag">Step 5: Integrating the feature flag<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/#step-5-integrating-the-feature-flag">​</a></h3>
<p>Now that we have our feature ready, it's time to connect our Next.js application to <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a>.</p>
<p>I will start by installing their <a href="https://configcat.com/docs/sdk-reference/js-ssr/" target="_blank" rel="noopener noreferrer">JavaScript (SSR) SDK</a> via NPM:</p>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">  npm i configcat-js-ssr</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Afterward, I'll import the installed package into <code>pages/index.js</code> and refactor the <code>getServerSideProps</code> function by initializing the ConfigCat client with my SDK key copied from the dashboard:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getServerSideProps </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Create the ConfigCat client with your SDK Key</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> configCatClient </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"YOUR-SDK-KEY"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Get your setting value</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> randomUserFeature </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> configCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getValueAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">"randomUserFeature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Get a random user</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> randomUser </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getRandomUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Return the data as props</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">props</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token literal-property property">randomUser</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> randomUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">results</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          randomUserFeature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> satisfies </span><span class="token maybe-class-name">GetServerSideProps</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">randomUser</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token maybe-class-name">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token literal-property property">randomUserFeature</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> boolean</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The next step is to refactor the template to only render the random profile card if the feature flag is toggled on, and to otherwise render a different message:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:rgb(130, 170, 255)">Home</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token parameter"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token parameter">  randomUser</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token parameter">  randomUserFeature</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token parameter"></span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">InferGetServerSidePropsType</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token parameter keyword" style="font-style:italic">typeof</span><span class="token parameter"> getServerSideProps</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">Head</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">title</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token maybe-class-name">Feature</span><span class="token plain"> </span><span class="token maybe-class-name">Flags</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> </span><span class="token maybe-class-name">Next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">js</span><span class="token plain"> </span><span class="token maybe-class-name">Sample</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">title</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">meta name</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"description"</span><span class="token plain"> content</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"Generated by create next app"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">meta name</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"viewport"</span><span class="token plain"> content</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"width=device-width, initial-scale=1"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">link rel</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"icon"</span><span class="token plain"> href</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"/favicon.ico"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token maybe-class-name">Head</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">main</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">randomUserFeature </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token maybe-class-name">UserCard</span><span class="token plain"> user</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">randomUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token maybe-class-name">UserCard</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">p</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token maybe-class-name">Feature</span><span class="token plain"> has been toggled off</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">p</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">main</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With that final touch, our feature flag now has control over the random user card. If the feature is toggled on:</p>
<p><img decoding="async" loading="lazy" alt="Feature flag toggled on" src="https://configcat.com/blog/assets/images/random-user-feature-flag-on-980a199129a32e8488e8a946b513918e.png" width="800" height="216" class="img_ev3q"></p>
<p>The users will see the random user card:</p>
<p><img decoding="async" loading="lazy" alt="Feature enabled" src="https://configcat.com/blog/assets/images/feature-on-f86a56e2b1e75ae642a696719d3ce70d.png" width="800" height="449" class="img_ev3q"></p>
<p>But when the feature flag is toggled off:</p>
<p><img decoding="async" loading="lazy" alt="Feature flag toggled off" src="https://configcat.com/blog/assets/images/random-user-feature-flag-off-52c68cab7cec30b86d9883f9639563ed.png" width="800" height="214" class="img_ev3q"></p>
<p>The users have no access to the feature:</p>
<p><img decoding="async" loading="lazy" alt="Feature disabled" src="https://configcat.com/blog/assets/images/feature-off-a74f16df9a9c15850b89fe8408a1d3cf.png" width="800" height="449" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="final-thoughts">Final thoughts<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2022/04/22/how-to-use-feature-flags-in-nextjs/#final-thoughts">​</a></h2>
<p>We have seen how feature flagging takes a simple concept - choosing between different code paths at runtime - to help teams introduce features in a controlled manner while in production.</p>
<p>Through feature flagging, you can ship code more frequently, test in production, perform canary deployment, and master feature releases to deliver high-quality software while also reducing some of the risks that come with continuous deployment.</p>
<p>You may find the following links helpful if you'd like to explore further:</p>
<ul>
<li><a href="https://github.com/configcat-labs/feature-flags-in-nextjs-sample" target="_blank" rel="noopener noreferrer">Source code for sample application</a></li>
<li><a href="https://configcat.com/docs/" target="_blank" rel="noopener noreferrer">ConfigCat Docs</a></li>
<li><a href="https://configcat.com/blog" target="_blank" rel="noopener noreferrer">ConfigCat Blog</a></li>
</ul>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a> supports simple feature toggles, user segmentation, and A/B testing and has a generous <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">free tier</a> for low-volume use cases or those just starting out.</p>
<p>For more information, follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>next.js</category>
            <category>how to</category>
            <category>react</category>
            <category>feature management</category>
            <category>feature flags</category>
        </item>
        <item>
            <title><![CDATA[How to Use Feature Flags with Kubernetes]]></title>
            <link>https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/</link>
            <guid>https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/</guid>
            <pubDate>Mon, 08 Jul 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[A step-by-step guide on using ConfigCat feature flags with Kubernetes for smoother deployments.]]></description>
            <content:encoded><![CDATA[<p>In a <a href="https://configcat.com/blog/2023/11/10/how-to-use-configcat-with-docker/" target="_blank" rel="noopener noreferrer">previous post</a>, I covered best practices and tips for using ConfigCat feature flags with <a href="https://www.docker.com/" target="_blank" rel="noopener noreferrer">Docker</a>. While Docker has advantages for easily sharing and deploying containerized applications, it poses challenges when deploying and managing those containers at scale. This is where <a href="https://kubernetes.io/" target="_blank" rel="noopener noreferrer">Kubernetes</a> comes in. Using feature flags, you can control your Kubernetes deployments and services with a simple click without editing your <code>.yaml</code> config files. Let's take a look together!</p>
<p><img decoding="async" loading="lazy" alt="Feature flags with docker cover" src="https://configcat.com/blog/assets/images/how-to-use-feature-flags-with-kubernetes-cover-871660d1cd3365b9a15286a454997cb6.png" width="1200" height="630" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="kubernetes-overview">Kubernetes Overview<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#kubernetes-overview">​</a></h2>
<p>If you have been using Docker, you may have heard of Kubernetes. It is an open-source container orchestration platform that allows you to manage and deploy containerized applications as you did with Docker but at a larger scale. While Docker helps developers to share and deploy their applications in containerized environments, its limitations can surface in complex scenarios. For example, you may need to deploy multiple containers across multiple machines and control what happens when one of the containers crashes. What if you need to spin up new containers on the fly to handle increased traffic?</p>
<p>You can think of Kubernetes as a framework of industry standards and best practices for deploying and managing containerized applications. It is platform agnostic and can be used to manage containers from many containerization platforms such as <a href="https://containerd.io/" target="_blank" rel="noopener noreferrer">containerd</a> and <a href="https://cri-o.io/" target="_blank" rel="noopener noreferrer">Docker</a>. Kubernetes can also work with any cloud provider like <a href="https://aws.amazon.com/" target="_blank" rel="noopener noreferrer">AWS</a>, <a href="https://azure.microsoft.com/" target="_blank" rel="noopener noreferrer">Azure</a>, or <a href="https://cloud.google.com/" target="_blank" rel="noopener noreferrer">Google Cloud</a>.</p>
<p>Kubernetes uses configurations from <a href="https://yaml.org/" target="_blank" rel="noopener noreferrer">YAML</a> or <a href="https://www.json.org/json-en.html" target="_blank" rel="noopener noreferrer">JSON</a> files that can specify the number of containers to deploy, the container image to use, and the ports to expose, etc. But how can you dynamically change these configurations without editing your config files? <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer">Feature flags</a> could help.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="feature-flags-and-kubernetes">Feature Flags and Kubernetes<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#feature-flags-and-kubernetes">​</a></h2>
<p><a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer">Feature flags</a> are a piece of code that conditionally hides and displays functionality. When a flag is true, the feature or block of code it controls is rendered and shown to users or hidden otherwise. Feature flags could integrate with <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer">many programming languages</a> and technologies, including Kubernetes.</p>
<p>Feature flags also come in useful when you need to minimize the risk of a deployment. For example, in the context of Kubernetes, if you have a container image that is not compatible with the current version of your application, it can be quickly replaced with a compatible one via a feature flag toggle. Other use cases can include <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B testing</a> and controlling how your <a href="https://configcat.com/blog/2023/04/05/using-feature-flags-in-cicd-pipelines/" target="_blank" rel="noopener noreferrer">continuous integration pipeline</a> deploys your application.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="using-a-feature-flag-provider">Using a Feature Flag Provider<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#using-a-feature-flag-provider">​</a></h2>
<p>To keep your feature flags organized and easily accessible, you can use a feature flag provider. <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a> allows you to manage your feature flags from an easy-to-use <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer">dashboard</a>, including the ability to set targeting rules for releasing features to a specific segment of users.</p>
<p>Let's discuss how you can create a feature flag in ConfigCat and use it to toggle between two versions of a <code>Node.js</code> image for a Kubernetes container.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-to-integrate-configcat-feature-flags-with-kubernetes">How to Integrate ConfigCat Feature Flags with Kubernetes<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#how-to-integrate-configcat-feature-flags-with-kubernetes">​</a></h2>
<p>Thanks to the open-source nature and wide adoption of Kubernetes, there are many ways to add feature flags. Kubernetes comes with an API that allows you to interact with it from your code. One of its <a href="https://kubernetes.io/docs/reference/#officially-supported-client-libraries" target="_blank" rel="noopener noreferrer">Official client libraries</a> is the <a href="https://github.com/kubernetes-client/python" target="_blank" rel="noopener noreferrer">Kubernetes Python client library</a>. In the upcoming demo, I'll use this library with the <a href="https://configcat.com/docs/sdk-reference/python/" target="_blank" rel="noopener noreferrer">ConfigCat's Python SDK</a> to integrate feature flags with Kubernetes.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="prerequisites">Prerequisites<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#prerequisites">​</a></h3>
<p>In the demo, I'll use Kubernetes through the Docker Desktop application. To follow along, you'll need to have the following installed on your machine:</p>
<ul>
<li><a href="https://www.docker.com/products/docker-desktop/" target="_blank" rel="noopener noreferrer">Docker Desktop</a></li>
<li><a href="https://www.python.org/downloads/" target="_blank" rel="noopener noreferrer">Python 3</a></li>
<li><a href="https://pip.pypa.io/en/stable/installation/" target="_blank" rel="noopener noreferrer">pip</a></li>
<li><a href="https://git-scm.com/downloads" target="_blank" rel="noopener noreferrer">Git</a></li>
<li>A code editor such as <a href="https://code.visualstudio.com/" target="_blank" rel="noopener noreferrer">VS Code</a></li>
<li>Basic knowledge of <a href="https://www.python.org/" target="_blank" rel="noopener noreferrer">Python</a> and <a href="https://kubernetes.io/" target="_blank" rel="noopener noreferrer">Kubernetes</a></li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="setting-up-the-demo">Setting up the Demo<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#setting-up-the-demo">​</a></h3>
<p>To get started, open up a terminal and clone the demo repository with the following command:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">git clone git@github.com:configcat-labs/feature-flags-with-kubernetes.git</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With the demo cloned, I'll walk you through the steps to build it from scratch to give you a better understanding of how it works. Feel free to refer to the source code above if you get stuck.</p>
<ol>
<li>Create a new folder on your computer and name it <code>feature-flags-with-kubernetes</code>. Then create a new folder called <code>backend</code> with an <code>app.js</code> file in it with the following content:</li>
</ol>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> http </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">require</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'http'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> server </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> http</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">createServer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">req</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">req</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">end</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'Hello from the node kubernetes pod!'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">server</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">listen</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">3000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="2">
<li>Create two Dockerfiles named <code>Dockerfile.with-node18</code> and <code>Dockerfile.with-node20</code> in the root folder with the following content:</li>
</ol>
<div class="language-Dockerfile language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Specify the base image</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">FROM node:18-alpine</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Set the working directory in the Docker image</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">WORKDIR /backend</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Copy the application files to the working directory</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY ./backend .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Export port 3000</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">EXPOSE 3000</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Run the application</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">CMD ["node", "app.js"]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-Dockerfile language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Dockerfile.with-node20</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Specify the base image</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">FROM node:20-alpine</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Set the working directory in the Docker image</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">WORKDIR /backend</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Copy the application files to the working directory</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY ./backend .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Export port 3000</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">EXPOSE 3000</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Run the application</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">CMD ["node", "app.js"]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<blockquote>
<p>Based on the state of the feature flag, we'll tell Kubernetes which Dockerfile to use to build the image for the backend container.</p>
</blockquote>
<ol start="3">
<li>Create a file <code>deployment.yaml</code> in the root folder with the following content. This file is called a deployment file and contains instructions for Kubernetes to deploy a single container with the image specified in the <code>image</code> property. <code>backend-with-node18</code> is the default. I'll show you how to change it dynamically based on the value of the feature flag.</li>
</ol>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> apps/v1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> backend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">replicas</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">selector</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">matchLabels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> backend</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">template</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">labels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> backend</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">containers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> backend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">container</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> backend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">with</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">node18</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">imagePullPolicy</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Never</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">containerPort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">3000</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="4">
<li>To expose the <code>backend-container</code> and make it accessible from outside the pod and in the browser, create a file called <code>service.yaml</code> in the root of the <code>feature-flags-with-kubernetes</code> folder with the following content:</li>
</ol>
<div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Service</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> backend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">service</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">selector</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> backend</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">protocol</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> TCP</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">port</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">3000</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">targetPort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">3000</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> LoadBalancer</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="5">
<li>Point your terminal to the root folder and execute the following commands to set a Python virtual environment, activate it, and install the required dependencies:</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">python3 -m venv venv</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">source venv/bin/activate</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Create a file called <code>requirements.txt</code> in the root folder. You can copy the contents from the <code>requirements.txt</code> file <a href="https://github.com/configcat-labs/feature-flags-with-kubernetes/blob/master/requirements.txt" target="_blank" rel="noopener noreferrer">here</a>. Then install the dependencies with the following command:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">pip3 install -r requirements.txt</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="6">
<li>Build and tag each of the Docker images from the Dockerfiles with the following commands:</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">docker build -f Dockerfile.with-node18 -t backend-with-node18:latest .</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">docker build -f Dockerfile.with-node20 -t backend-with-node20:latest .</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Both images should now be available in your Docker Desktop application:</p>
<p><img decoding="async" loading="lazy" alt="Docker images created" src="https://configcat.com/blog/assets/images/docker-images-8e69441a0b7f2802e1021f3125d39f4c.png" width="800" height="456" class="img_ev3q"></p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="creating-a-feature-flag">Creating a Feature Flag<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#creating-a-feature-flag">​</a></h4>
<ol>
<li>Create a <a href="https://app.configcat.com/signup" target="_blank" rel="noopener noreferrer">free-tier account</a> on ConfigCat and create a feature flag with the following details:</li>
</ol>
<p><img decoding="async" loading="lazy" alt="Creating a feature flag" src="https://configcat.com/blog/assets/images/creating-a-feature-flag-16ab9062df69f0159cfff23f01c9515e.png" width="800" height="655" class="img_ev3q"></p>
<ol start="2">
<li>Copy your SDK key by clicking on the <strong>VIEW SDK KEY</strong> button on the top right corner of the dashboard.</li>
</ol>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="setting-up-the-kubernetes-script">Setting up the Kubernetes Script<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#setting-up-the-kubernetes-script">​</a></h4>
<ol>
<li>
<p>In the root folder, create a file called <code>kubernetes-script.py</code> with the content <strong><a href="https://github.com/configcat-labs/feature-flags-with-kubernetes/blob/master/kubernetes-script.py" target="_blank" rel="noopener noreferrer">here</a></strong>. This script will create the deployment and service from the <code>.yaml</code> files created earlier and update/patch in the appropriate <code>Node.js</code> image based on the value of the feature flag. I've added comments to explain what each line does.</p>
</li>
<li>
<p>Execute the script with the following command:</p>
</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">python3 kubernetes-script.py</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="3">
<li>If you've followed the steps correctly, you should be able to access the application at <a href="http://localhost:3000/" target="_blank" rel="noopener noreferrer">http://localhost:3000</a> and see the following:</li>
</ol>
<p><img decoding="async" loading="lazy" alt="App in browser" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAHECAMAAAD25L7nAAACAVBMVEUcGyIqKTJCQU0dHCMAAAAbGiEQEBJAP0sbGyIYFx4dGyMhICX///8dGyEfHiQaGSAjIilFRE8vLjIlJCkeHSO8vL8nJivz8/b9/f8iISgsKzT7+/8sLDD4+PwpKCxQT1YoyEDn5urp6e319fkZGB/x8PTs7O8qKi7j4+c8PD8xMDQuLTYAAAf6+v1KSU0FAxDS0tZ7e4DQ0NPIyMu/v8KSkpYWFRyNjZHu7vHa2d3OztE1NDu5ubzLy86BgIV4eHtHRkokIyggHCB+foLW1tnFxcixsbX+X1dCQkaGhotYV10QDhcAAAypqKygoKNIR1D39/shICmsrK+Dg4cAAR4UExrCwsWJiY5ycnYoJi8LCRXg4OSkpKdhYWdOTlI+PUozMkG0tLeXl5pAP0MCGCC2trl6eX5ranBfXmQ7OkczMzj/vC79uy3d3eBlZGpMTE8kIjaurrJIR1I3NkM3NzwcISEnHSH/X1c6OT4dGyebm55ubnJUU1oSEBpcW2ADEB8ZAB9LSlR1dHovLT1oZ2z/YVkozUErKTskHSEaGCQpJzkdHSHYUk0pqTvXoC0dDyIgHTP/vy8NBitAKyQZFS//wS0BACUnvT3wsS08ISUdMCMqIyIXFSKfQD4mfjHwWlOfdilKOSXvWlQgPiehQD0lfzH/wS+fdiv/wzCfdykgPiY2gJghAAAcT0lEQVR42uyd+1MSURSAd9bLLA0seRVamiIThIypQMske9iQUhiC4ZpNRayFj+1hxCbOGIVIioMvVLTX9H73V3ZBNDShSYtZmPuN7tG7+wMz7Dfnnrtnd4mzxh1lhIigd5ZXle8kju/2kqWKd/dxiYTAFAcXdhKiIiNIlwDJUgUKXViQouG2uBJIRpAaaekmEJRCpDVYkGJhXw1NiImMIARFli4UsQMLUizsFtlXtZpBSloQ6Q48xyoWFOJKIFgQjLgQVwWCBcFgUigOGCvSGA8osCCY4sGK2DhGW630b2NTUzSxVSSKGrBGjUKCBcEUB3Qw6PMFg/Q6ZV4Fw+Hgq3XaTA0Nzc0NDU0RW0NmcoyoMoyYTDIsCKJSKbJyELMR6aQ17Hvxwhe2Tkqzxlh2cZFlaTS2yhA9Ovry5egoPURsBWUlMMv3yNUIFOpBpRILQkvARSWBETPSSZ/v0/Tbt9Ovfb5VG6RBNvxu9vnz2XdhNihd9WN07s3Ms2czb+ZGt2RImWxfbyN4aEQ8BA02WXlZHkECm51hMEC5XLkdghCuBPL3ECALCuVd+SheKq8gZRJl862r2BBRM+lbnB4fHx4eH59e9E1mxtj3s/Nf5ueX5mffs5OrfvyYmZjYv39iYubjVgyRlAPESWOakwAcArslOQXhFzbxAEYTrrgf/q4NmcYlxHikD4z6vXBjoBZ4soCgzxQLUBTaQCqfIDJwhGkGlQRGvNBW3/T4+TTj0z4rvVKyh2eX7qZZmg2vlO9T9NwM0iPFxMwc/fd1yC7QqZXL1Rnkcm0n2JVLEN7jjHhJCH/lBYiInWlIdjdygXWjSIGF9HFUwlMXikMqNtYZ4DYEb8TpKaQhFGxpOBSJHGpowYIUO8HwJ+TH8HDakNfhIIF4xb5bunsnBTLkHftqJYG8QX5kDHnz9ylEseOxQdujWqNHq3VIFJsL4vJ3dwzwLi5KQgp6Y4KLhHxcqAKttcDcAgQKWSHEvKl9cS6S7LbFKOiCUVUHw9yMcccOd1T3C9F1gavTXIlCsmDAeIOhcXm50dAQhzkFKZPJKg/dZ/rAPpkMz7LEijWYSiDDSJGVFBK0pha12NkvSJC0IfOzbJBGY0OjM78EmRkdoom/QwZuyXtAFj3yg0C2uSDQb2cGotH+MYFzxSJ1ngRMVJ0b5MHla6CpiTxHCdA/UBeJBeJVZwb9icv6fjTz8nfuuc7XW5Ld8vYBvRk0ZocEa6vmC1r/BxyNFrvd0ugI5KxBaElqmnmLeQRMAHRhQ0SK1ffiwzBKIMgPtP3wwmdFY+HF5/Orgtx5vhhGY1NzL5/tX+PZy7mpvxbkoFoFDlYYzyKMFQeBSp1HkG5mQGjS6Wr7Fxr1jKbX5OxgNLaUIEd12sPX2hI2HaNvYO0G/Z4eu05jaHPXC4N2Fqgs4Fi1H7j164IlAlrqQYQsIFRk2a7X25cjuYt0ifLIkfu3nmqcB24cuV9xXGy9DZg1Qd6m9UhtfhPk7r8W5DY4q5HLNWfRH/kF0fHte+xPLPWs3kzZmFC7Dag6TMeQIJqxM4dHPOoHfL0emA1sw+WF3uonyVMnSD5+qlo+AszmBa5bRzZlBw9vaGcDZB4KL0glaGYQGrWaYfQaN9hLYMTIyhQrnT7WTbHSNQj6vbu07SlWtiDGiw97VarehxeNfxJEqDcD8EA7phtLclXeNlVT7eE4EqTJDBK1bqeFX7iiG3QevtYTArZqzstzJOd3XtbeM9W3LHCNyIzs8OSK7o8lSKGnWMqLt5qb+x451apHfc11IYeCwIiSYPh1qkhHgmQX6V/n76ayB1rGmv+6WqR/3k6RnhGkQtkFEF3KivyC2HVcUwtA5/4VXR8rtJHXDO2tGn9aEBNf6x7R845m3ZhjTGXRLttq/aR/OXqmEYBH6qentH7wwAJU2YF1a8k/liAFLtJp5VWA2IdqkBQK3IQiUjLLvMM5lnm/zYbp7S7zZgtCKCuMxgolkREk9yoWdV09MsYcBYZ7AyrG09G6YFYnkCD15kNCbU+VWuW5Z0iqWtleNefe05l0qlin2jnQ2lF1Rv6gX1cPutcFsxkUdoaFlnlBJALyLvMqKyv3mW4wfWBvZaUM+yFacl0oXJrfeKHw41YvFGYX6RnyF+nxTsOT2DGGaRlInKtlGDfr1jG1huipE+DoaZNwwgauW5jqTnZEz+jbk1eq9VWtBpJDx+tHotFTmo7aQT6WFTyc9oFpCzV6QS4U6vF1EJGTajV5navV5Pv6VpPPWa0m/3GZl6RcbZDyt3nigivKP61KkLEng0KIrAp5QyGKCkVIfwCd/IEk7A/5oQAHIIQUlWh7FEhAKv50jOKyA0z2aZq3UIIUoNVEBu5r6rAgImfzZkV6q82K279QiKB4inTxAoQUJDneRUKBI3nSm/4heS/p8nIUpNA2tY8S0AlJouM5b4AkIRdFu7IC9N+8FxHB0yA2EUTZVeEOARmBETcFaHfPtJqo18jXaoKAG9oN0QaFLLL2kTB/syIVCYihS3izbl7lceDA9XkRUIAbpiTlwHEwCwcolxSo3Z0Sgx+bCkKU7cV+YDKG7JKALNC/+H4QDCYLhSwLBb4nHYPBTzXBgmCwIFgQzKbgR4/iR49i8oAfXo0fXo0pAL9ef1CqOYTCrz/AbP8FOpe8pfqCEOi9hF+gg9meIBLJ8UuClypFvAL2A7PtDIIM6ZIS0tKDkHZhPzDbFYRGhkhqdpQiNRLsB2Yb1CBBalCUlC4EpngoExk/2TvXnjSWMI6zhz8vPCwL3YXljgHkIncFEYqIBDEI4lEbteIlUSMaEzUmvBCtTWp843fww54BURQX62nSw7ad34tufXa9JfNz5pl5dkavyu/kVXplm79/P5SUXwoFIz+CDIUiE+QoCIUiG6ggFAoVhLEwFMp/5o8RxMIs65UUym+RpDM/wQ+lVkGh/Hf+DEGYZS3dEppCBekLPVOAQgV5A9p/UKgg7xeEozuoU6gg/QThbJWKjXtjsxXa31D+H0EswaA8FiCeNXm9bwQ6HTS2VxqoxBG0iDroFuuUNwWx9DbrH3oqeBFsNsk/TLAxYE26gmh8ZixUU6kqIDp6/MijdhaJRM5GsZrXvuxZ+ib5ek6h4TTfreF/vD7+HEpNJ0A7K7kj2fLFDcs7/NgQ33wq0wRmZoD7iyY2BmyIsuOAXgAuU6mVlZR3D3Don/cUIuadxhYeQzIkvjAkqe3jgHIoqVStdr+KlFUazsbzYruHsvlsenLlyFVQdQJ0gk3eMK8JLpdKG5bv+1EqLQeZvjSwYzhJpU4MX1BOlJYHaEhXEG4Ik07PHAeod92b0xjhnrXnpNYVP6zXbz7Z2VgolH/e6vuNuTRaQdTqfdLdQHKkbZVWtwqCoNKKICjVI+YkCKK2E6Bb8soaCT+aHwrlZk/Tl3qsXPjQ/7EGJo3Og/X5A5dx74Q9uw8yg0TZGQ+huGQYRdLGr2JmLZyAWv/8hA7jLQi8MczGkqvqJ3MWMv4t2JRmXTt7b101xA21zqz3YXccV/5bODhFJ9T6NmYdRz5wCGTspVHpEKjGE2PQiRiLj29Fr4WFjfNY8Qqi0AnQQw/kjKQf28vvGWItb/c3JINJ0xzaTLEm49mdHAQRcBUeQ4XniA62EObDhxCeCRIx1mHz1XbspjBrgEPZPRGLnUJAAEKiXsWRa5Tcc0QBIYCsC2PWHJAkQyaRhPJqrVkAKr4Fvb8Kn44XK41NU9rL7gHzrHeWzcKBWTbmCd88BQSaiMgYST+alg591OjQ7GtIsLljnEPm4jhz/CXNmuzDsuhB8jj0RK7FTspRi3gOkX8hSA4Cp1Wm7Ua7ZzSq7gpi3YUNke19cNwQIkfH0GuQ2Y4gj6ITdfc2f6SEWSChHdSEEHaOHEiW2SIyIKywdWDTCThd1zhn53HJXmLfk0boIfAJDgVFtvS2/ZYf9wyz0YaRpHv3vmWIlEUXMDiRIVI0kGCNdmdpWQ6CqEP7qXmITzl5aj+k7hVEoV5Q7vCfjGd4LsgBagbrUngFIgxWu7sKVN3ucNGHeEuQj56w6wrYc9utWdWCJWt3GydnPFZ7KrJdzCG3DiDmxSm7BeHYuoaPHgQwxY5+fQzwCops6c28P4ydMplHjhlJjjOPMKdjHyTyeUsQJwe4eEjlz3aG95lB0s1B8kgfPDZHHgdp5PWvBFGptTXcGCMvBJnCHDuVi7OXWGENY1l2Ysf6cbvKLrYEuTGlJtfts5hnZ+srbJE8MfH1xBOoW7OnWGTnEMXVXtG9h8nwNMSoaxybaQRwaTqatrYCznE46BhLvvSUhQfr07mxDvXCZ+nx0+dCfaxDbroeZCyvR1gzqXUcP2Qq93d3jEymeXlkx/GwQqi0YTxLZHklCMnKfaj3CLILYwyA/wTGWQC75JeDphReQ7YlyB6QcCPrjgJFFlPsOlDSRolVjkxhv9ZAwsR6T7EXPoQP6TScHxHAtPVq0toJCHSqV7709iDl6dPSt386/MVI8tfj/W+l0+kyafx9BSFYMiikL3SymOZ1YM9rHuIeZnVF7x4cUoIoBOReCcJOoYSit2SawqgP4Fa8RiObaA+xlj4nYQgjPYtRLFrLw5umpVgO+9YEAklcq4H9mSOnB/NW2oP8gvQOju7KhW+1jeUHdIwkus7tjdq3QvnOwrwxxCJc4MAfsshCEK7Cey4R0JLViQCqRqbCvVsQUwINjDst1jUEcIYtMtI6JP/PtgVBS5CYHwGssGXg867HPeOwGnAcRSj6KQcf1tmrLzQH+RVhegjelaeHm8H3zGIFm8PTZen520YnSScEM/AbiCwDpFtq4kPVXQKvUvEouavwkVDPNK9AsPUOscIHSLvLuGGLmF06Qi48MWUC1lkD4n7k3C1B7JhjJ9FwubCVAPHnNBmOoxJZ/IqsvQxk2a9wOaNY6cxiXXjSWGgH6CyWvGEkDZFo9hIP9vWDjLH+eZjmPb7I4NzY+noDpCuIXkDMdY9AAPeuWHfs310o7HD7YhZrn5hw67H6WX8ERynTpsmVKViNm0biy3gKBTYHrLGB6zTrt9vHiByuWetsDTHWv7DI7uLKG0672LmnZQ+xvQ5izdF1kF8CRtqQZcv31wkl/JBaKDxnJ5BhBstTEzSvYtO7A+x4N5E0k8DLUpPbeo5Qv407a09lKPqK7eAT8HUqvjsDHuWp+HkJKKwVb6oTmKiifDBcwfyuD8xKPHEIG8bW4lvqysLMeeJieO40hMh5PDENrQOF+Hi1VhFCzNx4eyW9E6Ar6XKGIbzOQ94nSDf/6Ftqsn7gd0+gwQyWriAqIRSKLZ2vuGMIteoFpYoVCc6n5RKCfggwCyBEhaGHqzmPNjZAB4T0eWAonwRBHBFA0HJcFFgFwAmhdlypFUFQkFqs1ee1WApaWy9rJNt+832lJs23nmrgH1Ks6Nk0DA/ej64gCq1wjcVUag/Xgla63J1wVsPzYkUlL2oVeZ7nzSpSW8XzNjPRiecF3jHksGnVPKfQirxGxdlITNW+ZePIegrPK9W8TqUwk890aNrFuzZyg9x5quYlAfpyo7z5Ke+DdMvdI8Bdhhk4ymcemEXo8hDNqn4vTBFGRHL3/dD3QX5fmJ9HsBFs3gUv5LAX9Yt2qLRdV6RL1Dl1B/pnnfKnvnJLN22gyEYQ2UBHMhQqCN04jqKggtCtRylvQAWhm1dT3oAKQo8/oPSHHn/wQ9ADdCg/xB9zgM6/7NzBSiNBEAbggqpaCE3XBKcSaAhzEgJL2JXdJQvL7im7IMl5RQa8xJtP4EGfwJe2IqMjRklE9PR/h2mqu/qfufSxBwAHBAAHBOAj0ScAeBEpALwEVxEAAAAAAAAAAAAAAAAAAAAA4M2YuR+fx5m2vL01887t0fJecHUdnpNtbKRlzNThpmmSEnmMprRNhweTJtMubJnCtK5oP1pPt0MmtfavylW07MecXkVtahrPsWUCeJB9Ja2byCHTHZ9LMI15iRWlp7RIqDLtUK004klkqLQPHYrkJ6k+6Lb3Lcq0h/x/zq87H19lZuqtrBwnBHrWni+Or2fLxXTOnpJbe/nr759TaWZfvh19X0oh4lSMerUsfxyNyqGbW0k5IoptnlaiztTJNvxcLA0Go7VMjMImnR6wcUpMfbpNZP27rdxT8f7jLv79lMYs2jeRjaxHdFPo8Tb3Ejnm1tWbKsqDxi3Hnm46UqO8d9fuFLplrmdXJ2dSt8eL8xb/Xrxl72x/krfCMN6Fq8lYD6VpS2lXyhNAoDIQ5VUYKAQhPILESUAUJBHjozFBY+IH49uHxT98p1Dc47Ltw7KP/cWk0nN6nVvjT6St3A5/omAn9RW4VKeIS4AknT74qiSPQLfm2yQjSCwfTINRWMZGZlHSq+f1NXnAeZDm2OAAnaCHcRdQH6DOfmi0a+6De3UfZuFdk1hWstKF1bDH61aSkGQ7nQ5za6j6uwVJAYRVioY28eFXb5f1FOjDQgJNQ0MhyLBasAteYhnXgNfQ5diBVAAvsGzQhXSQWp6et6DQ4fgrBnS6IAEduviKgXQKSWOZZe0sr3QwIjtI4KvVj5ZxcPhOEP04iYo6TQK1GlBnIETyCPIMziLPkGQ3fr3Dnz/5XKGmVwCvy/sDME1AAT9VoLHCTxvQ2uDseUEU9eeu+OrermB/DVp9mS7Yw6wm4KINN19YpAsC8AJfLMkncWGt5l11eNLP0U1eCN66JZ2IXAwbAWhcGo9TUHvX4klMH8AFwE5BlQGmv4Ll+F8iTTy6aIDwhUedA2ovAv40JICbDYDTFrVzcgFt8S3SgIhj3RHE4a+CbAEt9QveSodGZh3B1zODCsIG0TgcUUGSl34j1IBiN2MKZsJ6NJypd2/GlZLqb+Bp24j2sL4XTm2G9DziDEXA9Tiqx8JNKLF5STdvsUrXbH1mZtOfakGy0/E2181Q6DfUMhGj9AJpJYhawVasgtm4jf1xHzljz4jOsCY2I4Z5BQWZXEbXZzCrplqqufE1dBg5B4axlN80r4GDqLGdR2EjY/j9dm0Ml6yNN2Op8uMaZovaFVQO/XuOIA7/IMg8mw2lviAU6xeNKgJ4swRhJGxRQRLoEd9OzL+e5hiKi9W2Znq1v6Ml2xGSyeca16TUyJCtpDEfEp+5t2xsLHfa/fPU5PhbNxAi9zPShGinL8+WBTAh5s6eeo3JIv0CpVTxnIxPUDrMN6JzcPJKkKMzdb6OA/UOt1Q/HyltzfVrZNXeKBT+rfA6JqV87smrp3oTqylgqnR1RHr4lo9sNoptPBHfe1kf0cNmo9yq9bOGqa72eiSHkWrV3kePVI796jckHEEc/kYQc5P+Qn3sk8rz1abaTn8SRMReCNhSrT0LOKT1I4DrPkbmoFRIDSepIQ57bylUTPD84twYR49+AQqu7QywOcexnQ7NFkR9x5XRR8lKJ8VfyT1QCuOWZK+usuQa9eVaNaPk38MaJsYdzg7zyJEp9skR1MzVc4X08TqOgdJWc4BZpsPHo11/CUDUB7gxj34bFakJWfIOQFmzBampQ6Dqt2tvLr7EHvkGEX19yxHE4S+CNIAWeb0nsXA4HPrSXQgStwURuuEslKnegmgL0qnRBzdc9yblw/oDmtGgkjTL8PfejZtcCB7e/iPq6+EVxFd3NAdUTbTs9A9BUnc4M4pYpKtHL3oeaMZQVLetac+Q7P7MEUKaWLenU0GMm9MLtfJFj9JpsSKSZhUPYrKtW35lUCUhurv8kyceHeIxfRE1aFj0HI2YGm2+QLAF2bCm+wiG/mXt9CO9azQQwMh/Rd10cPj0Ih2oEHmiXtfbCTevYd/IQ7QFicMsw/2iHyDw0RrZsmUpiCiiGeFYxKqIPN0aJ77vBYlcI0AFGS4EOdCX6R7msyChRfrkTp0B2Rj6eh+1m4G8WqutZ3ukB0yMDdxagqREPKiVC7pv48E6jRbKIqChnTpYCFLe/vHxIjgQOnLUh8eBFs2its6xCn7JV6locdfqGaQF+FQMD5e1jzeBndQWJB6JJO+8nYXDJ0GMxWne9VvSAuRrr4YaGQJyHbfkCK+oGm0ckF0oH4Kk7heCGFSQAB3qY0QP9T/dRr4TRMGWTnML7u0ckB3j2U5nPLYgxgbOIkU7/fdTo4pfYiY29CyA23jB9aeMe+oZ8vrvuCdF+MhXFEke/pI17WYAs7kQxFgKckQaQO0NcjdWBniUI4/Afg37J4A5R11ePYOUANO0az9HlhYxJLsI4HlyBYFxcFgRRJ8UAR95QY7My/49CBKqJJzrcPJpiYRa2E1tb5I9rK7yabggl1SQ5K9UowTXuQnpGWO7FtB77+RkuL0ShEu3Y5F5BV4jC2TCWKVr8lKQI3JHBczb6Wm0SMkkYcs3sxoLJzr86jpIDnf+7Z+nhn/ToNOHJLqpmgpmJFwNRe4AKoJoKd0CzD0k5mRvU/XhAT4y3rzGuz9SnqeOkY1Ux+QA8dWL9Ig6NskM61btsSmeU9t7OnXrgVZ5iQTj4LBCw1vlLIm+bz2NWbXsGyU5Ln3Sax6kZQGPk+wTMGqW7wNdjlnCd8TLBiR5oFxaHcUFTCtl3xvE1qh2yR8fwOVaBU+PshO474tAfgJ+lb66jHj5gNrlrZ2e5pO9zPnTwSuHr9nycCfNe+y1Kn2gMXxHP9vsn1+hePSU8W0gjt1muVkc8DjIQ+I7N5ffgN4MnZOjcrn1kqwPXPnh8EsH+75ytfeIUa5cnUGWV5UZlUq5iLhdewC72Wy+9YY4doZbkBgHhxUsB4AXgFdOgwXPsrwbgEyHOgA4CZQCx35/f1Tdy7i8gORlWCEJiuQGTsEC/Kdg8B6gLtCtS7DTP26qGnCnAG+nMzwsXFQdC/mvjfyDAD42SWFNgYWH4a0iPHIB0DhA4NzLVbyy15onL9M6GixWimu403sApLVl7XW3hAXcWt166DTccfhkiKixXiUhs664GFi0w2f4eCK+GAokgqxHobv5T831Ja91m5OoWBtWo8N11iXWeZFRAt/N0wKJOMuIQa83SHfb6R+35Yoyy9OV2UU6VSEgBgIBOhQU46Li+b6RP6skNG9QFIOi4KajAVGjKQqdFqSrB4JWES6azMbjXoanIXTcw8jxhFW0INJcmZXo7LjrQ5CNwwke4h+1e6wi4iLHuuj3QfI6Nys6/AMe13/6VwnX/5Lu+vc4z8cn/76qx/OXdM9qs8Lllq5qp/ynFI9jhYODjcuLtHMy18Hhn/BIjh8ODg4ODg4ODg4ODg5/sAcHAgAAAABA/q+NoKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsAcHAgAAAABA/q+NoKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqoq7MGBAAAAAACQ/2sjqKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqoKe3AgAAAAAADk/9oIqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrSHhyQAAAAAAj6/7ofoQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBOkz7Wz2+NOrUAAAAASUVORK5CYII=" width="800" height="452" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="testing-the-feature-flag">Testing the Feature Flag<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#testing-the-feature-flag">​</a></h3>
<p>To test the feature flag, return to your <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat dashboard</a> and turn on the feature flag. Execute the script again. You should now see that the container is using the <code>backend-with-node20</code> image noted by the <strong>sha256 hash of the image</strong>:</p>
<p><img decoding="async" loading="lazy" alt="Feature flag on - Using container with node20 image" src="https://configcat.com/blog/assets/images/flag-on-container-using-node20-a02ad4c478a395eb110c910dc24ab1bd.png" width="800" height="452" class="img_ev3q"></p>
<p>That's it! You've made it this far and successfully integrated feature flags with Kubernetes.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="final-thoughts">Final Thoughts<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#final-thoughts">​</a></h2>
<p>Kubernetes is platform agnostic and takes a containerized approach to developing and deploying applications further. It removes the limitations of scaling from containerization platforms like Docker. It provides a standardized framework for managing multiple containers across multiple machines and provides fault tolerance and load balancing. In the demo, I've shown you one way of using Kubernetes with feature flags. Rather than editing your <code>.yaml</code> config files each time, you can use feature flags to change your deployment and service configs on the fly dynamically. To learn more about feature flags, check out the <a href="https://configcat.com/docs/" target="_blank" rel="noopener noreferrer">ConfigCat documentation</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="references">References<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#references">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="source-code">Source Code<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#source-code">​</a></h3>
<p>You can find the complete code for the demo app <a href="https://github.com/configcat-labs/feature-flags-with-kubernetes" target="_blank" rel="noopener noreferrer">here</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="further-reading">Further Reading<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/08/using-feature-flags-with-kubernetes/#further-reading">​</a></h3>
<p>If you'd like to learn more, check out the following resources:</p>
<ul>
<li><a href="https://kubernetes.io/docs/tutorials/kubernetes-basics/" target="_blank" rel="noopener noreferrer">Learn Kubernetes Basics</a></li>
<li><a href="https://configcat.com/docs/sdk-reference/python/" target="_blank" rel="noopener noreferrer">ConfigCat Python SDK Reference</a></li>
</ul>
<p>ConfigCat supports simple feature toggles, user segmentation, and A/B testing and has a <a href="https://app.configcat.com/signup" target="_blank" rel="noopener noreferrer">generous free tier</a> for low-volume use cases or those just starting out.</p>
<p>Stay on top of the latest posts and announcements from ConfigCat on <a href="https://twitter.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature management</category>
            <category>feature flags</category>
            <category>kubernetes</category>
            <category>configcat</category>
            <category>how to</category>
        </item>
        <item>
            <title><![CDATA[The Environmental Impact of Feature Management]]></title>
            <link>https://configcat.com/blog/2024/07/04/the-environmental-impact-of-feature-management/</link>
            <guid>https://configcat.com/blog/2024/07/04/the-environmental-impact-of-feature-management/</guid>
            <pubDate>Thu, 04 Jul 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Discover how efficient feature management contributes to eco-friendly tech practices, reduces carbon footprints, and aligns with global sustainability goals in the tech industry.]]></description>
            <content:encoded><![CDATA[<p>Nowadays, the issue of sustainability has moved from the fringes of public discourse to become a central concern for industries worldwide, and the technology sector is no exception. The significance of sustainability within the technology sector has escalated more than ever before.</p>
<p>As the digital era continues to evolve at a rapid pace, the environmental footprint of the tech industry has come under increasing scrutiny. This is primarily due to the vast amounts of energy and resources consumed by technology infrastructures such as data centers, networks, and the multitude of end-user devices that have become ubiquitous daily</p>
<p><img decoding="async" loading="lazy" alt="The environmental impact of feature management cover" src="https://configcat.com/blog/assets/images/environmental-impact-of-feature-management-cover-8c6daf7fcd22ea38bcdc48574f9bc183.png" width="800" height="450" class="img_ev3q"></p>
<p>As global awareness of environmental issues such as climate change, resource depletion, and carbon emissions intensifies, the tech industry finds itself at a crossroads. It is no longer just about innovation and development; there's a growing need to balance progress with sustainable practices and environmental stewardship.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-growing-importance-of-sustainability-in-tech">The Growing Importance of Sustainability in Tech<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/04/the-environmental-impact-of-feature-management/#the-growing-importance-of-sustainability-in-tech">​</a></h2>
<p>With its large data centers, extensive network infrastructures, and billions of smart devices, the digital ecosystem has led to a significant increase in energy use and resource consumption in the tech sector. These developments, while beneficial in connecting the world and driving innovation, have a substantial environmental cost. The high energy demand for maintaining and operating these systems has heightened concerns about their carbon footprints and overall planetary impact.</p>
<p>In response, the tech industry is increasingly adopting sustainable practices. This change is driven by regulatory bodies, customer expectations, investor demands, and a genuine concern for the planet. Companies now realize that sustainable practices benefit the environment, their brand, customer loyalty, and their financial success.</p>
<p>This shift towards sustainability is taking various forms. Tech companies are designing energy-efficient data centers, using renewable energy, adopting eco-friendly manufacturing, and focusing on product recyclability. They aim to minimize their environmental impact through these diverse strategies.</p>
<p>Moreover, there's an emphasis on the entire lifecycle of software products. This includes not only their development but also their deployment, use, and management, focusing on improved resource management. This commitment to sustainability is crucial for creating a more environmentally responsible world.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-feature-management-can-reduce-carbon-footprints">How Feature Management Can Reduce Carbon Footprints<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/04/the-environmental-impact-of-feature-management/#how-feature-management-can-reduce-carbon-footprints">​</a></h2>
<p><img decoding="async" loading="lazy" alt="How feature management can reduce carbon footprints" src="https://configcat.com/blog/assets/images/efficient-deployments-4c5fada6f435e5e419b0c79a9f4da0aa.png" width="800" height="458" class="img_ev3q"></p>
<p>As we move forward, we see the future of technology is closely linked with our planet's health. Integrating sustainability into software development's core strategies and practices is becoming vital.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-role-of-feature-management-in-sustainable-software-deployment">The Role of Feature Management in Sustainable Software Deployment<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/04/the-environmental-impact-of-feature-management/#the-role-of-feature-management-in-sustainable-software-deployment">​</a></h3>
<p><a href="https://configcat.com/feature-toggle-management/" target="_blank" rel="noopener noreferrer">Feature management</a> is a key strategy for mitigating environmental impact and achieving sustainable technology practices. It contributes to efficient and eco-friendly software deployment, making it crucial for greener technology practices.</p>
<p>Feature management strategically controls and deploys new features in software applications. Developers can release, test, and modify functionalities in a controlled, incremental manner. They can also phase them out to specific user segments. Its significance lies in optimizing the deployment process. This minimizes resource consumption and energy expenditure.</p>
<p>Traditionally, deployment strategies involve large, infrequent updates. These are resource-intensive in terms of energy and computational demand. They require significant resources and often lead to downtime. During this downtime, additional resources are consumed to bring systems back online.</p>
<p>Feature management allows for smaller, more frequent updates. This reduces the strain on servers and data centers. It leads to more efficient resource use and effecitvely reducing the carbon footprint of software deployments. Incremental changes reduce the need for extensive rollbacks and associated resource consumption, thereby diminishing environmental impact.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="enhancing-eco-efficiency-with-targeted-and-adaptive-deployments">Enhancing Eco-Efficiency with Targeted and Adaptive Deployments<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/04/the-environmental-impact-of-feature-management/#enhancing-eco-efficiency-with-targeted-and-adaptive-deployments">​</a></h3>
<p>Feature management enables targeted deployments. Developers can selectively roll out features to specific segments or environments. This ensures judicious use of server capacities and avoids wasteful expenditure on unnecessary or underused features. It allows for precise server allocation and processing power, enhancing resource efficiency.</p>
<p>Feature management also reduces errors and bugs. Efficient practices allow for thorough testing and quicker issue resolution. This saves resources on fixing large-scale problems post-deployment. It saves energy and streamlines the development process, making it more environmentally friendly.</p>
<p>Beyond environmental benefits, feature management supports broader sustainability goals. It enables faster feature adaptation and responsiveness to user needs. This leads to efficient software that meets user requirements without overburdening the system. It contributes to the software lifecycle's longevity and sustainability, underscoring feature management's importance in sustainable technology practices.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="minimizing-resource-usage-with-green-ab-testing">Minimizing Resource Usage with Green A/B Testing<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/04/the-environmental-impact-of-feature-management/#minimizing-resource-usage-with-green-ab-testing">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Minimizing resource usage during testing" src="https://configcat.com/blog/assets/images/green-a-b-testing-46e04f53dcd4db463b3d054625945197.png" width="800" height="458" class="img_ev3q"></p>
<p><a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B testing</a> is essential for optimizing and improving software applications. Yet, as environmental sustainability becomes more crucial, the conventional practices of A/B testing are being re-evaluated. The concept of Green A/B testing is aimed at minimizing the resource usage and environmental impact associated with these testing phases.</p>
<p>Traditional A/B testing compares different feature versions among user segments. It assesses which version performs better in user engagement, satisfaction, or other metrics. Although effective for enhancing user experience and product performance, this method often demands significant resources, traffic, and computational power. Each test variant typically runs on separate servers or instances, increasing energy use and carbon footprint.</p>
<p>Green A/B testing seeks to address these environmental concerns by incorporating eco-friendly practices into the testing process. It focuses on optimizing test designs to use fewer resources while maintaining result quality. For example, using advanced statistical methods to cut down on required tests and computational power.</p>
<p>Another aspect of Green A/B testing is the use of advanced AI algorithms and machine learning techniques to predict outcomes with fewer data points and a combination of highly efficient evaluation of a broad set of hypotheses within a single experiment. This predictive modeling allows for a reduction in the sample size needed for testing, thereby decreasing the overall computational load.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="environmental-benefits-of-efficient-feature-management">Environmental Benefits of Efficient Feature Management<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/04/the-environmental-impact-of-feature-management/#environmental-benefits-of-efficient-feature-management">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Environmental benefits of efficient feature management" src="https://configcat.com/blog/assets/images/environmental-benefits-e3c421ff2e4afebb50a286395869dc62.png" width="800" height="458" class="img_ev3q"></p>
<p>The move towards efficient feature management in software development is not just a theoretical exercise in sustainability; it has tangible, real-world implications for the environment. Efficient feature management, at its core, revolves around deploying software updates and new features in a more controlled and resource-conscious manner.</p>
<p>This approach significantly reduces the frequency and volume of data transferred and processed during each update, leading to a direct decrease in energy use. In data centers and server farms, where energy consumption is a major environmental concern, this reduction is particularly impactful.</p>
<p>The environmental benefits extend beyond just energy savings. By minimizing the need for large-scale, all-encompassing updates, efficient feature management reduces the computational load on servers. This, in turn, translates into less heat generation and a lower demand for cooling, which is another major energy consumer in data centers.</p>
<p>Moreover, the reduced server load can prolong hardware lifespans, thereby decreasing the demand for new hardware production and the associated environmental costs. These metrics can be tracked over time to provide a clear picture of the environmental savings achieved through efficient feature management.</p>
<p>In addition to its direct impacts, the principles of efficient feature management can inspire broader changes within organizations, leading to a culture of sustainability that permeates other aspects of business operations. This shift can catalyze wider environmental initiatives, ranging from green procurement practices to investments in renewable energy sources.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/07/04/the-environmental-impact-of-feature-management/#conclusion">​</a></h2>
<p>This growing importance of sustainability in tech is not just a trend but a fundamental shift in how the industry operates and how it envisions its role in a global context. The role of feature management in reducing the carbon footprint of software deployments is multifaceted.</p>
<p>By enabling more controlled, efficient, and targeted deployment processes and experiments, feature management not only enhances the performance and reliability of software but also significantly reducing impact in the tech industry.</p>
<p>As the focus on sustainability continues to grow, the adoption of feature management practices becomes increasingly important in the journey towards greener and more responsible software development, which is proving to be an essential component in the tech industry's journey towards environmental responsibility.</p>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a> is a feature flag and remote configuration service that empowers developers to control and customize the functionality of their applications. With ConfigCat, you can easily toggle features on and off, alter their settings, and roll out updates to specific users or groups. <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer">Targeting</a> is supported through attributes, percentage-based rollouts, and segmentation. ConfigCat is available for <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer">all major programming languages and frameworks</a>, and can be accessed as a SaaS or self-hosted service. Additionally, we are fully compliant with GDPR and ISO 27001 standards.</p>
<p>For more feature flagging goodies, stay connected to ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flag</category>
            <category>feature management</category>
            <category>environmental impact</category>
            <category>sustainable software deployment</category>
        </item>
        <item>
            <title><![CDATA[Feature Flags and Cybersecurity - A Layered Defense Approach]]></title>
            <link>https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/</link>
            <guid>https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/</guid>
            <pubDate>Thu, 27 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Exploring how companies and organizations can utilize feature flags as a defense tool in cybersecurity.]]></description>
            <content:encoded><![CDATA[<p>As the world becomes increasingly digital and technology advances, so too do the threats. As a result, we must adapt and learn how to protect and safeguard our online presence, making robust cybersecurity measures more vital than ever before. This is especially important for companies, which generally have more at stake than individuals, necessitating a shift from outdated methods to new strategies to effectively combat cyber attacks.</p>
<p><img decoding="async" loading="lazy" alt="A hacker fighting ConfigCat feature flags" src="https://configcat.com/blog/assets/images/feature-flags-cyber-security-cover-51e64b59355515ba154b14d21711b91f.png" width="800" height="450" class="img_ev3q"></p>
<p>In cybersecurity, <a href="https://configcat.com/blog/2023/09/14/feature-flags-shaping-software-dev/" target="_blank" rel="noopener noreferrer">employing feature flags</a> as a strategic defense tool to manage access to different features has become an increasingly popular approach. <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer">Feature flags</a>, also known as feature toggles or switches, provide a mechanism within a software application that allows developers to enable or disable specific features. Leveraging feature flags for access control offers several benefits, one of which is significantly bolstering the security posture of a system.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="feature-flags-as-a-defense-tool-controlling-feature-access">Feature Flags as a Defense Tool: Controlling Feature Access<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#feature-flags-as-a-defense-tool-controlling-feature-access">​</a></h2>
<p>Strategically implementing feature flags transforms them into dynamic and versatile tools for controlling feature access, significantly enhancing the overall security of feature releases and deployed updates in a software application. Their agility and flexibility make them invaluable assets for responding to vulnerabilities in features and code changes while addressing evolving threats and maintaining a proactive security posture in the following ways:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="strategic-feature-rollouts">Strategic Feature Rollouts<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#strategic-feature-rollouts">​</a></h3>
<p>When strategically navigating feature deployment, feature flags are great at smoothly rolling out new features to a limited group of users. This approach makes it easier to closely monitor the process and catch any possible security issues before a full release. For example, a security-sensitive feature could be initially rolled out to internal users or a specific group, so that its impact on the system can be evaluated.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="swift-response-to-security-threats">Swift Response to Security Threats<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#swift-response-to-security-threats">​</a></h3>
<p>In the face of security threats or vulnerabilities, feature flags enable quick responses by promptly deactivating affected features, without requiring a complete application update. Immediate action can be taken upon identifying a security flaw, and quickly disabling the associated feature to mitigate potential risks.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="precision-access-control-for-sensitive-features">Precision Access Control for Sensitive Features<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#precision-access-control-for-sensitive-features">​</a></h3>
<p>Feature flags give you precise control over who can access certain features in an application. This is especially useful for sensitive features. For example, a financial application can use feature flags to restrict access to important transactional features. Only authorized users will be able to access these features.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ab-testing-for-security-measures">A/B Testing for Security Measures<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#ab-testing-for-security-measures">​</a></h3>
<p>Feature flags help with <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B testing</a>, which lets organizations evaluate the effectiveness of two variations of an implementation or security feature. For example, feature flags can be used to test different authentication mechanisms to determine the most secure approach.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="secure-isolation-of-experimental-features">Secure Isolation of Experimental Features<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#secure-isolation-of-experimental-features">​</a></h3>
<p>Feature flags facilitate isolated experimentation of features and security changes to ensure they work as intended before public release. These limit access to designated users or systems, allowing thorough testing in a controlled environment. For example, when experimenting with a new encryption algorithm, it can be confined to a controlled environment using feature flags.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="agile-response-to-compliance-dynamics">Agile Response to Compliance Dynamics<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#agile-response-to-compliance-dynamics">​</a></h3>
<p>Incorporating feature flags makes it easier to adapt to changing rules and regulations by turning specific features on or off. For example, if a new data protection law comes into effect, feature flags let you quickly make changes to the features that control how data is handled.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="emergency-kill-switch">Emergency Kill Switch<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#emergency-kill-switch">​</a></h3>
<p>Acting as a cybersecurity emergency kill switch, feature flags empower organizations to promptly disable specific features in response to critical security incidents. In the event of a widespread attack, certain functionalities can be swiftly deactivated, effectively containing the impact.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="dynamic-user-permission-adjustments">Dynamic User Permission Adjustments<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#dynamic-user-permission-adjustments">​</a></h3>
<p>Feature flags facilitate the dynamic modification of user permissions, allowing for real-time adjustments to user's access rights. For example, if a user experiences a change in security clearance, their access to specific features can be instantly adapted through feature flags.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="minimizing-attack-surface">Minimizing Attack Surface<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#minimizing-attack-surface">​</a></h3>
<p>Strategically toggling off non-essential features becomes a cybersecurity imperative, effectively minimizing the attack surface. Particularly during periods of heightened security concerns, non-critical features can be temporarily disabled to bolster defenses.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="streamlined-security-audits">Streamlined Security Audits<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#streamlined-security-audits">​</a></h3>
<p>The deployment of feature flags streamlines security audits by providing robust tracking and monitoring capabilities, offering insights into feature access. Access logs related to features handling sensitive data can be meticulously scrutinized, identifying and investigating any anomalies with ease.</p>
<p><img decoding="async" loading="lazy" alt="Computer monitor with a hacking program open" src="https://configcat.com/blog/assets/images/computer-monitor-7da4a95cfdc33476982a7de70adf6793.png" width="800" height="450" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="potential-risks-when-feature-flags-become-vulnerabilities">Potential Risks: When Feature Flags Become Vulnerabilities<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#potential-risks-when-feature-flags-become-vulnerabilities">​</a></h2>
<p>Occasionally, if not handled with care, these seemingly useful tools can lead to unintended issues. Curious to know how?</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="security-gaps">Security Gaps<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#security-gaps">​</a></h3>
<p>Improperly managed feature flags can create security loopholes. If attackers discover these flags, they can exploit them to gain unauthorized access to features or sensitive data. To mitigate this risk, organizations should institute a rigorous security review process for feature flags.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="visibility-and-monitoring-challenges">Visibility and Monitoring Challenges<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#visibility-and-monitoring-challenges">​</a></h3>
<p>In environments with numerous feature flags, feature flags can make it difficult to monitor and log system behavior accurately, as they can change the application's behavior dynamically. This can hinder the detection of malicious activities. Clear visibility into the impact of feature flag modifications on the system is essential for maintaining a secure environment.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="complexity-and-technical-debt">Complexity and Technical Debt<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#complexity-and-technical-debt">​</a></h3>
<p>Overuse or mismanagement of feature flags can lead to increased complexity in the codebase. This complexity can obscure underlying security issues, making them harder to identify and fix.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="configuration-errors">Configuration Errors<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#configuration-errors">​</a></h3>
<p>Human error in configuring feature flags can unintentionally expose features or data that should remain restricted, leading to potential security breaches. To mitigate misconfiguration risks, organizations should enforce strict configuration management practices for feature flags.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="inadequate-testing">Inadequate Testing<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#inadequate-testing">​</a></h3>
<p>Feature flags might bypass standard testing protocols, especially if they are used to enable features in a rush. This can lead to the deployment of untested or under-tested features, increasing the risk of vulnerabilities.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mitigating-third-party-risks">Mitigating Third-Party Risks<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#mitigating-third-party-risks">​</a></h3>
<p>If utilizing third-party solutions for feature flag management, organizations must adhere to the security practices of those vendors to avoid introducing additional risks. Thoroughly vetting third-party solutions, assessing vendors' security practices, and considering contractual agreements that address security and privacy concerns are key steps in mitigating vendor and third-party risks.</p>
<p><img decoding="async" loading="lazy" alt="Mouse cursor on the word &amp;#39;security&amp;#39;" src="https://configcat.com/blog/assets/images/mouse-cursor-security-acd01613e7a91b449f71fb6e3ed594fe.png" width="800" height="450" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="best-practices-ensuring-feature-flags-dont-compromise-security">Best Practices: Ensuring Feature Flags Don't Compromise Security<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#best-practices-ensuring-feature-flags-dont-compromise-security">​</a></h2>
<p>To ensure that these helpful tools do not compromise your software, here are a few tips:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="role-based-access-control-rbac">Role-Based Access Control (RBAC)<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#role-based-access-control-rbac">​</a></h3>
<p>Limit access to feature flag controls to authorized personnel only. Define roles and permissions to ensure that only authorized individuals can modify or toggle feature flags.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="security-measures">Security Measures<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#security-measures">​</a></h3>
<ul>
<li><strong>Audit Trails:</strong> Log and record all modifications to feature flags, including who made the changes and when. This information is valuable for tracking any unauthorized or unexpected alterations.</li>
<li><strong>Secure Flag Configuration:</strong> Treat feature flag configurations as sensitive data. Use encryption methods to protect the configuration files and ensure that they are stored securely.</li>
<li><strong>Code Reviews:</strong> Integrate feature flag changes into the standard code review process to catch potential security issues early. Verify that the code changes related to feature flags adhere to security best practices.</li>
<li><strong>Testing for Security Implications:</strong> Test features thoroughly, especially those related to security, to identify and rectify any vulnerabilities before they are exposed to users.</li>
<li><strong>Penetration Testing:</strong> Engage in regular penetration testing to identify potential security vulnerabilities related to feature flags. Address any findings promptly to enhance the overall security of the application.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="auditing-and-compliance">Auditing and Compliance<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#auditing-and-compliance">​</a></h3>
<ul>
<li><strong>Regular Audits:</strong> Periodically review the usage and configuration of feature flags. Ensure that no unnecessary or insecure flags are left active, and verify that the existing flags align with the current security requirements.</li>
<li><strong>Compliance Checks:</strong> Ensure that the use of feature flags complies with relevant industry regulations and standards. This is particularly important when dealing with sensitive data or applications subject to specific compliance requirements.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="emergency-kill-switch-1">Emergency Kill Switch<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#emergency-kill-switch-1">​</a></h3>
<p>Implement a mechanism to quickly disable all feature flags in case of a critical security incident. This emergency kill switch can be crucial to contain potential threats rapidly.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="documentation-and-communication">Documentation and Communication<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#documentation-and-communication">​</a></h3>
<p>Maintain clear documentation on the purpose and usage of each feature flag. Communicate changes to relevant stakeholders to avoid misunderstandings and ensure that everyone is aware of the state of the feature flags.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="limited-lifespan-for-flags">Limited Lifespan for Flags<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#limited-lifespan-for-flags">​</a></h3>
<p>Assigning a limited lifespan to feature flags is a key practice. Setting expiration dates, especially for flags used in testing or temporary contexts, prevents the accumulation of unnecessary flags that may pose security risks.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="education-and-training">Education and Training<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#education-and-training">​</a></h3>
<p>Ensure that development, operations, and security teams are educated on the secure implementation and management of feature flags. Training helps foster a security-aware culture within the organization.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/27/feature-flags-cyber-security/#conclusion">​</a></h2>
<p><a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer">Feature flags</a> are dynamic tools that offer significant advantages in controlling feature access and strengthening a system's security. The strategic release of features, swift response to security threats, precise access control, A/B testing for security measures, and secure isolation of experimental features highlight the proactive use of feature flags.</p>
<p>Nevertheless, it is important to be diligent in navigating potential risks associated with its use and challenges such as security gaps, visibility and monitoring issues, misconfigurations, and third-party risks. Implementing best practices, such as role-based access control, robust security measures, emergency kill switches, auditing and compliance checks, documentation, limited flag lifespans, and ongoing education, forms a comprehensive framework to ensure that feature flags do not compromise security.</p>
<p>By incorporating these considerations into existing practices, organizations can fully leverage the potential of feature flags while minimizing security risks and fostering a secure and resilient software development lifecycle. Bring the power of feature flags to the rest of the organization.</p>
<p>It's all right. Your feature flags are served. If you want to stay up-to-date with the mischievous antics of the cat with feature flags, follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>feature toggles</category>
            <category>cybersecurity</category>
            <category>feature management</category>
            <category>best practices</category>
        </item>
        <item>
            <title><![CDATA[Using ConfigCat's Feature Flags in an ASP.NET Core Application]]></title>
            <link>https://configcat.com/blog/2021/10/10/aspnetcore-options-pattern/</link>
            <guid>https://configcat.com/blog/2021/10/10/aspnetcore-options-pattern/</guid>
            <pubDate>Fri, 21 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[A guide on using ConfigCat feature flags in an ASP.NET Core 8 web application with the options pattern.]]></description>
            <content:encoded><![CDATA[<p>In this post, I'll investigate integrating <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat's</a> feature management system with an ASP.NET Core 8 Web API Service and the <code>Options&lt;T&gt;</code> <a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-8.0" target="_blank" rel="noopener noreferrer">pattern</a>. We'll also leverage the built-in polling mechanism of the ConfigCat client library to refresh feature flags' states during the application's runtime. Let's get started!</p>
<p><img decoding="async" loading="lazy" alt="Using ConfigCat&amp;#39;s Feature Flags in an ASP.NET Core application cover" src="https://configcat.com/blog/assets/images/using-feature-flags-in-aspnetcore-cover-cd7b884b7e6d94746001aa9444e593d9.png" width="800" height="450" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="feature-flags-with-configcat-and-aspnet-core-options">Feature Flags with ConfigCat and Asp.Net Core Options<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/10/10/aspnetcore-options-pattern/#feature-flags-with-configcat-and-aspnet-core-options">​</a></h2>
<p>Feature flagging or feature toggling is a technique used to enable or disable application features dynamically. For instance, feature flags allow product owners to switch features on or off during the application's runtime. Specific features can be activated or deactivated for particular environments, users, or regions. This approach facilitates A-B testing, testing with a subset of users, or rolling out features to different countries. It can also help comply with certain regional restrictions.</p>
<blockquote>
<p>Throughout my career, I've used different sorts of feature flag solutions. In some cases, this was a conscious decision built upon a well-designed application architecture. In contrast, in other cases it was just an <code>if</code> statement with a key-value pair in the configuration file. However, I haven't yet encountered such a complete service as the one provided by <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a>.</p>
</blockquote>
<p>I will focus on using feature flags in web services, though they are even more crucial for desktop applications. Managing a few web services is simpler than handling hundreds or thousands of desktop applications, which is common in enterprises.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="implementation-options">Implementation Options<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/10/10/aspnetcore-options-pattern/#implementation-options">​</a></h2>
<p><a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer">Feature flags</a> can be leveraged in many ways. In the past, when computer networks were less ubiquitous, feature flags were typically implemented as compiler directives. This method involved compiling or commenting out certain code paths. The advantage was less branching and smaller code size. However, to toggle a feature, recompiling the source code was necessary, making this solution less dynamic. Users would need to reinstall or upgrade their application to see the toggled feature.</p>
<p>Today, the most common technique is branching by <em>if</em> statements. If a feature flag is enabled, a specific code path is executed. For example, when a button is clicked to start order processing, if a feature flag is enabled, an SMS is sent to the user. This could be expressed as:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">ProcessOrder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> isSmsFeatureEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">GetValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"sendSMS"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">isSmsFeatureEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">SendSms</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ...</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Another approach would be to leverage <a href="https://www.martinfowler.com/bliki/BranchByAbstraction.html" target="_blank" rel="noopener noreferrer">branching by abstractions</a>. This is a larger topic, which I won't cover in this post. It might be worth exploring in a separate article.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="configcat-and-aspnet-core-and-net-8">ConfigCat and Asp.Net Core and .NET 8<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/10/10/aspnetcore-options-pattern/#configcat-and-aspnet-core-and-net-8">​</a></h2>
<p>Using <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat's feature flagging service</a> does not restrict us from choosing any implementation technique, although using compiler directives is less likely. In this section, I'll demonstrate how to integrate ConfigCat's configuration with the <code>Options&lt;T&gt;</code> pattern in .NET 8.</p>
<p>It's worth noting that no user-specific feature flag will be used, meaning that this implementation will not consider targeting. In all cases, the 'To all users' value of the feature flag is used.</p>
<p>When using the <code>Options&lt;T&gt;</code> pattern, there is no straightforward API to query user-specific settings. In a web application used by multiple users, there is also no effective way to fetch flags for one or a few users during application startup. Therefore, all feature flags shall be independent of users when registered with Options.</p>
<p>We're not going to dive to deep into creating a .NET application, but here's a <a href="https://dotnet.microsoft.com/en-us/learn/dotnet/hello-world-tutorial/intro" target="_blank" rel="noopener noreferrer">quick and easy guide</a> on how to do it. First, let me show you the complete startup code and the service's action, then describe the necessary types I will create for the solution. Here is the <code>Program.cs</code> file:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">using</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">Microsoft</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Extensions</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Options</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">using</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">ConfigCatInDotnetSample</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Configuration</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> builder </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> WebApplication</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">CreateBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Add ConfigCat configuration</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Configuration</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">AddConfigCat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Configuration</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"ConfigCat:Key"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    TimeSpan</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Parse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Configuration</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">"ConfigCat:PollInterval"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Configure services to use ConfigCat settings</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Services</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">ConfigureConfigCat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Configuration</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Add logging</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Logging</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">ClearProviders</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Logging</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">AddConsole</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> app </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Build</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">UseHttpsRedirection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Define a route that handles GET requests to /api/feature</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">MapGet</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"/api/feature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name" style="color:rgb(255, 203, 107)">HttpContext</span><span class="token plain"> context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IOptionsSnapshot</span><span class="token class-name punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token class-name" style="color:rgb(255, 203, 107)">FeatureSet</span><span class="token class-name punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"> features</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> logger </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">RequestServices</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token generic-method function" style="color:rgb(130, 170, 255)">GetRequiredService</span><span class="token generic-method generic class-name punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token generic-method generic class-name" style="color:rgb(255, 203, 107)">ILogger</span><span class="token generic-method generic class-name punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token generic-method generic class-name" style="color:rgb(255, 203, 107)">Program</span><span class="token generic-method generic class-name punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token generic-method generic class-name punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">try</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> featureValue </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> features</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">myFeature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        logger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">LogInformation</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token interpolation-string string" style="color:rgb(195, 232, 141)">$"myFeature is set to: </span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token interpolation-string interpolation expression language-csharp">featureValue</span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token interpolation-string string" style="color:rgb(195, 232, 141)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">featureValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">StatusCode </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> StatusCodes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Status200OK</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">WriteAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"the feature flag is on"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">StatusCode </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> StatusCodes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Status200OK</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">WriteAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"the feature flag off"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name" style="color:rgb(255, 203, 107)">Exception</span><span class="token plain"> ex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        logger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">LogError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Error while retrieving the feature flag value."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">StatusCode </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> StatusCodes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Status500InternalServerError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> context</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">WriteAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Internal Server Error"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Run</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">FeatureSet</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">bool</span><span class="token plain"> myFeature </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This web API has a single GET endpoint: <code>/api/feature</code>. The response depends on a feature flag: myFeature. When the feature is turned on, it returns HTTP 200 OK with a message indicating the feature flag is on. When the feature is turned off, it returns a message stating otherwise. The state of the feature flag is accessed through <code>IOptionsSnapshot&lt;FeatureSet&gt;</code> features, which I will explain later in this post.</p>
<p>The <code>builder.Configuration.AddConfigCat();</code> uses a custom extension method to add ConfigCat's toggle values to the ASP.NET Core configuration. The line <code>services.Configure&lt;FeatureSet&gt;(configuration.GetSection("FeatureSet"));</code> sets up the feature flags with the <code>Options&lt;T&gt;</code> pattern. This standard method binds a given section of the configuration to a type and registers the type with the DI container. Here, I'll bind the configuration to a type called FeatureSet with a single boolean property <code>myFeature</code>.</p>
<p>Let's look at the custom extension method. The following code integrates ConfigCat configuration values into ASP.NET's setup. The extension method uses <code>ConfigurationManager</code> to read the ConfigCat API key and poll interval settings from <code>appsettings.json</code>. These values are added by the ASP.NET application's file provider during startup.</p>
<p>In production, it's better to pass the ConfigCat key as a secret or environment variable. The configuration source should set this value before calling AddConfigCat. Since '0' is an invalid polling interval, the method validates it. The method also has an optional parameter to handle cases when ConfigCat can't fetch the feature flags, and an <code>onError</code> parameter to handle exceptions. Feature flags are periodically fetched from the service, and <code>onError</code> provides a way to track errors during these background polls.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Configuration/ConfigCatExtensions.cs</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">using</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">ConfigCat</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">namespace</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(178, 204, 214)">ConfigCatInDotnetSample</span><span class="token namespace punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token namespace" style="color:rgb(178, 204, 214)">Configuration</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatExtensions</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token return-type class-name" style="color:rgb(255, 203, 107)">IConfigurationBuilder</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">AddConfigCat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IConfigurationBuilder</span><span class="token plain"> builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">TimeSpan</span><span class="token plain"> pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> configSource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name" style="color:rgb(255, 203, 107)">ConfigCatConfigurationSource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Add</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">configSource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token return-type class-name" style="color:rgb(255, 203, 107)">IServiceCollection</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">ConfigureConfigCat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IServiceCollection</span><span class="token plain"> services</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IConfiguration</span><span class="token plain"> configuration</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            services</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token generic-method function" style="color:rgb(130, 170, 255)">Configure</span><span class="token generic-method generic class-name punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token generic-method generic class-name" style="color:rgb(255, 203, 107)">FeatureSet</span><span class="token generic-method generic class-name punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">configuration</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">GetSection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"FeatureSet"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> services</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">//...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can view the complete code <a href="https://github.com/configcat-labs/feature-flags-in-dotnet-sample/blob/main/Configuration/ConfigCatExtensions.cs" target="_blank" rel="noopener noreferrer">here</a>.</p>
<p>The ConfigCatOptions record type encapsulates the parameters for <code>ConfigCatConfigurationProvider</code>.</p>
<p>The next type is <code>ConfigCatConfigurationSource</code>. An <code>IConfigurationSource</code> is required to be implemented as this is the type added to the configuration sources. The responsibility of the type is to create an <code>IConfigurationProvider</code>. With .NET 8, when a configuration provider is removed or modified, all the remaining sources are rebuilt. This implementation returns a lazily instantiated <code>ConfigCatConfigurationProvider</code> instance. I will use singleton semantics because auto-polling built into the <code>ConfigCatConfigurationProvider</code> refreshes the configuration automatically.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatConfigurationSource</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> IConfigurationSource</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatConfigurationSource</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token type-list class-name" style="color:rgb(255, 203, 107)">IConfigurationSource</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> _sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">TimeSpan</span><span class="token plain"> _pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">ConfigCatConfigurationSource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">TimeSpan</span><span class="token plain"> pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            _sdkKey </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            _pollInterval </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token return-type class-name" style="color:rgb(255, 203, 107)">IConfigurationProvider</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">Build</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name" style="color:rgb(255, 203, 107)">IConfigurationBuilder</span><span class="token plain"> builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name" style="color:rgb(255, 203, 107)">ConfigCatConfigurationProvider</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">_sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> _pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<blockquote>
<p>Another use case could be when the feature flags are read-only at application startup. In certain applications, this could be a valid scenario. For this, manual polling would be a better choice, and creating a new instance of <code>ConfigCatConfigurationProvider</code> on every <code>Build()</code> method invocation would also make sense.</p>
</blockquote>
<p>The last and most complex class to implement is <code>ConfigCatConfigurationProvider</code>. This type derives from <code>ConfigurationProvider</code> which already implements many of the <code>IConfigurationProvider</code> interface members. Here, I'll only override the <code>Load()</code> method, which is invoked by the Host right after the configuration provider is instantiated. In the first invocation, I'll create a new <code>ConfigCatClient</code>.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatConfigurationProvider</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token type-list class-name" style="color:rgb(255, 203, 107)">ConfigurationProvider</span><span class="token type-list punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token type-list"> </span><span class="token type-list class-name" style="color:rgb(255, 203, 107)">IDisposable</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IConfigCatClient</span><span class="token plain"> _client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Timer</span><span class="token plain"> _timer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ILogger</span><span class="token class-name punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token class-name" style="color:rgb(255, 203, 107)">ConfigCatConfigurationProvider</span><span class="token class-name punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"> _logger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">ConfigCatConfigurationProvider</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token plain"> sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">TimeSpan</span><span class="token plain"> pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> loggerFactory </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> LoggerFactory</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Create</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">builder </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                builder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">AddConsole</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            _logger </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> loggerFactory</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token generic-method function" style="color:rgb(130, 170, 255)">CreateLogger</span><span class="token generic-method generic class-name punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token generic-method generic class-name" style="color:rgb(255, 203, 107)">ConfigCatConfigurationProvider</span><span class="token generic-method generic class-name punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            _client </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> ConfigCatClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">sdkKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> options </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                options</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">PollingMode </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> PollingModes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ManualPoll</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                options</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Logger </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name" style="color:rgb(255, 203, 107)">ConsoleLogger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ConfigCat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">LogLevel</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Warning</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Initial data load</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token function" style="color:rgb(130, 170, 255)">LoadAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Wait</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Block until initial load completes</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            _timer </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name" style="color:rgb(255, 203, 107)">Timer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> _ </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">RefreshConfigAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">null</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> pollInterval</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">private</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token return-type class-name" style="color:rgb(255, 203, 107)">Task</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">RefreshConfigAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">LoadAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">override</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">Load</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token function" style="color:rgb(130, 170, 255)">LoadAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Wait</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Block until load completes</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token return-type class-name" style="color:rgb(255, 203, 107)">Task</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">LoadAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> config </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name" style="color:rgb(255, 203, 107)">Dictionary</span><span class="token constructor-invocation class-name punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token constructor-invocation class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token constructor-invocation class-name punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token constructor-invocation class-name" style="color:rgb(255, 203, 107)"> </span><span class="token constructor-invocation class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">string</span><span class="token constructor-invocation class-name punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">StringComparer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">OrdinalIgnoreCase</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">try</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> _client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">ForceRefreshAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Ensure we fetch the latest config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> allKeys </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> _client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">GetAllKeysAsync</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                Console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">WriteLine</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token interpolation-string string" style="color:rgb(195, 232, 141)">$"All keys from ConfigCat: </span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token interpolation-string interpolation expression language-csharp keyword" style="font-style:italic">string</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token interpolation-string interpolation expression language-csharp function" style="color:rgb(130, 170, 255)">Join</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token interpolation-string interpolation expression language-csharp string" style="color:rgb(195, 232, 141)">", "</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token interpolation-string interpolation expression language-csharp"> allKeys</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token interpolation-string string" style="color:rgb(195, 232, 141)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> settings </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> _client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">FetchedConfig</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Settings</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token keyword" style="font-style:italic">foreach</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> setting </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> settings</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                    </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> key </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> setting</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                    </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">var</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">value</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> setting</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                    Console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">WriteLine</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token interpolation-string string" style="color:rgb(195, 232, 141)">$"Feature Flag: </span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token interpolation-string interpolation expression language-csharp">key</span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token interpolation-string string" style="color:rgb(195, 232, 141)"> | Value: </span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token interpolation-string interpolation expression language-csharp keyword" style="font-style:italic">value</span><span class="token interpolation-string interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token interpolation-string string" style="color:rgb(195, 232, 141)">"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                Data </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                </span><span class="token function" style="color:rgb(130, 170, 255)">OnReload</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token class-name" style="color:rgb(255, 203, 107)">Exception</span><span class="token plain"> ex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">                _logger</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">LogError</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Error loading configuration from ConfigCat."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">Dispose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            _timer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Dispose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            _client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Dispose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Once <code>ConfigCatClient</code> has loaded the data, the <code>OnConfigurationChanged</code> event is fired. This is when all key-value pairs are loaded. <code>LoadData()</code> and <code>ParseKeys()</code> methods read and parse the keys and corresponding values. The result dictionary is set in the Data property, which is declared by the base class. The only additional logic applied here is to replace the underscore characters with semicolons. This is done because the ':' character is unsupported in key names. To deal with the hierarchy of configuration values, another character must be used for the ConfigCat feature names. Using the <code>\_</code> character resembles a similar behavior to using configuration values with environment variables.</p>
<p>Note that the <code>LoadData()</code> method invokes a method from the base type: <code>OnReload();</code>. This generates a new change token signaling the configuration provider that the configuration values have changed. The values of options might change due to the built-in auto-polling mechanism; however, the <code>OnConfigurationChanged</code> event is only fired when the values have changed.</p>
<p>To read the latest configuration values while serving the HTTP request, an <code>IOptionsSnapshot&lt;FeatureSet&gt;</code> is passed to the <code>GET</code> request's action handler. This type is useful in scenarios where options should be recomputed on every request.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="sample-app">Sample App<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/10/10/aspnetcore-options-pattern/#sample-app">​</a></h3>
<p>You can find the complete code for the sample application <a href="https://github.com/configcat-labs/feature-flags-in-dotnet-sample" target="_blank" rel="noopener noreferrer">here</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/10/10/aspnetcore-options-pattern/#conclusion">​</a></h2>
<p>An aging but maintained application needs a feature flag solution. The more robust the solution, the more options the development team has to isolate preview features for specific users. Building a custom feature flag solution usually doesn't offer a competitive advantage, so using a purpose-built service makes sense. ConfigCat's solution seems like a reasonable choice for my next project.</p>
<p>ConfigCat supports simple feature toggles, user segmentation, and A/B testing and has a <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">generous free tier</a> for low-volume use cases or those just starting out.</p>
<p>For additional feature flagging tips and resources, stay connected with ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>ASP.NET Core</category>
            <category>ASP.NET</category>
            <category>feature flags</category>
            <category>how to</category>
        </item>
        <item>
            <title><![CDATA[Using Feature Flags in a React.js Application]]></title>
            <link>https://configcat.com/blog/2021/12/13/feature-flags-in-react/</link>
            <guid>https://configcat.com/blog/2021/12/13/feature-flags-in-react/</guid>
            <pubDate>Thu, 20 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[A step-by-step guide to implementing ConfigCat feature flags in a React.js application using ConfigCat's official React SDK.]]></description>
            <content:encoded><![CDATA[<p>In this post, I'm going to be demonstrating how to integrate ConfigCat's feature flags in a React application. I will build a simple, pretty easy-to-understand application that simulates a race between three cars. Let's get started!</p>
<p><img decoding="async" loading="lazy" alt="Using feature flags in a React.js application cover" src="https://configcat.com/blog/assets/images/using-feature-flags-in-react-cover-2a90ddc49f6121dd77683f6f7d3ff6bf.png" width="800" height="371" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-are-feature-flags-exactly-and-why-are-they-used">What are feature flags exactly, and why are they used?<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/12/13/feature-flags-in-react/#what-are-feature-flags-exactly-and-why-are-they-used">​</a></h2>
<p>A <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer">feature flag</a> is a switch that allows specific features in an application to be turned on or off via a remote interface without needing to redeploy the entire codebase. Feature flags are useful in a variety of scenarios, such as releasing a feature gradually, displaying an application extension only for users in a specific country, or limiting a feature to a <a href="https://configcat.com/docs/targeting/targeting-overview/" target="_blank" rel="noopener noreferrer">specific number of users</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-will-the-app-use-the-feature-flag">How will the app use the feature flag?<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/12/13/feature-flags-in-react/#how-will-the-app-use-the-feature-flag">​</a></h2>
<p>I'm going to present a working demo of how to use a feature flag to enable a race simulation between three cars to see which one reaches the finish line first. The feature flag will work like a stoplight: when the flag is on, the light turns green, and the cars will race; otherwise, they will remain still.</p>
<p><strong>Note:</strong> In case you want to follow along from the beginning, here's <a href="https://github.com/configcat-labs/feature-flags-in-react-sample" target="_blank" rel="noopener noreferrer">the full app</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="hooking-up-configcat-to-react">Hooking up ConfigCat to React<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/12/13/feature-flags-in-react/#hooking-up-configcat-to-react">​</a></h2>
<p>But first thing's first — let's start a new React project. The <a href="https://react.dev/learn/start-a-new-react-project" target="_blank" rel="noopener noreferrer">Start a New React Project</a> section in the official React documentation recommends choosing one of the many React-powered frameworks, which is a common approach in modern <a href="https://solveit.dev/blog/why-use-react-for-web-development" target="_blank" rel="noopener noreferrer">React web development</a>.</p>
<ol>
<li>Create a new Next.js React app and navigate to the generated project folder and install the <a href="https://configcat.com/docs/sdk-reference/react/" target="_blank" rel="noopener noreferrer">configcat-react</a> SDK:</li>
</ol>
<div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">npx create-next-app@latest</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">npm install configcat-react</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The package uses <a href="https://react.dev/reference/react/createContext" target="_blank" rel="noopener noreferrer">React's Context API</a> to expose a provider for wrapping your app's root component. In our case it's the <code>src/pages/_app.tsx</code> file:</p>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@/styles/globals.css'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> type </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token maybe-class-name">AppProps</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'next/app'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ConfigCatProvider</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">PollingMode</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'configcat-react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Import the ConfigCatProvider and PollingMode</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color:rgb(130, 170, 255)">App</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">Component</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> pageProps </span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">AppProps</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">ConfigCatProvider</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">      </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">sdkKey</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">YOUR-CONFIGCAT-SDK-KEY</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">      </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">pollingMode</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript maybe-class-name" style="color:rgb(255, 85, 114)">PollingMode</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript property-access maybe-class-name" style="color:rgb(255, 85, 114)">AutoPoll</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">      </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">options</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">        </span><span class="token tag script language-javascript literal-property property" style="color:rgb(255, 85, 114)">pollIntervalSeconds</span><span class="token tag script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript number" style="color:rgb(247, 140, 108)">5</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">      </span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">Component</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag spread punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag spread operator" style="color:rgb(137, 221, 255)">...</span><span class="token tag spread" style="color:rgb(255, 85, 114)">pageProps</span><span class="token tag spread punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">ConfigCatProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In the code above, I've used the <code>ConfigCatProvider</code> with the following props:</p>
<ul>
<li>
<p><strong>sdkKey</strong>: This is a string that links the application to your ConfigCat account. You can find your SDK key <a href="https://app.configcat.com/sdkkey" target="_blank" rel="noopener noreferrer">here</a>. It is recommended to use secure methods for adding your SDK key to your source code, rather than including it directly.</p>
</li>
<li>
<p><strong>pollingMode</strong>: By default, the React SDK downloads the latest values automatically and stores them in the local cache. With this prop, you can choose the <a href="https://configcat.com/docs/sdk-reference/react/#polling-modes" target="_blank" rel="noopener noreferrer">polling mode</a> that best aligns with your specific use case.</p>
</li>
<li>
<p><strong>options</strong>: This prop can be used to further configure the SDK. You can read more about it <a href="https://configcat.com/docs/sdk-reference/react/#creating-the-configcat-client" target="_blank" rel="noopener noreferrer">here</a>. In this case, specifying the <code>pollIntervalSeconds</code> option configures the SDK to poll your feature flag values from your account at the specified interval in seconds.</p>
</li>
</ul>
<p>The <code>ConfigCatProvider</code> allows you to use feature flags throughout your application or just for a specific component, in this case I'm going to be using it in the <code>Cars</code> component which is used in <code>src/pages/index.tsx</code>. First, I need to import the <code>useFeatureFlag</code> hook from the <code>configcat-react</code> package to reference the value of the feature flag and the loading state:</p>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> useFeatureFlag </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword module" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'configcat-react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function maybe-class-name" style="color:rgb(130, 170, 255)">Cars</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> loading </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useFeatureFlag</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'YOUR-FEATURE-FLAG-KEY'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token literal-property property">images</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token maybe-class-name">TImage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> loading </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text">Loading...</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">className</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">cars-container</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">images</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">map</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">Car</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">carImage</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">image</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">key</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">image</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript property-access" style="color:rgb(255, 85, 114)">link</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">raceMode</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">value</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">Car</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">className</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">finish-line</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">RaceStatus</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">raceMode</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">value</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">RaceStatus</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>I've passed <code>raceMode</code> down to each car, along with the car image. Now, let's get to the fun part where we make the cars race based on the feature flag's value.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="using-the-feature-flag-value">Using the feature flag value<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/12/13/feature-flags-in-react/#using-the-feature-flag-value">​</a></h2>
<p>Initially, the app shows three cars aligned on a road, ready to race each other to the finish line. To let them race, I will add some CSS animations to each car, which will animate them when the flag is switched on.</p>
<p><img decoding="async" loading="lazy" alt="Cars waiting" src="https://configcat.com/blog/assets/images/using-feature-flags-in-react-cover-2a90ddc49f6121dd77683f6f7d3ff6bf.png" width="800" height="371" class="img_ev3q"></p>
<p>Next, let's add a <code>raceMode</code> prop on every car to get the value when it's changed - based on that, the car will have the racing animation class.</p>
<div class="language-jsx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-jsx codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword module" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function maybe-class-name" style="color:rgb(130, 170, 255)">Car</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token parameter"> carImage</span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token parameter"> raceMode </span><span class="token parameter punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token parameter operator" style="color:rgb(137, 221, 255)">:</span><span class="token parameter"> </span><span class="token parameter maybe-class-name">CarProps</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">let</span><span class="token plain"> customClass </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> raceMode </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">car-image </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">carImage</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation property-access">class</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'car-image'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword control-flow" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">className</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">car-container</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">Image</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">        </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">src</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">carImage</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript property-access" style="color:rgb(255, 85, 114)">link</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">        </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">alt</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">carImage</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript property-access" style="color:rgb(255, 85, 114)">class</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">        </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">className</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token tag script language-javascript template-string string" style="color:rgb(195, 232, 141)">car-image </span><span class="token tag script language-javascript template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token tag script language-javascript template-string interpolation" style="color:rgb(255, 85, 114)">customClass</span><span class="token tag script language-javascript template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag script language-javascript template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">        </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">width</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript number" style="color:rgb(247, 140, 108)">100</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">        </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">height</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript number" style="color:rgb(247, 140, 108)">100</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">Image</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Based on its value, different styling will be applied to each car. With a little string interpolation magic, the CSS class is now dynamically changed every time the feature flag is toggled. In the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer">dashboard</a>, I will switch the flag value to 'on' and see the light turn green. The cars are now racing! I'm betting on the red one.</p>
<p><img decoding="async" loading="lazy" alt="Cars Racing" src="https://configcat.com/blog/assets/images/react-cars-racing-de286bdf3b37ce276d0ee4e1f46c0004.gif" width="800" height="388" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/12/13/feature-flags-in-react/#summary">​</a></h2>
<p>As a quick recap, what were the key steps in this demo? First, I installed the ConfigCat React SDK and wrapped the app's root component with the <code>ConfigCatProvider</code>. Next, I fetched the flag value and loading state using the <code>useFeatureFlag</code> hook. Finally, when the flag is switched on, some CSS classes are added to the cars' containers, and a race is simulated.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2021/12/13/feature-flags-in-react/#conclusion">​</a></h2>
<p>Feature flags can be used in a variety of ways in all kinds of applications. ConfigCat's feature flag solution is so easy to use that even non-technical team members can easily use them, with its 10-minute trainable <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">user interface</a>. I hope you've found this article useful, and if you want to implement a feature flag with React yourself, the source code from this demo is available in this public <a href="https://github.com/configcat-labs/feature-flags-in-react-sample" target="_blank" rel="noopener noreferrer">repository</a> on GitHub.</p>
<p>Don't forget to explore more about ConfigCat on <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">Github</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, and <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>.</p>]]></content:encoded>
            <category>React</category>
            <category>how to</category>
            <category>feature management</category>
            <category>feature flags</category>
            <category>Next.js</category>
        </item>
        <item>
            <title><![CDATA[Eating Our Own Cat Food - The Rollout of ConfigCat's Config V2]]></title>
            <link>https://configcat.com/blog/2024/06/20/the-rollout-of-config-v2/</link>
            <guid>https://configcat.com/blog/2024/06/20/the-rollout-of-config-v2/</guid>
            <pubDate>Thu, 20 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[This is the story of our successful rollout of Config V2, the latest and most advanced version of ConfigCat.]]></description>
            <content:encoded><![CDATA[<p>We'd like to share the story of how we successfully rolled out <a href="https://configcat.com/docs/advanced/config-v2/" target="_blank" rel="noopener noreferrer">Config V2</a>, the latest and most advanced version of ConfigCat. Let us take you behind the scenes and show you how we used our own tool to achieve a smooth and gradual rollout. Join us as we explain the steps we took to launch Config V2 and demonstrate how we "eat our own <del>dog</del> cat food".</p>
<p><img decoding="async" loading="lazy" alt="The rollout of Config V2" src="https://configcat.com/blog/assets/images/the-rollout-of-configcats-config-v2-cover-9eee3c3554f22ec805f731e76debb2a9.png" width="800" height="671" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="listening-to-our-users">Listening to Our Users<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/20/the-rollout-of-config-v2/#listening-to-our-users">​</a></h2>
<p>We started the journey of Config V2 by listening to our users. We gathered extensive feedback and identified their needs and pain points. This user-centric approach helped us develop Config V2 to address real-world requirements (Our users are the best source of inspiration! 🩷). We had to redesign the user interface for some of the new features, so we decided to bundle them together and release them all at once instead of one by one. This led to the creation of a completely new version of ConfigCat, which includes not only new functionalities but also a brand-new, lean, and user-friendly dashboard.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="user-testing-phase-putting-config-v2-to-the-test">User Testing Phase: Putting Config V2 to the Test<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/20/the-rollout-of-config-v2/#user-testing-phase-putting-config-v2-to-the-test">​</a></h2>
<p>Before releasing Config V2 to everyone, we conducted thorough user testing. Our goal was to make sure the new dashboard and features were easy to use. We tested Config V2 with two groups:</p>
<ol>
<li>
<p><strong>New Users</strong>: To see how easily they could navigate the new dashboard.</p>
</li>
<li>
<p><strong>Existing Customers</strong>: Especially those who had requested specific features, to understand their reactions and gather detailed feedback.</p>
</li>
</ol>
<p>Participants completed tasks while we observed their interactions in live meetings. This hands-on testing provided valuable insights and helped us identify areas for improvement. (Watching users interact with the new features was both exciting and nerve-wracking! 😳)</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="refining-based-on-feedback">Refining Based on Feedback<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/20/the-rollout-of-config-v2/#refining-based-on-feedback">​</a></h2>
<p>Based on the results, we identified several areas for improvement. For example, the new comparators dropdown list was too long and confusing. To fix this, we shortened the list and added a Comparator Selector dialog window that explains each comparator, making it easier for users to find the right one. These improvements were essential for enhancing the user experience.</p>
<img class="zoomable" src="https://configcat.com/blog/assets/the-rollout-of-config-v2/comparator-selector-dialog.png" alt="Comparator selector dialog">
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="beta-testing-phase-fine-tuning-config-v2">Beta Testing Phase: Fine-Tuning Config V2<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/20/the-rollout-of-config-v2/#beta-testing-phase-fine-tuning-config-v2">​</a></h2>
<p>After implementing initial feedback, we moved to the beta testing phase. We invited current customers to participate, and their positive feedback was encouraging. Using ConfigCat, we enabled V2 for the beta testers by creating a segment for them and adding their organizations to it. Seeing our own tool in action was incredibly satisfying! 🥰</p>
<p>During the beta tests, we collected feedback via email and through our <a href="https://configcat.com/slack/" target="_blank" rel="noopener noreferrer">Community Slack</a>. Over two months, we fine-tuned Config V2, getting it ready for a wider audience.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="gradual-rollout-using-our-own-cat-food">Gradual Rollout: Using Our Own Cat Food<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/20/the-rollout-of-config-v2/#gradual-rollout-using-our-own-cat-food">​</a></h2>
<p>For the official release, we decided to "eat our own cat food" by using ConfigCat's gradual rollout feature. Here's how we did it:</p>
<ol>
<li><strong>Initial Rollout</strong>: We made Config V2 accessible to 10% of ConfigCat users, including beta testers. As you can see in the screenshot below, we not only used our own tool but also applied the new Config V2 features such as the <a href="https://configcat.com/docs/targeting/targeting-rule/user-condition/#date-and-time-comparators" target="_blank" rel="noopener noreferrer">BEFORE/AFTER comparators</a> to enable V2 for 10% of our users.</li>
</ol>
<img class="zoomable" src="https://configcat.com/blog/assets/the-rollout-of-config-v2/gradual-rollout-using-config-v2-comparators.png" alt="Gradual rollout using Config V2 comparators">
<ol start="2">
<li>
<p><strong>Phased Expansion</strong>: After two weeks, we expanded the rollout to 50% of our users. This phased approach allowed us to monitor the rollout closely and quickly address any issues.</p>
</li>
<li>
<p><strong>Full Release</strong>: After another two weeks, Config V2 was available to 100% of ConfigCat users. The gradual rollout allowed a smooth transition and gave us confidence in Config V2's stability and performance. When we officially released it to 100% of ConfigCat users, Config V2 became the default version for everyone signing up for ConfigCat.</p>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="smooth-transition">Smooth Transition<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/20/the-rollout-of-config-v2/#smooth-transition">​</a></h2>
<p>Throughout the phased rollout, we aimed for a seamless experience. Config V1 and V2 could be used side by side with no service interruptions. Users could migrate at their own pace, and Config V1 remained fully accessible. While Config V1 is still supported, all future development will focus on V2.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion-a-confident-launch-with-configcat">Conclusion: A Confident Launch with ConfigCat<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/20/the-rollout-of-config-v2/#conclusion-a-confident-launch-with-configcat">​</a></h2>
<p>The successful rollout of Config V2 demonstrates our commitment to quality and user satisfaction. By using our own tool for the gradual rollout, we showcased the reliability and effectiveness of ConfigCat. We are proud of Config V2 and confident it will provide our users with an enhanced and intuitive experience.</p>
<p>Thank you for joining us on this journey. We look forward to your feedback and hope you enjoy the new experience with Config V2. As always, happy feature flagging, and may your settings be as smooth as a cat's purr!</p>
<p>For the latest updates and insights on our newest tools, be sure to follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>config v2</category>
            <category>feature management system</category>
        </item>
        <item>
            <title><![CDATA[Global Feature Management - Catering to Diverse Audiences]]></title>
            <link>https://configcat.com/blog/2024/06/06/global-feature-management-catering-to-diverse-audiences/</link>
            <guid>https://configcat.com/blog/2024/06/06/global-feature-management-catering-to-diverse-audiences/</guid>
            <pubDate>Thu, 06 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Dive into Global Feature Management for diverse audiences in the digital age. Uncover the importance of cultural considerations, localization, and feature flags in software deployment and catering to diverse audiences.]]></description>
            <content:encoded><![CDATA[<p>In the current era of digital globalization, the ambition to launch software on a global scale is more than a mere aspiration; it's a necessity for businesses seeking to stay competitive and relevant. Imagine a world where your software reaches every corner of the globe, where your application speaks to users in the bustling streets of Tokyo, the vibrant markets of Mumbai, the sleek offices of New York, and the cozy cafes of Paris.</p>
<p>This is the dream of global software deployment, a software product that transcends borders, reaching a global audience. However, the path to achieving this global reach is fraught with obstacles that test the mettle of even the most seasoned developers and business strategists. It's a dream that brings with it a complex maze of challenges and opportunities.</p>
<p>Understanding and catering to diverse user groups is not just about translating content but about truly grasping the varied needs, preferences, and cultural nuances. A one-size-fits-all approach can lead to a product that fits none perfectly. This introduces the need for a sophisticated feature management strategy that respects and addresses the intricacies of global markets.</p>
<p><img decoding="async" loading="lazy" alt="Understanding regional preferences" src="https://configcat.com/blog/assets/images/catering-to-diverse-audiences-cover-3eab169f926f5e2b1e0640bdec71031b.png" width="800" height="458" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="cultural-considerations-understanding-regional-preferences-and-norms">Cultural Considerations: Understanding Regional Preferences and Norms<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/06/global-feature-management-catering-to-diverse-audiences/#cultural-considerations-understanding-regional-preferences-and-norms">​</a></h2>
<p>The cornerstone of effective global feature management lies in understanding cultural differences. Each market has its unique preferences, norms, and taboos. For instance, color schemes that are appealing in one country might be off-putting in another due to cultural associations. Similarly, the layout, content, and even the functionality of a product may need to be adjusted to align with local expectations and usage patterns.</p>
<p>When we talk about cultural considerations in software development, we delve into a realm that goes far beyond simple aesthetics. Yes, visual elements like color schemes, typography, and imagery are important—they can convey messages and evoke emotions that are deeply rooted in cultural contexts. For instance, while red may symbolize prosperity and good fortune in East Asian cultures, it might represent danger or caution in Western societies. But cultural considerations encompass much more than just visual appeal.</p>
<p>At a deeper level, cultural nuances influence user expectations and interaction patterns. In some cultures, a minimalist design might be appreciated for its clarity and simplicity, while in others, more information-dense layouts are preferred. The way users navigate through an app or website—whether they expect top-down, left-to-right, or even non-linear navigation—can vary significantly.</p>
<p>Cultural considerations also extend into the core functionality of the software itself. Features that are indispensable in one market might be irrelevant or even undesirable in another. For example, social sharing features are highly popular in markets with a strong social media presence, but in regions where privacy is highly valued, these features might be less desirable.</p>
<p>Navigating this intricate tapestry of global cultures is pivotal to successful software deployment, as each region is not just a geographical entity but a rich mosaic of history, traditions, values, and behaviors. Understanding these diverse cultural landscapes is crucial for any software aiming to gain global success.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="localization-and-feature-flags-tailoring-features-for-different-markets">Localization and Feature Flags: Tailoring Features for Different Markets<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/06/global-feature-management-catering-to-diverse-audiences/#localization-and-feature-flags-tailoring-features-for-different-markets">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Tailoring features for different markets" src="https://configcat.com/blog/assets/images/tailoring-features-for-different-markets-f90cd653446abea0ba378805c18cd3af.png" width="800" height="458" class="img_ev3q"></p>
<p>In the quest to create software that resonates with users across the globe, two key strategies stand out as game changers: localization and the use of feature flags. These strategies go hand in hand in tailoring software experiences to suit diverse markets, ensuring that each user feels like the product was made just for them.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="localization-more-than-just-translation">Localization: More Than Just Translation<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/06/global-feature-management-catering-to-diverse-audiences/#localization-more-than-just-translation">​</a></h3>
<p>Localization is an art that transcends mere language translation and is the key to addressing these cultural nuances. It's about culturally adapting your software to meet different regions' specific needs and sensibilities. It is fundamentally personalization attuned to geographic nuances, where content and features are dynamically adjusted according to a user's location or IP address to make it more region-specific.</p>
<p>This process entails a deep dive into local customs and consumer behavior, ensuring that features align with the target market and meet expectations in specific locations or regions to avoid cultural missteps and maintain utmost relevance. It also involves adjusting features and functionalities to align with local usage patterns and preferences, ensuring a more tailored experience for customers. For example, integrating local payment methods, adjusting date and time formats, or modifying navigation flows.</p>
<p>Effective localization also considers regional aesthetics and design preferences in adapting visual elements to ensure cultural appropriateness. What constitutes an appealing and intuitive interface can vary dramatically between cultures. In some regions, vibrant and dynamic designs are favored, while in others, a clean, minimalist approach is more appealing.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="feature-flags-customizing-and-tailoring-user-experiences-in-real-time">Feature Flags: Customizing and Tailoring User Experiences in Real-Time<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/06/global-feature-management-catering-to-diverse-audiences/#feature-flags-customizing-and-tailoring-user-experiences-in-real-time">​</a></h3>
<p><img decoding="async" loading="lazy" alt="using feature flags to tailor user experiences" src="https://configcat.com/blog/assets/images/feature-flags-8b9416dbecbda7d7ffa52b1a770a8d67.png" width="800" height="458" class="img_ev3q"></p>
<p><a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer">Feature flags</a>, also known as feature toggles, offer a dynamic way to manage software features across different markets. They allow developers to turn features on or off for specific user segments. This flexibility is invaluable in customizing and tailoring user experiences in the global context.</p>
<p>Consider a social media platform: while certain features, like news feeds or messaging, are universally relevant, others might need to be adjusted or replaced based on regional preferences or regulations. For example, a feature that integrates local maps or weather might be popular in one region but irrelevant in another. Feature flags provide this capability and facilitate real-time adjustments to shape users' experiences dynamically.</p>
<p>Feature flags also enable <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B testing</a> in different markets to test and gather data on their performance before deciding on a wider release. Companies can also gradually roll out new features in specific regions. This approach reduces the risk of launching features that might not resonate with the target audience.</p>
<p>Additionally, feature flags can be used to comply with local laws. In some countries, data privacy laws are stricter, requiring adjustments to how user data is handled and stored. With feature flags, these adjustments can be made seamlessly without disrupting the service for users in other regions.</p>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a> is a feature flagging service that centralizes feature management and provides configuration options for rolling out features to specific user segments and groups. You can find the documentation <a href="https://configcat.com/docs" target="_blank" rel="noopener noreferrer">here</a> to learn more.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-synergy-of-localization-and-feature-flags">The Synergy of Localization and Feature Flags<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/06/global-feature-management-catering-to-diverse-audiences/#the-synergy-of-localization-and-feature-flags">​</a></h3>
<p>The combination of localization and feature flags allows for a level of customization that was previously unattainable. It enables software companies to not only speak the language of their users but also to respect and adapt to their cultural contexts and preferences.</p>
<p>This synergy is key to building and maintaining a loyal user base in diverse global markets. It enables a more fluid and agile deployment strategy where features can be tested, released, or withdrawn from specific markets without impacting the global user base.</p>
<p>In essence, the successful global deployment of software hinges on a nuanced understanding of localization and the strategic use of feature flags. Together, they empower companies to deliver tailored experiences that resonate with users around the globe, fostering a sense of inclusivity and respect for cultural diversity.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="examples-of-companies-with-successful-global-feature-deployments">Examples of Companies with Successful Global Feature Deployments<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/06/global-feature-management-catering-to-diverse-audiences/#examples-of-companies-with-successful-global-feature-deployments">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Examples of global feature deployments" src="https://configcat.com/blog/assets/images/successful-examples-9644bb36bd309e1476e1b958876d37f5.png" width="800" height="458" class="img_ev3q"></p>
<p>Several leading companies have successfully harnessed the power of localization to tailor their features for different markets, exemplifying the importance of cultural sensitivity in global business strategies. For instance, Netflix, a titan in the streaming industry, not only offers region-specific content libraries but also localizes interfaces, subtitles, and dubbing options to resonate with local audiences.</p>
<p>Similarly, tech giant Apple adapts its App Store content to reflect local trends, languages, and user preferences, ensuring a personalized experience for users across the globe. E-commerce platforms like Amazon and Alibaba stand out in their use of localization, offering region-specific product selections, payment options, and even marketing strategies that align with local customs and shopping habits.</p>
<p>Platforms like Facebook, Microsoft, Google, and Twitter have also made strides in tailoring experiences based on regions and cultural norms to cater to the specific needs of users in various regions or locations. These companies demonstrate that effective localization is not just about translating content but about deeply understanding and respecting each market's cultural, legal, and societal nuances. This approach not only enhances user satisfaction and conversion but also positions these companies as culturally aware and adaptable entities in the global marketplace.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/06/06/global-feature-management-catering-to-diverse-audiences/#conclusion">​</a></h2>
<p>Understanding and respecting cultural differences is not just a moral imperative but a strategic necessity in the global software market. It involves a holistic approach that considers visual design, user interface, functionality, content, and the broader social and technological context. It also requires a deep understanding of diverse audiences and the agility to adapt features swiftly and efficiently.</p>
<p>The ultimate goal of global feature management is to strike a delicate balance between maintaining a product's core identity and adapting to local markets. Combining cultural insights, localization strategies, and feature flags can help software developers and companies strike the right balance. In doing so, they not only expand their global footprint but also build a loyal and diverse user base.</p>
<p>Curious to give ConfigCat feature flags a try on your own? Curious to give ConfigCat feature flags a try on your own? <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">Sign up</a> for a free-tier account to get started. Deploy any time, release when confident.</p>
<p>For more feature flagging goodies, stay connected to ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flag</category>
            <category>global software deployment</category>
            <category>localization strategies</category>
            <category>feature adaptation</category>
            <category>diverse audiences</category>
        </item>
        <item>
            <title><![CDATA[New Comparators in Config V2]]></title>
            <link>https://configcat.com/blog/2024/05/20/config-v2-new-comparators/</link>
            <guid>https://configcat.com/blog/2024/05/20/config-v2-new-comparators/</guid>
            <pubDate>Mon, 20 May 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[An overview of Config V2's New Comparators]]></description>
            <content:encoded><![CDATA[<p><strong>Config V2</strong> introduces <strong>New Comparators</strong> that make it much easier to create precise <a href="https://configcat.com/docs/targeting/targeting-rule/targeting-rule-overview/" target="_blank" rel="noopener noreferrer">Targeting Rules</a> by facilitating seamless comparison of texts, arrays, and dates.</p>
<p><img decoding="async" loading="lazy" alt="New Comparators" src="https://configcat.com/blog/assets/images/new-comparators-preview-7f580f2f37c744c6c6e8a00cedaf62e9.png" width="800" height="400" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="overview">Overview<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#overview">​</a></h2>
<p><a href="https://configcat.com/docs/advanced/config-v2/" target="_blank" rel="noopener noreferrer">The latest release</a> showcases a variety of new comparators, each designed to offer specific functionalities for handling texts, arrays, and dates.</p>
<p>In this post, we'll illustrate these comparators with various examples.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="new-text-comparators">New Text Comparators<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#new-text-comparators">​</a></h3>
<p>In Config V2, we're introducing new text comparators, expanding your toolkit with options like <code>EQUALS</code>, <code>NOT EQUALS</code>, <code>STARTS WITH ANY OF</code>, <code>NOT STARTS WITH ANY OF</code>, <code>ENDS WITH ANY OF</code>, and <code>NOT ENDS WITH ANY OF</code>. Let's see them one by one.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="equals">EQUALS<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#equals">​</a></h4>
<p>Check if a given string exactly matches the specified value. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"userType" EQUALS "admin"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/equals.png" alt="Equals">
<blockquote>
<p>Ensures only users with the type 'admin' are targeted.</p>
</blockquote>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="not-equals">NOT EQUALS<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#not-equals">​</a></h4>
<p>Determines if a string does not match the provided value. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"Country" NOT EQUALS "Canada"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/not-equals.png" alt="Not equals">
<blockquote>
<p>Targets all users outside Canada.</p>
</blockquote>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="starts-with-any-of">STARTS WITH ANY OF<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#starts-with-any-of">​</a></h4>
<p>Tests if a string starts with any of the specified substrings. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"Email" STARTS WITH ANY OF ["info@", "support@"]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/starts-with-any-of.png" alt="Starts with any of">
<blockquote>
<p>Would target emails starting with 'info@' or 'support@'.</p>
</blockquote>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="not-starts-with-any-of">NOT STARTS WITH ANY OF<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#not-starts-with-any-of">​</a></h4>
<p>Ensures a string does not start with any of the specified prefixes. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"username" NOT STARTS WITH ANY OF ["temp", "guest"]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/not-starts-with-any-of.png" alt="Not starts with any of">
<blockquote>
<p>Excludes users with 'temp' or 'guest'.</p>
</blockquote>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="ends-with-any-of">ENDS WITH ANY OF<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#ends-with-any-of">​</a></h4>
<p>Check if a string ends with any of the given substrings. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"file" ENDS WITH ANY OF [".pdf", ".docx"]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/ends-with-any-of.png" alt="Ends with any of">
<blockquote>
<p>Targets only files ending in .pdf or .docx.</p>
</blockquote>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="not-ends-with-any-of">NOT ENDS WITH ANY OF<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#not-ends-with-any-of">​</a></h4>
<p>Confirms a string does not end with any of the listed suffixes. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"image" NOT ENDS WITH ANY OF [".png", ".jpg"]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/not-ends-with-any-of.png" alt="Not ends with any of">
<blockquote>
<p>Excludes images ending in .png or .jpg.</p>
</blockquote>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="date--time-comparators">Date &amp; Time Comparators<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#date--time-comparators">​</a></h3>
<p>ConfigCat now includes Date and Time comparators, namely <code>BEFORE</code> and <code>AFTER</code>, making feature flag management simpler than ever. These comparators are perfect for managing time-specific campaigns like summer sales, Black Friday events, Christmas promotions, and more. They help you easily control when your promotions start and end, making it simple to run successful marketing campaigns.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="before">BEFORE<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#before">​</a></h4>
<p>Compares if a date is earlier than the specified date. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"expiryDate" BEFORE "2022-12-31"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/date-time-before.png" alt="Date &amp; Time before">
<blockquote>
<p>Targets all items that expire before January 1, 2023.</p>
</blockquote>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="after">AFTER<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#after">​</a></h4>
<p>Determines if a date is later than the provided date. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"startDate" AFTER "2023-01-01"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/date-time-after.png" alt="Date &amp; Time after">
<blockquote>
<p>Would target items starting from January 2, 2023.</p>
</blockquote>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="array-comparators">Array Comparators<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#array-comparators">​</a></h3>
<p>When it comes to managing arrays of strings, Config V2 offers powerful tools known as Array Comparators. These comparators are designed to handle arrays efficiently, simplifying complex comparisons.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="array-contains-any-of">ARRAY CONTAINS ANY OF<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#array-contains-any-of">​</a></h4>
<p>Verifies if any element of the array matches any of the specified values. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"tags" ARRAY CONTAINS ANY OF ["urgent", "high-priority"]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/array-contains-any-of.png" alt="Array contains any of">
<blockquote>
<p>Targets items tagged as 'urgent' or 'high-priority'.</p>
</blockquote>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="array-not-contains-any-of">ARRAY NOT CONTAINS ANY OF<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#array-not-contains-any-of">​</a></h4>
<p>Check if the array does not contain any of the specified elements. For example:</p>
<div class="language-md codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-md codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">"features" ARRAY NOT CONTAINS ANY OF ["beta"]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/new-comparators/array-not-contains-any-of.png" alt="Array not contains any of">
<blockquote>
<p>Targets all feature sets that do not include 'beta'.</p>
</blockquote>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/20/config-v2-new-comparators/#conclusion">​</a></h2>
<p>What sets Config V2 apart is the ability to mix and match these comparators, empowering you to precisely tailor your Targeting Rules according to your desired user base. By implementing these comparators for texts, dates, and arrays, you ensure that your features reach the right users at the right time, enhancing both functionality and user satisfaction.</p>
<p>For more insights and updates on our latest tools, follow ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>config v2</category>
            <category>feature management system</category>
        </item>
        <item>
            <title><![CDATA[InfluxDB's Success Story with ConfigCat]]></title>
            <link>https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/</link>
            <guid>https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/</guid>
            <pubDate>Wed, 15 May 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[InfluxDB's success in user testing with ConfigCat's feature flags in Cloud 2.]]></description>
            <content:encoded><![CDATA[<p>In the ever-evolving world of software development, the ability to create personalized and dynamic user experiences is paramount. This article explores how <a href="https://www.influxdata.com/" target="_blank" rel="noopener noreferrer">InfluxDB</a>, a prominent time-series database solution, leveraged <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer">ConfigCat's feature flags</a> to enhance their Cloud 2 user testing processes. The insights shared in this article are based on a <a href="https://www.youtube.com/watch?v=nx_Hv4A4Xd4" target="_blank" rel="noopener noreferrer">video presentation</a> by Gavin Cabbage from InfluxDB.</p>
<p><img decoding="async" loading="lazy" alt="InfluxData and ConfigCat logo cover" src="https://configcat.com/blog/assets/images/influxdb-19a3109221853842cb70caf6c0bc1e0c.png" width="800" height="450" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="gavins-demo-a-glimpse-into-cloud-2-user-testing">Gavin's Demo: A Glimpse into Cloud 2 User Testing<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#gavins-demo-a-glimpse-into-cloud-2-user-testing">​</a></h2>
<p>Gavin's presentation showcased how InfluxDB harnessed the power of ConfigCat feature flags for user testing within their Cloud 2 environment. The primary goal was to illustrate a testing flow, emphasizing that there are various other ways to do it.</p>
<p>Let's jump into the demonstration, but first, a few words need to be mentioned about these useful tools. Feature flags, also referred to as feature toggles, serve as a valuable instrument in software development, providing developers with the capability to activate or deactivate specific features in a live environment. This dynamic functionality allows for controlled adjustments to the application's behavior without the need for code changes, offering flexibility in managing feature releases and testing different configurations.</p>
<p>In this specific pattern presented, InfluxDB had particular users in mind and aimed to provide them with different prototypes for testing. The demo highlighted the ease with which ConfigCat could be integrated into their existing infrastructure and workflow to perform dynamic and targeted user testing. They could configure rules within the ConfigCat console, making it possible to effectively personalize the user experience. This flexibility allowed InfluxDB to gather invaluable user feedback and preferences insights.</p>
<p>Here you can see the feature flag architecture built out for Cloud 2:</p>
<p><img decoding="async" loading="lazy" alt="Feature flag architecture" src="https://configcat.com/blog/assets/images/feature-flag-architecture-b51b79ce61cd22bd09193da9d16337a6.png" width="799" height="449" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="key-takeaways-from-the-presentation">Key Takeaways from the Presentation<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#key-takeaways-from-the-presentation">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="dynamic-user-testing">Dynamic User Testing<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#dynamic-user-testing">​</a></h3>
<p>In the video, InfluxDB demonstrated how they configured rules within the ConfigCat console to personalize the user experience effectively. For instance, they could change the language in messages, offering different versions of a message to different user segments: one user could be met with the slightly mean "No dashboards found dummy!" message, while for others "I am so sorry! We couldn't find your dashboards" appeared.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="effortless-integration">Effortless Integration<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#effortless-integration">​</a></h3>
<p>InfluxDB showcased how ConfigCat seamlessly integrates into the development process. Developers can easily incorporate feature flags into their code, as ConfigCat generates the necessary code based on the configuration. This integration not only streamlines operations but also maintains type safety in the backend, reducing the chances of errors.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="centralized-control">Centralized Control<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#centralized-control">​</a></h3>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a> acts as a central hub for managing feature flags. In the presentation, InfluxDB demonstrated how they could configure flags, set default values, and control exposure to the front end — all from a single location. This centralized control simplifies flag management and reduces complexity, making it easier for teams to collaborate.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="real-time-configurations">Real-Time Configurations<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#real-time-configurations">​</a></h3>
<p>As demonstrated, changes to the application's behavior can be made without requiring code deployments. This real-time flexibility allows teams to respond promptly to user feedback and evolving requirements. For example, InfluxDB showed how they could instantly change the content of a message for different users.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="front-end-control">Front-End Control<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#front-end-control">​</a></h3>
<p>In the demo, InfluxDB illustrated that some feature flags can also be exposed to the front end. This feature provides developers with control over the presentation and behavior of the application. They can use feature flags for backend functionality and customizing the user experience, which can be particularly useful in A/B testing and user-centric feature rollouts.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="scalability">Scalability<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#scalability">​</a></h3>
<p>The video showcased how ConfigCat's feature flags are scalable, making them suitable for different phases of deployment. In this case, InfluxDB simulated deployment to a local environment, but the flexibility to apply the same principles to various stages of deployment — such as staging and production — makes ConfigCat a versatile tool for both small-scale testing and large-scale implementations.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-power-of-user-centricity">The Power of User-Centricity<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#the-power-of-user-centricity">​</a></h2>
<p>InfluxDB's success with ConfigCat's feature flags underscores the importance of prioritizing the user in software development. By tailoring experiences, gathering feedback, and responding swiftly to user preferences, they elevated their user-centric approach.</p>
<p>ConfigCat's platform offered the tools needed to make this transition seamless and effective. It provided InfluxDB with the ability to experiment, iterate, and refine user experiences continuously. This user-centric perspective not only enhances the user journey but also ensures that software aligns more closely with user needs and expectations.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="wrapping-it-up">Wrapping it up<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/15/influxdbs-success-story-with-configcat/#wrapping-it-up">​</a></h2>
<p><a href="https://configcat.com/featureflags" target="_blank" rel="noopener noreferrer">ConfigCat's feature flags</a> are a valuable asset for any organization seeking to improve user experiences and streamline user testing. InfluxDB's successful journey demonstrates that with the right tools and a user-centric mindset, software development can evolve to meet the ever-changing demands of the modern tech landscape.
As technology continues to evolve, ConfigCat's feature flags are sure to remain a cornerstone of success for those who prioritize aligning software more closely with user needs and preferences.
Deploy any time, release when confident.</p>
<p>ConfigCat supports simple feature toggles, user segmentation, and A/B testing and has a generous <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">free tier</a> for low-volume use cases or those just starting out.</p>
<p>If you want to stay up-to-date with the mischievous antics of the cat with feature flags, follow ConfigCat on <a href="https://twitter.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>InfluxDB</category>
            <category>InfluxData</category>
            <category>Cloud 2</category>
            <category>success story</category>
            <category>user story</category>
            <category>ConfigCat</category>
        </item>
        <item>
            <title><![CDATA[Feature Management in the Era of AI - Opportunities and Challenges]]></title>
            <link>https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/</link>
            <guid>https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/</guid>
            <pubDate>Thu, 09 May 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[This article explores the potential of AI in feature management in software development. Discover how AI enhances efficiency, innovation, and precision in tasks like predictive feature flagging and A/B testing while navigating its challenges.]]></description>
            <content:encoded><![CDATA[<p>The rise of AI in software development is reshaping the industry's landscape, redefining roles, and setting new benchmarks for efficiency, innovation, and creativity. Gone are the days when software development was exclusively the domain of developers meticulously crafting code, with the process steeped in manual oversight and prone to human error. The introduction of AI into this sphere has been akin to when factories started using assembly lines in manufacturing—revolutionizing productivity and output quality.</p>
<p>AI's role in software development has swiftly moved from a supportive backdrop to a central player, taking on tasks that once consumed countless hours of human labor. Its capabilities have snowballed, from analyzing vast data to identifying patterns, automating repetitive tasks, and even preempting developer actions by suggesting improvements and debugging possible errors or bugs. It has enabled developers to transcend traditional limitations, empowering them to innovate at an unprecedented pace and scale. Hence, AI has become a keystone in the quest for efficiency, precision, and speed in software development.</p>
<p><img decoding="async" loading="lazy" alt="illustration of ai in feature management" src="https://configcat.com/blog/assets/images/ai-in-feature-management-cover-8d4b38bef0b4b723ee7263ebcc0b5afb.png" width="800" height="457" class="img_ev3q"></p>
<p>AI's integration into development processes has also catalyzed the emergence of new ways to leverage its strengths, predicated on its intelligent analysis and application of data models to enhance the software development lifecycle. One of these emerging advancements is in the innovative interplay between AI and <a href="https://configcat.com/feature-toggle-management/" target="_blank" rel="noopener noreferrer">feature management</a> in reshaping how we create, deploy, and manage software and its associated features. While these advancements possess a wealth of potential, they also pose complexities and challenges that require thoughtful consideration and navigation.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="predictive-feature-flagging-using-ai-to-predict-optimal-feature-releases">Predictive Feature Flagging: Using AI to Predict Optimal Feature Releases<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#predictive-feature-flagging-using-ai-to-predict-optimal-feature-releases">​</a></h2>
<p>Feature flagging is a feature management technique used in software development to dynamically turn features on or off without redeploying the entire application, which allows developers to test changes in production with specific user segments, perform <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B testing</a>, and roll out new features incrementally while mitigating deployment risks. Integrating AI into this process can improve the workflow to make it more efficient and automated.</p>
<p>Predictive feature flagging is one of such ways AI can be used to elevate feature management by facilitating the ability to predict the optimal time and manner to release new features; it's a bit like having an intelligent assistant to help decide when and how to introduce new features in a software application. This predictive model analyzes a wealth of data, including user behaviors or interactions, preferences, and feedback, alongside relevant trends or metrics to make predictive decisions.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="predicting-and-personalizing-feature-releases">Predicting and Personalizing Feature Releases<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#predicting-and-personalizing-feature-releases">​</a></h3>
<p>In the past, deciding when and how to release a new feature in an app was often based on a mix of experience and guesswork. It was a bit like trying to hit a moving target in the dark. However, with predictive feature flagging using AI, this process becomes more like turning on a light in that dark room by empowering decision-making with insights derived from comprehensive data analysis on how people use and interact with the software. These AI algorithms identify patterns and insights that humans might miss, like analyzing how people interact with different things in the app. Then, using this information, AI predicts how new features might perform when released to everyone.</p>
<p>Utilizing this method, you can also figure out when the best time is for a new feature to be released and the best group of users to try out the feature first. For example, an AI might suggest releasing a new feature on a specific weekday night if users are less active on the app during that particular weekday. AI can also personalize how features are released to different groups of users. Imagine you have a fitness app; AI might suggest initially releasing a new step-tracking feature to users who are already active joggers, but maybe not to those who use the app primarily for diet tracking initially to get more accurate feedback.</p>
<p>Predictive feature flagging isn't just about deciding when and what to release. It's also about learning from each release. Every time a feature is released, AI can gather more data about how users react and interact with it. This information helps it make even better predictions in the future. In other words, predictive feature flagging with AI has the potential to create a more responsive and adaptive feature release pipeline and make introducing new features safer and more user-centric. This is great for minimizing the uncertainties and risks of new features and understanding their potential impact before public release.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="automated-ab-testing-leveraging-ai-for-more-efficient-testing-scenarios">Automated A/B Testing: Leveraging AI for More Efficient Testing Scenarios<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#automated-ab-testing-leveraging-ai-for-more-efficient-testing-scenarios">​</a></h2>
<p><img decoding="async" loading="lazy" alt="illustration of AI in a/b testing" src="https://configcat.com/blog/assets/images/ai-in-ab-testing-5d9f321cc3ff16eb2439dc569055fed4.png" width="800" height="457" class="img_ev3q"></p>
<p>Effectively fine-tuning your product to optimize engagement with your audience often hinges on how well you can experiment with and optimize different features and elements of your application. This is where <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B testing</a> plays a pivotal role by serving as a cornerstone and vital tool for businesses to compare two versions of a webpage or experiment with different implementations of features to determine which variations perform better.</p>
<p>However, conducting these experiments thoroughly and accurately is not a trivial task. It requires significant time and resources, often involving complex planning, execution, and analysis to yield meaningful results. AI can transform this landscape by turbocharging A/B tests to automate and enhance many aspects of the A/B testing process for more efficient testing scenarios. For instance, it can quickly generate multiple variations of web pages and content, predict outcomes based on historical data, or even analyze test results to extract insights more efficiently than manual methods.</p>
<p>By summarizing test outcomes and highlighting key findings, AI not only speeds up the analysis process but can also provide actionable insights for future strategies. This accelerates the learning and adaptation curve from each set of experiments to significantly reduce the time and effort traditionally required in A/B testing.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ais-role-in-overcoming-ab-testing-challenges">AI's Role in Overcoming A/B Testing Challenges<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#ais-role-in-overcoming-ab-testing-challenges">​</a></h3>
<p>Another area where AI proves invaluable is in identifying optimization barriers in A/B testing. By analyzing user feedback and performance data, AI can quickly pinpoint areas hindering conversion rates and help businesses understand common pain points and preferences, allowing immediate action to enhance application performance or shape future A/B testing strategies. Furthermore, feeding competitor data into an AI can also enable businesses to gain insights into optimization strategies, keeping them ahead in an increasingly competitive market.</p>
<p>Moreover, many businesses lack the needed resources and traffic to conduct sufficient A/B tests. This lack makes achieving successful and consistent experiments to benefit from website optimization efforts challenging. Using AI tools, teams can examine key metrics, such as conversion rate, revenue, and retention, to see how they differ between variations.</p>
<p>You can also use them to spot anomalies, outliers, or trends in your data. The ability of AI to process and synthesize large datasets comes in handy in anticipating future trends, allowing businesses to tailor their tests more effectively. This predictive capacity not only helps conduct more focused and relevant experiments but also streamlines the optimization process to ensure that implementations and features remain at the forefront of your industry.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="potential-pitfalls-and-considerations-when-combining-ai-and-feature-management">Potential Pitfalls and Considerations When Combining AI and Feature Management<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#potential-pitfalls-and-considerations-when-combining-ai-and-feature-management">​</a></h2>
<p><img decoding="async" loading="lazy" alt="illustration of challenges when combining AI and feature management" src="https://configcat.com/blog/assets/images/ai-challenges-f9cc77ebff294f3b54be8c5942dbf7c0.png" width="800" height="457" class="img_ev3q"></p>
<p>Integrating AI with feature management opens up a realm of exciting opportunities. However, like adding a powerful engine to a car, ensuring that AI is safe and Synergizes well with existing systems is crucial.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="data-quality-and-quantity-the-foundation-of-ais-effectiveness">Data Quality and Quantity: The Foundation of AI's Effectiveness<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#data-quality-and-quantity-the-foundation-of-ais-effectiveness">​</a></h3>
<p>One of the primary challenges is the issue of data quality and quantity. AI systems require consistent and accurate data to learn effectively and make sound predictions. Insufficient or inaccurate data can lead to erroneous outcomes.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-expertise-gap-in-ai-implementation">The Expertise Gap in AI Implementation<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#the-expertise-gap-in-ai-implementation">​</a></h3>
<p>The complexity and rapid evolution of AI present another challenge: the expertise gap. Many software developers may not possess the necessary skills to implement AI effectively, leading to potential errors and inefficiencies in feature management.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="understanding-ai-decision-making-the-black-box-problem">Understanding AI Decision-Making: The 'Black Box' Problem<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#understanding-ai-decision-making-the-black-box-problem">​</a></h3>
<p>A significant hurdle is the 'black box' problem, where the reasoning behind AI's decisions is not always transparent or understandable, even to its creators. This lack of clarity can be problematic when using AI for critical decisions in feature management.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bias-in-ai-ensuring-fair-and-balanced-decisions">Bias in AI: Ensuring Fair and Balanced Decisions<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#bias-in-ai-ensuring-fair-and-balanced-decisions">​</a></h3>
<p>Another important concern is the unintentional encoding of biases in AI systems. These biases can lead to unfair or imbalanced decisions, especially in feature management, where they might result in the development of features that disproportionately favor certain user groups.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ethical-and-legal-considerations-in-ai-deployment">Ethical and Legal Considerations in AI Deployment<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#ethical-and-legal-considerations-in-ai-deployment">​</a></h3>
<p>Lastly, as AI assumes more responsibility in decision-making, ethical and legal considerations become increasingly important. Questions of accountability arise: who is responsible if an AI's decision leads to a software problem? Is it the developers, the company, or the AI itself?</p>
<p>Navigating these ethical waters and challenges can be tricky and requires careful planning and consideration. Nevertheless, addressing these challenges is critical to successfully harnessing the power of AI in feature management.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/05/09/feature-management-in-the-era-of-ai/#conclusion">​</a></h2>
<p>As AI tools become more sophisticated, the future of feature management is undeniably intertwined with it as it takes on more responsibilities in the development process, allowing developers to focus on creative and strategic tasks. The potential for AI to enhance feature management is immense; innovative techniques like predictive feature flagging and automated A/B testing only showcase a little of AI's potential to revolutionize how features are developed, tested, and rolled out.</p>
<p>AI's integration into feature management heralds a new age of efficiency and precision. The harmonious blend of human ingenuity and AI's capabilities will define the next generation of software development and feature management. However, developers and companies must approach this new era with a mindset of responsible AI use, ensuring that tomorrow's software is not just powerful but also equitable, transparent, and reliable.</p>
<p><a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a> is a developer-centric feature flag service with unlimited team size, awesome support, and a reasonable price tag. ConfigCat supports simple feature toggles, user segmentation, and A/B testing and has a generous <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">free tier</a> for low-volume use cases or those just starting out.</p>
<p>For more feature flagging goodies, stay connected to ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>feature management</category>
            <category>artificial intelligence</category>
            <category>AI</category>
            <category>feature flagging</category>
            <category>software development</category>
        </item>
        <item>
            <title><![CDATA[Using Feature Flags with Machine Learning Models]]></title>
            <link>https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/</link>
            <guid>https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/</guid>
            <pubDate>Tue, 23 Apr 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[A guide to using feature flags with machine learning models]]></description>
            <content:encoded><![CDATA[<p>Machine learning models are the core building blocks of artificial intelligence. As of this writing, a popular AI chatbot circulating in the media and tech industry is <a href="https://openai.com/blog/chatgpt" target="_blank" rel="noopener noreferrer">ChatGPT</a>. It uses several large generative language models under the hood and can perform tasks that some might describe as super-human.</p>
<p>This advancement in AI showcases the potential of machine learning models and their transformative impact. With the number of machine learning libraries available on the internet, you can even develop your custom models. What's even better is that you can decouple the features of your model and control how they behave using feature flags.</p>
<p><img decoding="async" loading="lazy" alt="Using feature flags with machine learning models" src="https://configcat.com/blog/assets/images/using-feature-flags-with-ml-models-cover-eda5dc9efdbeed13d23abe569e09133d.jpg" width="800" height="450" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="using-feature-flags-with-machine-learning-models">Using feature flags with machine learning models<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/#using-feature-flags-with-machine-learning-models">​</a></h2>
<p>A <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer">feature flag</a> can be thought of as a toggle switch for a feature it is linked to. Using a conditional if-statement in your code, you can decide to render this feature if its flag is toggled on or choose to hide it otherwise if it is toggled off. However, feature flags aren't solely used for showing or hiding features from users. They can also be configured to augment various processes, including Canary Releases, Progressive Deployments, A/B Testing, DevOps, and CI/CD pipelines, to name a few.</p>
<p>Feature flags can bring these benefits to your machine-learning models as well. In the following section, I'll show you how to create two machine-learning models for classifying text using Python, as it is a widely used programming language for developing machine-learning models. Then, I'll use a feature flag to control what model to use for the classification. For this, I'll use <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a>. ConfigCat is a feature flag service with unlimited team size, awesome support, and a reasonable price tag that takes 10 mins to learn. Using their <a href="https://configcat.com/docs/sdk-reference/overview/" target="_blank" rel="noopener noreferrer">extensive list of SDKs</a>, you can easily integrate feature flags in just about any programming language and technology. Let's dive in!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="guide-how-to-use-feature-flags-with-machine-learning-models">Guide: How to use feature flags with machine learning models<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/#guide-how-to-use-feature-flags-with-machine-learning-models">​</a></h2>
<p>Using a popular machine learning library called <a href="https://spacy.io/" target="_blank" rel="noopener noreferrer">SpaCy</a>, I'll create two text classification models. One will serve as a base model, and the other as a pro model. These can typically fit into a scenario where you only need to give paid users access to the pro model while other users use the base model.</p>
<p>Both models take a sentence or a piece of text as input and classify it to an intent based on the training data each model was trained on. Here are the differences between the two models and the intents that they are capable of classifying text to.</p>
<ul>
<li><strong>Base model</strong>: goodbye, greeting, business_hours</li>
<li><strong>Pro model</strong>: goodbye, greeting, business_hours, payment_methods</li>
</ul>
<p>The key difference is that the pro model is capable of classifying a text such as:</p>
<p>"Can I pay you with my Google Pay wallet?" to <code>payment_methods</code>, whereas the base model would not.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="setup-of-a-demo-application">Setup of a demo application<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/#setup-of-a-demo-application">​</a></h3>
<p>I've created a <a href="https://github.com/configcat-labs/feature-flags-with-ml-models-sample" target="_blank" rel="noopener noreferrer">sample app</a> to demonstrate how a feature flag can be used to control which model classifies the text entered by a user.</p>
<p>In the <code>app.py</code> file, I've imported the resources needed to build and test each model. This is followed by two functions: <code>train_classifier(model_type)</code> and <code>classify_text(text, model_type)</code>. The <code>train_classifier</code> function takes <code>model_type</code> as a parameter (either 'pro' or 'base'), and the <code>classify_text</code> takes the text to classify and the <code>model_type</code> to use to perform the classification.</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># app.py</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> pandas </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> pd</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> sklearn</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">svm </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> LinearSVC</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> sklearn</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">model_selection </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> train_test_split</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> sklearn</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">feature_extraction</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">text </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> CountVectorizer</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> sklearn</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">feature_extraction</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">text </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> TfidfTransformer</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> pickle5 </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> pickle</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">train_classifier</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">model_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Load the training data</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    df </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> pd</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">read_json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'./models/{0}/classification_data.json'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token builtin" style="color:rgb(130, 170, 255)">format</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">model_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    X_train</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> X_test</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> y_train</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> y_test </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> train_test_split</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'text'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> df</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'intent'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> random_state</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Train the model</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    count_vect </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> CountVectorizer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    X_train_counts </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> count_vect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">fit_transform</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">X_train</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    tfidf_transformer </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> TfidfTransformer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    X_train_tfidf </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> tfidf_transformer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">fit_transform</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">X_train_counts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    model </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> LinearSVC</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">dual</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"auto"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">fit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">X_train_tfidf</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> y_train</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Save the vectorizer </span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    vec_file </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./models/{0}/vectorizer.pickle'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token builtin" style="color:rgb(130, 170, 255)">format</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">model_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    pickle</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">dump</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">count_vect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">open</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">vec_file</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'wb'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Save the model</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    mod_file </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./models/{0}/classifier.model'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token builtin" style="color:rgb(130, 170, 255)">format</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">model_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    pickle</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">dump</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">open</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">mod_file</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'wb'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Print training complete to the terminal</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Training completed for {0} model"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token builtin" style="color:rgb(130, 170, 255)">format</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">model_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">classify_text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> model_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Load the vectorizer</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    vec_file </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./models/{0}/vectorizer.pickle'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token builtin" style="color:rgb(130, 170, 255)">format</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">model_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    count_vect </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> pickle</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">load</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token builtin" style="color:rgb(130, 170, 255)">open</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">vec_file</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'rb'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Load the model</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    mod_file </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./models/{0}/classifier.model'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token builtin" style="color:rgb(130, 170, 255)">format</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">model_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    model </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> pickle</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">load</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token builtin" style="color:rgb(130, 170, 255)">open</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">mod_file</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'rb'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Classify the text</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    text_counts </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> count_vect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">transform</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    predicted </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">predict</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">text_counts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    scores </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">decision_function</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">text_counts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    result </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">'model'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> model_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">'intent'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> predicted</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">'confidence'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">max</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">scores</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">'text'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> text</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> result</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In the <code>interact.py</code> file, I've imported both the <code>train_classifier</code> and <code>classify_text</code> functions from <code>app.py</code> and added a <strong>test_query()</strong> function, which takes the text entered by the user and passes it to the <code>classify_text</code> function, printing the result to the terminal.</p>
<p>The second function, <strong>run_app()</strong>, performs the command line interaction. Finally, a while loop was added at the bottom to keep the <strong>run_app()</strong> function active until the user exits the interaction.</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># interact.py</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> app </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> train_classifier</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> classify_text</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">test_query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    text </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Hi I'm a chatbot. Lets talk: "</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    result </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> classify_text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'pro'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">run_app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    option </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"1 - Interact | 2 - Train | 3 - Exit: "</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> option </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"1"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        test_query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">elif</span><span class="token plain"> option </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"2"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        model </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Model to train: 1 - Base | 2 - Pro: "</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        selected_model </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'base'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> model </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'1'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'pro'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        train_classifier</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">selected_model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">elif</span><span class="token plain"> option </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"3"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">True</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">while</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">True</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">not</span><span class="token plain"> run_app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">break</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="adding-a-feature-flag">Adding a feature flag<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/#adding-a-feature-flag">​</a></h3>
<p>With the help of a feature flag, we can control which model can perform the text classification. One exciting benefit of feature flags in such a use-case scenario is that you can do this remotely without redeploying your application.</p>
<ol>
<li>
<p>To create a feature flag, sign up for a <a href="https://app.configcat.com/sign-up" target="_blank" rel="noopener noreferrer">free ConfigCat account</a>.</p>
</li>
<li>
<p>In the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer">dashboard</a>, create a feature flag with the following details:</p>
</li>
</ol>
<ul>
<li>Name: <code>Pro Model</code></li>
<li>Key: <code>proModel</code></li>
<li>Hint: <code>When on, the pro classifier model will be used</code></li>
</ul>
<ol start="3">
<li>To use the feature flag, I'll install the <a href="https://configcat.com/docs/sdk-reference/python/" target="_blank" rel="noopener noreferrer">ConfigCat SDK for Python</a>. The SDK is used to connect the app to ConfigCat and download the latest value of the feature flag.</li>
</ol>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">pip install configcat-client</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="4">
<li>Import the ConfigCat SDK in <code>interact.py</code></li>
</ol>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> configcatclient</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="5">
<li>Create the ConfigCat client and pass in your SDK key:</li>
</ol>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">configcat_client </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcatclient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">'YOUR-CONFIGCAT-SDK-KEY'</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Replace with your SDK key</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="6">
<li>I'll modify the <strong>test_query()</strong> function in <code>interact.py</code> to only use the pro model for making a classification when the feature flag is on and the base model when it is off:</li>
</ol>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> app </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> train_classifier</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> classify_text</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> configcatclient </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Import the ConfigCat SDK</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">configcat_client </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcatclient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token string" style="color:rgb(195, 232, 141)">'YOUR-CONFIGCAT-SDK-KEY'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Replace with your SDK key</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">test_query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    text </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Hi I'm a chatbot. Lets talk: "</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Get the value of the proModel feature flag</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    proModel </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> configcat_client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'proModel'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Use the pro model if the feature flag is on</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    model </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'pro'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> proModel </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'base'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    result </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> classify_text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="running-the-app">Running the app<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/#running-the-app">​</a></h3>
<p>Before testing the app and the feature flag, you'll need to ensure that you have the following installed:</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="prerequisites">Prerequisites<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/#prerequisites">​</a></h4>
<ul>
<li><a href="https://www.python.org/downloads/" target="_blank" rel="noopener noreferrer">Python 3</a></li>
<li><a href="https://pip.pypa.io/en/stable/installation/" target="_blank" rel="noopener noreferrer">Pip3</a></li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="steps">Steps<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/#steps">​</a></h4>
<ol>
<li>Clone the repository</li>
</ol>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">git clone git@github.com:configcat-labs/feature-flags-with-ml-models-sample.git</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="2">
<li>Create and activate a virtual environment</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">python3 -m venv venv</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">source venv/bin/activate</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="4">
<li>Install dependencies and run the app</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">pip3 install -r requirements.txt</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">python3 interact.py</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="5">
<li>Train both base and pro models by entering the appropriate option in the command line. For this example, I'll train the base model first.</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">1 - Interact | 2 - Train | 3 - Exit: 2</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Model to train: 1 - Base | 2 - Pro: 1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Training completed for base model</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Train the pro model.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">1 - Interact | 2 - Train | 3 - Exit: 2</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Model to train: 1 - Base | 2 - Pro: 2</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Training completed for pro model</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="6">
<li>Now, copy your SDK key from the <a href="https://app.configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat dashboard</a> and paste it into the <code>YOUR-CONFIGCAT-SDK-KEY</code> placeholder in the <code>interact.py</code> file.</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="did-it-work">Did it work<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/#did-it-work">​</a></h3>
<ol>
<li>
<p>Head over to CC and <strong>enable the feature flag</strong>.</p>
</li>
<li>
<p>Run the app again and enter a text to classify. The output should show that the pro model is used for classifying the text:</p>
</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">1 - Interact | 2 - Train | 3 - Exit: 1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Hi, I'm a chatbot. Let's talk: can I pay you with my Google Pay wallet?</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">{'model': 'pro', 'intent': 'payment_methods', 'confidence': 2.0369560833357596, 'text': 'Can I pay you with my Google Pay wallet?'}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<ol start="3">
<li><strong>Disable the feature flag</strong>. You should now see that the base model is used to classify the text.</li>
</ol>
<blockquote>
<p>The ConfigCat SDK downloads and stores the latest values automatically every 60 seconds. You can change this default behavior. Check out the <a href="https://configcat.com/docs/sdk-reference/python/" target="_blank" rel="noopener noreferrer">ConfigCat SDK Docs</a> to learn more.</p>
</blockquote>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">1 - Interact | 2 - Train | 3 - Exit: 1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Hi, I'm a chatbot. Let's talk: can I pay you with my Google Pay wallet?</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">{'model': 'base', 'intent': 'greeting', 'confidence': 0.32370119051141377, 'text': 'Can I pay you with my Google Pay wallet?'}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>From the above, you can see that the feature flag was used to control which model to use in classifying the text. When the flag was off, the base model was used, and the result intent was greeting, which is an incorrect classification. When the flag was on, the pro model was used, and the result intent was <code>payment_methods</code>, which is the correct classification.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-future-of-feature-flags-and-machine-learning-models">The future of feature flags and machine learning models<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/23/using-feature-flags-with-ml-models/#the-future-of-feature-flags-and-machine-learning-models">​</a></h2>
<p><img decoding="async" loading="lazy" alt="The future of feature flags and machine learning models" src="https://configcat.com/blog/assets/images/the-future-ad1bd94ac6216d114fa27d81b088f4f3.jpg" width="798" height="450" class="img_ev3q"></p>
<p>With machine learning models becoming increasingly popular, I believe that feature flags will play a significant role in how they are used. Feature flags can be used to control the behavior of these models, what data to use when training a model, and even what model to use for a specific task. I'm excited to see how feature flags will be used with machine learning models in the future.</p>
<p>If you want to try what you've learned, check out <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a>. They have a <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">forever-free plan</a> that you can use to get started. You can also check out the <a href="https://configcat.com/docs/sdk-reference/python/" target="_blank" rel="noopener noreferrer">ConfigCat Python SDK Docs</a> to dive deeper into using feature flags with Python. Deploy any time, release when confident.</p>
<p>Stay connected to ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://twitter.com/configcat" target="_blank" rel="noopener noreferrer">X (Twitter)</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature-flags</category>
            <category>machine-learning</category>
            <category>feature-management</category>
            <category>ml-models</category>
            <category>configcat</category>
        </item>
        <item>
            <title><![CDATA[The Ethical Implications of Feature Flags in Software Development]]></title>
            <link>https://configcat.com/blog/2024/04/16/the-ethical-implications-of-feature-flags-in-software-development/</link>
            <guid>https://configcat.com/blog/2024/04/16/the-ethical-implications-of-feature-flags-in-software-development/</guid>
            <pubDate>Tue, 16 Apr 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[This article explores the ethical implications of using feature flags in software development, examining the balance between innovation and ensuring ethical standards in feature flagging.]]></description>
            <content:encoded><![CDATA[<p>The conversation about ethics in technology has become increasingly vital as software continues to advance and intertwines deeply with our daily lives. Among the various pivotal tools at a developer's disposal, feature flags stand out due to their profound impact on user experience and business outcomes. They allow for the selective enabling and disabling of features without deploying new code, fundamentally transforming how features are rolled out, tested, and managed. This flexibility is revolutionary, facilitating dynamic changes to the software environment that can be tailored to diverse user groups and providing a robust platform for experimentation.</p>
<p><img decoding="async" loading="lazy" alt="illustration of developer implementing feature flags" src="https://configcat.com/blog/assets/images/the-power-of-feature-flags-a984885ee1a877e14c2bac2766b5d8a5.png" width="800" height="457" class="img_ev3q"></p>
<p>However, as with any powerful technology, feature flags introduce a complex array of ethical considerations that intersect with the technical prowess they offer. The capability to alter user experiences on the fly, personalize content delivery, and control feature accessibility in the software system requires a conscientious approach to avoid ethical pitfalls. These toggles can influence how users interact with software, subtly shaping their digital environment in ways that may not always be apparent or transparent. This power also introduces concerns that demand a critical examination of the strategies employed in feature flagging from an ethical standpoint.</p>
<p>How, then, can developers ensure these tools are used to enhance user experience rather than diminish it? What safeguards are necessary to prevent the exploitation of feature flagging capabilities? And, importantly, how can organizations cultivate an ethical framework that governs the use of feature flags? Addressing these questions is vital, as the answers will necessitate a balance between leveraging its technological advancement and honoring the trust users place in software products.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-power-of-feature-flags-controlling-user-experience">The Power of Feature Flags: Controlling User Experience<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/16/the-ethical-implications-of-feature-flags-in-software-development/#the-power-of-feature-flags-controlling-user-experience">​</a></h2>
<p>Feature flags represent an innovative shift in the control and agility within the software development process. At their core, feature flags let you launch new features and change your software configuration without (re)deploying code. This technical lever can dramatically alter the user interface and capabilities available to different users or groups, making the user experience highly customizable.</p>
<p>The real power of feature flags lies in their ability to segment control over who experiences what within an application. Imagine being able to release a new feature to 10% of your users to gauge reaction before a full rollout or quickly disabling a malfunctioning feature without taking down your entire site. Feature flags offer this level of granular control, acting as gatekeepers that can introduce changes incrementally or all at once based on predefined conditions.</p>
<p>This granularity extends to conducting A/B testing, where developers can present two variations of a feature to different user segments simultaneously to determine which performs better. It also allows for canary releases, a pattern where new features are rolled out to a small subset of users to ensure stability before a broader release. Such strategies enable the collection of valuable feedback and data that inform further development, ensuring that the software evolves in a direction that aligns with user needs and preferences.</p>
<p>Beyond testing and deployment, feature flags can manage operational risks by providing a fail-safe. If a new feature causes issues post-release, it can be quickly rolled back, minimizing user inconvenience and potential reputational damage. This capability underscores the responsiveness and resilience that feature flags bring to modern software operations.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ethical-dilemmas-potential-misuse-and-user-manipulation">Ethical Dilemmas: Potential Misuse and User Manipulation<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/16/the-ethical-implications-of-feature-flags-in-software-development/#ethical-dilemmas-potential-misuse-and-user-manipulation">​</a></h2>
<p><img decoding="async" loading="lazy" alt="illustration of users interacting with applications" src="https://configcat.com/blog/assets/images/ethical-use-of-feature-flags-cover-1dcca8cceb03bf8b6413c2c351f2ba9c.png" width="800" height="457" class="img_ev3q"></p>
<p>The ethical implications of feature flags span various dimensions—privacy concerns, fairness in feature accessibility, the integrity of user consent, and the potential for behavioral manipulation. These dilemmas stem from the inherent potential for misuse inherent in any powerful tool, as great power comes with great responsibility. With feature flags, this potential is multifaceted, given the degree of control they provide over the user's experience.</p>
<p>A major ethical concern is the possibility of user manipulation, as feature flags can be employed to shape users' experience and subtly guide their actions and decisions or manipulate user behavior in a way that may prioritize business objectives over user welfare. For example, by selectively showcasing features that lead to higher engagement or monetization, developers could nudge users toward certain behaviors without their explicit consent or awareness.</p>
<p>Moreover, feature flags could be used to conduct experiments on user groups without their knowledge or create "dark patterns" that benefit the business at the user's expense, potentially breaching the ethical standards of informed consent. Imagine a scenario where a feature flag is used to manipulate how personal data is collected or the interface through which choices are made without clear communication to users. This not only raises privacy concerns but also touches upon the respect for user autonomy and their right to be informed or give consent.</p>
<p>The potential for discrimination is another potential ethical pitfall that can be associated with feature flags. Decisions about which users see what features can be based on demographics or user behavior, leading to a potentially discriminatory experience where certain groups receive preferential treatment. This could inadvertently reinforce biases or create a sense of exclusion among users who do not receive the 'full' version of the application. While business models may necessitate similar stratification as with a multi-tiered system or 'premium' access, it's important to consider where to draw the line ethically. The ethical use of feature flags requires vigilance against such practices, ensuring that they are not employed to deceive or exploit users.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="best-practices-ensuring-ethical-use-of-feature-flags">Best Practices: Ensuring Ethical Use of Feature Flags<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/16/the-ethical-implications-of-feature-flags-in-software-development/#best-practices-ensuring-ethical-use-of-feature-flags">​</a></h2>
<p><img decoding="async" loading="lazy" alt="illustration of teams following best practices with feature flags" src="https://configcat.com/blog/assets/images/best-practices-to-follow-06fefe1ed7b3ee8ef672290f6bc4ff3c.png" width="800" height="457" class="img_ev3q"></p>
<p>Feature flags are much more than a technical convenience; they are a testament to how software development has evolved into a responsive, user-centric practice. They encapsulate the shift towards an iterative, feedback-informed approach to product development, with the user experience at its heart.</p>
<p>However, implementing feature flags, while innovative and powerful, necessitates the adoption of best practices to ensure their use upholds the highest ethical standards. Some key best practices that should be adopted include:</p>
<ul>
<li><strong>Transparency with Users:</strong> Users should be informed when they are part of a test group or when features may be subject to change. This includes clear communication about what data is being collected during the testing and how it will be used.</li>
<li><strong>Informed Consent:</strong> Prior to collecting data or exposing users to potentially impactful feature changes, obtain their consent. This goes beyond mere notification and involves ensuring that the users understand the implications of their participation.</li>
<li><strong>Equitable Feature Rollout:</strong> Avoid discrimination by ensuring that feature flag rollouts are based on objective criteria that do not unfairly prejudice any user group. Regular audits for bias can help maintain this equity.</li>
<li><strong>Adherence to Privacy Standards:</strong> Feature flags must be designed to comply with existing privacy laws and regulations, like GDPR or CCPA, which means not using them to circumvent user privacy controls or expectations.</li>
<li><strong>Ethical A/B Testing:</strong> When conducting A/B tests, establish clear hypotheses and success metrics that do not manipulate user behavior for unjust gain. A/B testing should be used to enhance user experience, not to exploit.</li>
<li><strong>Avoidance of Dark Patterns:</strong> Be vigilant against the use of feature flags to create interfaces that deceive or mislead users. This includes avoiding tricks to opt users into services, obscure cancellation processes, or misrepresent feature sets.</li>
<li><strong>Regular Review and Accountability:</strong> Implement a process for regular review of feature flag usage, with clear accountability structures in place. This ensures ongoing ethical compliance and provides a framework for addressing any issues that arise.</li>
<li><strong>Documentation and Audit Trails:</strong> Keep detailed logs of feature flag implementations and control and audit access to flags. This not only provides transparency but also ensures there is a trail to audit in the case of an ethical breach.</li>
<li><strong>Stakeholders Involvement:</strong> Involve stakeholders, including compliance experts, in the planning and review stages of feature flag implementation to ensure a broader perspective is considered.</li>
</ul>
<p>As the guardians of user experience, developers, product managers, and all stakeholders must tread carefully, ensuring that the power of feature flags is harnessed for good, keeping the user's best interests at the forefront of any feature flag use. It’s about fostering trust and respect with the user base, ensuring that the flags serve to enhance, rather than detract from, the overall user experience.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/16/the-ethical-implications-of-feature-flags-in-software-development/#conclusion">​</a></h2>
<p>In navigating these ethical waters, the challenge lies in balancing the undoubted benefits of feature flags with a commitment to user respect and dignity. Developers and companies must ask themselves hard questions about the implications of their feature flag strategies, ensuring that they are not crossing the line from innovation into manipulation. Establishing ethical guidelines and a culture of accountability is paramount in ensuring that the implementation of feature flags remains within the bounds of moral practice.</p>
<p>By integrating the best practices into the fabric of the development process, organizations can ensure that the use of feature flags aligns with ethical standards and respects the rights and experiences of users. It is not just about mitigating risks but also about fostering a culture of ethical awareness and user-centricity that drives the software development industry forward responsibly.</p>
<p>If you're looking for a service to support dynamic feature toggles (and bear in mind that simple feature toggles work well too), check out <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a>. We'd describe it as "like LaunchDarkly but cheaper and a bit less fancy" and find that it does most of what we need. ConfigCat supports simple feature toggles, user segmentation, and A/B testing and has a generous <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">free tier</a> for low-volume use cases or those just starting out</p>
<p>For more feature flagging goodies, stay connected to ConfigCat on <a href="https://x.com/configcat" target="_blank" rel="noopener noreferrer">X</a>, <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>user experience</category>
            <category>ethical use</category>
            <category>best practices</category>
            <category>software development</category>
        </item>
        <item>
            <title><![CDATA[AND Conditions in Config V2]]></title>
            <link>https://configcat.com/blog/2024/04/15/config-v2-and-conditions/</link>
            <guid>https://configcat.com/blog/2024/04/15/config-v2-and-conditions/</guid>
            <pubDate>Mon, 15 Apr 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[An overview of Config V2's AND Conditions]]></description>
            <content:encoded><![CDATA[<p><strong>Config V2</strong> introduces a powerful new feature: <a href="https://configcat.com/docs/advanced/config-v2/#and-conditions" target="_blank" rel="noopener noreferrer"><strong>AND conditions</strong></a>. These conditions enable you to create more sophisticated Targeting Rules, allowing for precise feature deployment based on multiple criteria.</p>
<p><img decoding="async" loading="lazy" alt="And Conditions" src="https://configcat.com/blog/assets/images/and-conditions-thumbnail-951f5ecbc5e18a654d10440ad6276921.png" width="1280" height="720" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="overview">Overview<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/15/config-v2-and-conditions/#overview">​</a></h2>
<p>For example, you can now customize your feature rollout to users who meet several conditions simultaneously, such as residing in a specific country, using a particular email domain, and various other string matches. With <strong>AND conditions</strong>, you gain granular control over feature deployments, ensuring more personalized experiences for your users - especially with the ability to combine more conditions together.</p>
<p>Let's dive into an example to illustrate the effectiveness of <strong>AND conditions</strong>. In the featured image, the flag is configured to hold a truthy value for users residing in Mexico or Canada <strong>AND</strong> whose emails end with the <strong>@example.com</strong> string <strong>AND</strong> who registered before 2024.01.01. Conversely, it holds a falsy value for all other users.</p>
<img class="zoomable" src="https://configcat.com/blog/assets/config-v2/and-conditions.png" alt="And Conditions Example">
<p>For a detailed overview of the exciting new features in Config V2, take a look at our post <a href="https://configcat.com/blog/2024/04/05/config-v2-overview/" target="_blank" rel="noopener noreferrer">here</a>, or at our YouTube video below.</p>
<figure style="display:flex;justify-content:center"><iframe width="560" height="315" src="https://www.youtube.com/embed/95jA16tcqVc?si=Qs5r45iaaFb7F64P" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></figure>]]></content:encoded>
            <category>feature flags</category>
            <category>config v2</category>
            <category>feature management system</category>
            <category>and conditions</category>
        </item>
        <item>
            <title><![CDATA[Enhancing User Experience with Feature Flags]]></title>
            <link>https://configcat.com/blog/2024/04/10/feature-flags-ux/</link>
            <guid>https://configcat.com/blog/2024/04/10/feature-flags-ux/</guid>
            <pubDate>Wed, 10 Apr 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how feature flags empower developers to enhance the user experience of software applications.]]></description>
            <content:encoded><![CDATA[<p>In today's fast-paced digital landscape, delivering a seamless and adaptive user experience is paramount for any software application. Apart from functionality, users expect a responsive and evolving interface that caters to their ever-changing needs. With <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer">feature flags</a>, this becomes a reality. Feature flags are not just technical gadgets but are pivotal in crafting a user-centric software environment. By offering the ability to activate or deactivate features without altering the underlying codebase, they empower developers to enhance the user experience dynamically.</p>
<p><img decoding="async" loading="lazy" alt="Enhancing user experience with feature flags cover image" src="https://configcat.com/blog/assets/images/enhancing-user-interactions-9577012b3c5983dafeb35b2781ee47f3.png" width="800" height="642" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="enhancing-user-experience-with-feature-flags">Enhancing User Experience with Feature Flags<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/10/feature-flags-ux/#enhancing-user-experience-with-feature-flags">​</a></h2>
<p>The agility and responsiveness of an application play a crucial role in determining the success of the user experience. Here is where <a href="https://configcat.com/featureflags/" target="_blank" rel="noopener noreferrer">feature flags</a> come into the picture, offering a versatile approach to managing and improving UX. They provide developers with the flexibility to introduce, test, and refine features in a controlled and user-focused manner. In addition to toggling functionalities, they enhance the user journey through gradual releases, tailored experiences, and direct feedback integration.</p>
<p>For instance, in the competitive landscape of mobile gaming, the user experience plays a critical factor in the success of a game. Call of Duty: Mobile, a popular game known for its immersive gameplay and dynamic content, illustrates how feature flags can enhance user experience.
Imagine the team planning to introduce a new in-game event with unique missions and rewards. To handle this, they turn to feature flags for precision and user-centricity. Here's how:</p>
<ul>
<li>
<p><strong>Gradually release new features</strong> -  The team employs feature flags to first unveil the new event to a selected group of players. This methodical approach allows them to observe player reactions and measure the feature's impact on game dynamics, ensuring a polished and well-received rollout to the broader player base.</p>
</li>
<li>
<p><strong>Run A/B tests</strong> - Feature flags are instrumental in conducting <a href="https://configcat.com/blog/2022/05/02/what-is-ab-testing/" target="_blank" rel="noopener noreferrer">A/B tests</a>, allowing the team to experiment with different aspects of the event. By alternating between mission challenges or reward systems, they can determine which variation engages players the most, crafting the most thrilling and rewarding experience.</p>
</li>
<li>
<p><strong>Enhance user interactions</strong> - Utilizing feature flags for user personalization is a game-changer. The development team can tailor the event to different player skill levels, ensuring an enjoyable and challenging experience for everyone, from casual to hardcore gamers. When <a href="https://configcat.com/blog/2020/11/19/user-targeting/" target="_blank" rel="noopener noreferrer">targeting rules</a> are added to feature flags, developers can release features to specific groups of users based on a range of criteria, such as geographic location, user behavior, device type, subscription type, and more.</p>
</li>
</ul>
<p>Furthermore, these targeting rules enhance in-game personalization. For instance, players from different regions could access unique events or content during their local holidays or festivals, increasing the game's cultural relevance and appeal. Additionally, <a href="https://configcat.com/docs/advanced/targeting/" target="_blank" rel="noopener noreferrer">ConfigCat’s targeting rules</a> allow for segmentation based on custom attributes, like players’ skill levels, achievements, or in-game purchases. Such detailed segmentation paves the way for a highly tailored gaming experience, boosting player satisfaction and engagement by catering to individual preferences and play styles.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-role-of-feature-flags-in-ab-testing-and-user-feedback">The role of feature flags in A/B testing and user feedback<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/10/feature-flags-ux/#the-role-of-feature-flags-in-ab-testing-and-user-feedback">​</a></h2>
<p><img decoding="async" loading="lazy" alt="A/B testing and user feedback" src="https://configcat.com/blog/assets/images/testing-and-user-feedback-05986dc06c244909b808236ee0e880d4.png" width="800" height="698" class="img_ev3q"></p>
<p>A/B testing is a technique used for comparing two versions of your app to see which performs better. Consider it your own 'what do users like best?' experiment. For example, you can create two versions of a feature – let's call them Version A and Version B. These could be variations in your website button colors, different page layouts, or two different ways of navigating your app. You can then show these versions to separate groups of users and collect metrics to help you decide which version to roll out.</p>
<p>A/B testing with feature flags is great for its speed and efficiency. You can test out new ideas and make tweaks without heavy lifting. It’s like having a direct line to your users, getting their opinions, and then adjusting your app or website based on what they tell you. As you start playing around with more feature flags, things can get a bit complex. That's why using a tool to monitor and manage your feature flags, like <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a>, is really helpful. It keeps everything organized and simplifies A/B testing.</p>
<p><img decoding="async" loading="lazy" alt="Real time adjustments" src="https://configcat.com/blog/assets/images/realtime-feature-adjustments-5eb7da60c1acdf0de0223b7a1e4864ce.png" width="800" height="692" class="img_ev3q"></p>
<p>Feature flags are like magic wands for developers, especially when it comes to enhancing how users interact with apps in real time. But it’s not just about what products to show. Feature flags can do much more. Say you're developing a travel app. With feature flags, you can change what users see based on where they are. If someone's in Paris, your app can show them the best local cafes or art exhibitions happening around them. And if they jet off to Tokyo next, the app switches to showing cool sushi spots and tech stores, all in real time. This is super handy because it makes the app feel more personal for users and it makes their experience more engaging.</p>
<p>Think of feature flags as your personal control panel, allowing you to tweak and tune features on the fly. Imagine you're working on an online store. You can use feature flags to show users products based on their buying and browsing history. For instance, if someone has been exploring sci-fi books, they'll be greeted with the newest and most exciting sci-fi releases when they launch the website. Pretty neat, right?</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="case-study-spotify">Case study: Spotify<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/10/feature-flags-ux/#case-study-spotify">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Case study spotify" src="https://configcat.com/blog/assets/images/case-study-spotify-103e9c842bff73213169c41d9522a63a.jpg" width="800" height="563" class="img_ev3q"></p>
<p>Spotify, a renowned musical streaming platform, boasts an artful deployment of feature flags in its relentless pursuit of creating an exceptional user experience. Take, for instance, Spotify's adept use of feature flags to:</p>
<ul>
<li>
<p><strong>Gradually release new features</strong> - Spotify employs feature flags to <a href="https://configcat.com/blog/2019/11/30/targeting/" target="_blank" rel="noopener noreferrer">gradually introduce new features</a>, starting with a select group of users. This approach enables Spotify to gather valuable feedback on these features before their full-scale release to all users.</p>
</li>
<li>
<p><strong>Run A/B tests</strong> - Spotify uses feature flags to run A/B tests on different versions of its features. This assists Spotify in identifying and implementing the best possible user experience.</p>
</li>
<li>
<p><strong>Collect user feedback</strong> - Spotify uses feature flags to collect user feedback on new features before a full release, helping identify and resolve issues proactively.</p>
</li>
<li>
<p><strong>Enhance user interactions</strong> - Spotify uses feature flags to enhance user interactions in real time. For example, Spotify uses feature flags to personalize the user experience by showing different content to different users based on their interests.</p>
</li>
</ul>
<p>Gustav Söderström, Spotify's Chief Product Officer, discussed the importance of human perspectives in a data-driven world in a 2021 interview. He said:</p>
<p>*While data is crucial, we should exercise caution in over-reliance. To create enjoyable, user-centric products, it's equally vital to factor in human perspectives, like user feedback and qualitative research, <em>making the right user experience decision comes down to a human perspective.</em></p>
<p>Nhi Ngo realized this when creating and introducing a "Shortcuts" feature on the Spotify Home page. Powered by machine learning, Shortcuts is a dedicated place that displays the user's current favorites as determined by Spotify's algorithms. The feature was crafted using data from diverse research methods, including longitudinal user studies and A/B testing. The result? A new product feature that wowed Spotify consumers prompted subsequent enhancements, such as including more time-based elements in the model so that recommendations altered depending on the time of day (for example, offering sleep music playlists at night). Spotify's user experience demonstrates how feature flags enhance interactions.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" href="https://configcat.com/blog/2024/04/10/feature-flags-ux/#conclusion">​</a></h2>
<p>Feature flags, or feature toggles, are powerful software development tools that enable developers to activate or deactivate functionalities without modifying the underlying code. This flexibility allows for precise control over which features users can access, all without the hassle of deploying new updates. One of the critical benefits of feature flags is that they allow developers to experiment with new features and design changes without having to deploy multiple versions of their product. This can assist developers in identifying and implementing the best possible user experience while minimizing risk.</p>
<p>Another critical benefit of feature flags is collecting user feedback on new features before widespread release, helping developers address potential issues proactively. <a href="https://configcat.com/" target="_blank" rel="noopener noreferrer">ConfigCat</a> can safely enhance your development process. Feature flags are invaluable for developers who enhance the user experience. <a href="https://app.configcat.com/auth/signup" target="_blank" rel="noopener noreferrer">Get started</a> with the free plan or <a href="https://calendly.com/configcat/demo" target="_blank" rel="noopener noreferrer">book a personalized demo</a> where their team will guide you through the product, ensuring you have all your questions answered. Deploy any time, release when confident.</p>
<p>Stay connected to ConfigCat on <a href="https://www.facebook.com/configcat" target="_blank" rel="noopener noreferrer">Facebook</a>, <a href="https://twitter.com/configcat" target="_blank" rel="noopener noreferrer">X (Twitter)</a>, <a href="https://www.linkedin.com/company/configcat/" target="_blank" rel="noopener noreferrer">LinkedIn</a>, and <a href="https://github.com/configcat" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>]]></content:encoded>
            <category>feature flags</category>
            <category>feature management</category>
            <category>user experience</category>
            <category>user interaction</category>
        </item>
    </channel>
</rss>