Segment Rules and Conditions in Flagsmith
A complete, plain-English guide to deciding exactly who sees what: how segments are built from rules and conditions, how every operator behaves, how overlapping audiences are resolved, and how to test, debug and maintain targeting that stays correct as your product grows.
Picture a new feature that is ready, but not for everybody. You want your own staff to see it first. Then perhaps customers on the premium plan in one country. Then a quarter of everyone using the latest version of your mobile app. Each of those sentences describes an audience, and each audience is described by a few simple facts about the people in it: who they work for, which plan they pay for, where they live, which version they run. Turning those facts into a precise, reusable definition is the job of segments, and the building blocks inside segments are rules and conditions.
Flagsmith is an open-source feature flag and remote configuration service. Its segments let you describe an audience once, then use that description on as many flags as you like. A segment is only as good as its rules, though. A misplaced operator, a trait spelled slightly differently in two apps or an unexpected empty value can quietly send a feature to the wrong people. The details matter, and they are easy to learn when they are explained in order.
This guide starts with the very first idea, what a segment is, and builds up to the full set of operators, nested rule groups, percentage splits, evaluation order, testing habits, privacy care and long-term maintenance. No prior knowledge of Flagsmith is assumed, and no code is needed to follow along. Menu names and some options vary between versions and plans, so treat the screens described here as signposts and confirm the exact wording in your own dashboard and in the official documentation.
1Why Audience Rules Exist
A feature flag with only an on and off position is a blunt tool. Segments make it precise.
What is a feature flag, briefly?
A feature flag is a switch in your application that decides whether some behaviour is active. The code for a new feature is shipped, but it stays hidden until the flag is turned on. The decision lives in a service such as Flagsmith, outside your code, so changing it needs no new deployment. This separates deploying code from releasing a feature, which is the single biggest reason teams adopt flags.
The problem with “everyone or no one”
A plain switch has two outcomes. Everyone gets the feature, or nobody does. That is rarely what a real release needs. New features are risky, so you want a small, friendly audience first. Some features belong only to paying customers. Some should appear only in countries where you have a legal licence. Some should be hidden from people running an old app version that cannot display them. Each of these is a question about who the user is, not just a question about whether the feature is ready.
What is a segment?
A segment is a saved description of a group of users, built from facts about those users. You give it a name, such as “premium customers in India”, and you describe the group using rules. From then on, Flagsmith can answer a simple question for any user: do you belong to this group or not? Flags can then behave differently for members of the group, which is called a segment override.
Think of a members-only club with a doorkeeper. The doorkeeper has a written list of entry rules: over eighteen, holds a gold card, and either lives in the city or is a guest of a member. Each visitor is checked against the list, and the doorkeeper says yes or no. The rule list is the segment, each line on the list is a condition, and the club’s different rooms, which treat members differently, are the flags with segment overrides.
Why define the group once?
You could, in theory, write the audience rules separately on every flag. That would quickly become a mess. If the definition of “premium customer” changes, you would have to hunt through dozens of flags to update each copy. A segment solves this by keeping the definition in one place. Change the segment, and every flag that uses it follows automatically. This is the same reasoning that makes programmers put repeated code into one shared function.
Real-world example: Facebook’s Gatekeeper
Facebook has publicly described an internal system called Gatekeeper that decides which users see which features, based on rules about users such as their employment, location or a percentage of the population. The idea of keeping rules about people separate from the features themselves, and changing them without redeploying code, is exactly the approach segments bring to ordinary teams.
Describe every segment in business words, such as “trial customers” or “internal staff”. When someone reads a flag’s override list months later, a name that explains itself saves a trip into the rules.
2The Vocabulary: Eight Words You Need
Almost everything in targeting uses the same few terms. Learn them once and the rest of this guide reads smoothly.
Identity
A single user as your application describes them to Flagsmith, usually with a unique identifier such as an account number or email-free user ID.
Trait
A named piece of information about an identity, such as plan, country or app_version. Traits are what rules look at.
Segment
A named, reusable audience definition made of rules, defined once at the project level.
Rule
A container that groups conditions and says how they combine: all of them, any of them or none of them.
Condition
One check, made of a property, an operator and a value, such as “plan equals premium”.
Operator
The kind of comparison a condition makes: equals, greater than, contains, is set and others.
Segment override
A setting on a flag, in one environment, that says what members of a segment should receive.
Priority
The ranking of a flag’s overrides, used to decide which one wins when a user belongs to several segments.
flowchart TD
SEG["Segment: Premium customers in India"] --> R1["Rule group 1: ALL of the following"]
SEG --> R2["Rule group 2: ANY of the following"]
R1 --> C1["Condition: plan equals premium"]
R1 --> C2["Condition: country equals IN"]
R2 --> C3["Condition: app_version at least 4.2.0"]
R2 --> C4["Condition: platform equals web"]
SEG -. "used by" .-> OV["Segment override on a flag in one environment"]
Read the figure from the top. One segment holds one or more rule groups. Each rule group holds conditions and states how they combine. Every condition is a single test about a trait. The dotted arrow at the bottom shows that a flag uses the whole segment through an override, so the flag never needs to know how the audience was built. This layering is what lets you change the rules without touching a single flag.
Imagine a job advert that says: candidates must have a degree and five years of experience, and must be fluent in either French or German. The advert is the segment. “Degree and five years” is one rule group where all conditions must hold. “French or German” is another where any one is enough. A candidate qualifies only when every rule group is satisfied. Flagsmith segments work in the same layered way.
Segments are shared, overrides are local
A segment is defined at the project level, so the same definition is available in every environment. The override, which says what members receive for a particular flag, is stored per environment. This means “internal staff” can mean the same thing in Development, Staging and Production, while the flag’s behaviour for them can differ in each. Understanding this split avoids many surprises when moving settings between environments.
Flagsmith can also create segments that are specific to a single feature. Such a segment is built from the flag’s override screen and belongs only to that flag. It is convenient for a one-off audience, but a shared, named segment is better when the same group will be reused.
3How Traits Reach Flagsmith
Rules can only judge what they can see. Before writing a single condition, you must know where the facts come from.
No identity, no segment
Segments work on identities. When your application asks Flagsmith for flags without saying who the user is, Flagsmith can only return the environment’s default values. It has nobody to test against. To use segments, your application must identify the user, passing a unique identifier, and usually a set of traits at the same time. Only then can the rules be evaluated for that person. This is the most common reason that a segment seems to “do nothing” during a first trial.
Where traits come from
Traits are supplied by your own application, since only it knows the facts. A web shop might send the customer’s plan, signup date, country and number of past orders. A mobile app might add the app version, the operating system and the device type. Traits can be sent each time the user is identified, and Flagsmith can also store them so they are remembered between visits. The choice between sending and storing depends on how your systems are arranged and which version of Flagsmith you use.
Your app knows a fact
For example, the logged-in customer is on the premium plan and lives in India.
The app identifies the user
It sends the user’s identifier to Flagsmith and includes the relevant traits in the same request.
Flagsmith checks the segments
Every segment override on the requested flags is tested against the identity and its traits.
Flagsmith returns the answers
The application receives the flag values that apply to this particular person.
Types of traits
A trait has a value, and a value has a type. Text such as a country code is a string. A whole number such as the count of past orders is an integer. A decimal number such as a lifetime spend is a float. A true or false fact such as “has verified email” is a boolean. Flagsmith keeps the type with the trait and compares accordingly. The same characters can mean different things: the text “10” and the number ten behave differently when ordered. Sending numbers as numbers, not as text, is therefore important for greater-than and less-than conditions.
| Type | Example | Typical use | Care needed |
|---|---|---|---|
| String | country = IN | Plans, regions, roles | Spelling and letter case must match exactly |
| Integer | orders = 12 | Counts and levels | Send as a number, not as text |
| Float | spend = 149.50 | Money and measurements | Be careful with rounding |
| Boolean | verified = true | Yes and no facts | Agree on true and false, not “yes” and “1” |
Think of the registration form at a conference. Each box on the form is a trait: name, company, job role, dietary needs. The organiser’s rules, such as “give the vegetarian lunch to anyone who ticked vegetarian”, can only work on boxes that were actually on the form, filled in the expected way. If half the attendees wrote “veggie” and the other half wrote “vegetarian”, the rule misses half of them.
Storing and sending traits wisely
Use one naming style
Pick plan, not Plan in one app and user_plan in another. Trait names are matched exactly.
Send only what rules need
Every trait is data you must protect and pay to move. Send the facts your segments use and nothing more.
Keep values predictable
Use fixed vocabulary such as free, pro and enterprise, not free text typed by users.
Sensitive personal data
Do not use traits for passwords, health details or other private information. Chapter 20 explains why.
Traits sent from a browser or phone app can be changed by a determined user. Never use a client-supplied trait alone to protect something valuable, such as access to paid content. For anything that must be secure, let your own server decide and send the trusted result.
4The Anatomy of a Rule and a Condition
Every segment, however complicated it looks, is built from one small repeating shape.
What is a condition?
A condition is a single yes-or-no test about an identity. It has three parts. The property says which fact to look at, usually the name of a trait. The operator says how to compare it. The value says what to compare it with. Together they read like a short sentence: “country equals IN”, “orders is greater than 5” or “email contains example.com”. When Flagsmith evaluates the condition for a user, the answer is either true or false.
What is a rule?
A rule is a container for conditions. It decides how their separate answers combine into one answer. Flagsmith offers three kinds of rule type. An “all” rule is true only when every condition inside it is true, which behaves like the word AND. An “any” rule is true when at least one condition inside it is true, which behaves like the word OR. A “none” rule is true only when no condition inside it is true, which behaves like “NOT any of these”.
| Rule type | Behaves like | True when | Plain example |
|---|---|---|---|
| All | AND | Every condition inside is true | Premium plan and country is India |
| Any | OR | At least one condition is true | Platform is iOS or platform is Android |
| None | NOT ANY | No condition inside is true | Not a test account and not a staff account |
How rule groups combine
A segment can hold several top-level rules. They combine like the word AND: the user belongs to the segment only when every top-level rule is true. Inside a rule, conditions combine according to the rule’s type. Rules can also be nested, so that a rule contains other rules. Nesting is what lets you express statements such as “on the paid plan, and either in India or in a country with a local partner, and not a test account”.
flowchart LR
U["User with traits"] --> T1{"Rule 1 ALL: plan is pro and orders over 3"}
T1 -- "false" --> OUT1["Not in segment"]
T1 -- "true" --> T2{"Rule 2 ANY: country is IN or country is NP"}
T2 -- "false" --> OUT1
T2 -- "true" --> T3{"Rule 3 NONE: is_test is true or is_staff is true"}
T3 -- "false" --> OUT1
T3 -- "true" --> IN1["In the segment"]
The figure follows one user through three top-level rules. First, the user must be on the pro plan and have placed more than three orders. If either is false, the journey ends and the user is outside the segment. Second, the user must be in India or Nepal, where only one of the two conditions is needed. Third, the user must not be a test account or a staff account, which is what a “none” rule checks. Only a user who passes every checkpoint reaches the segment. Reading the rules as a series of gates is a reliable way to predict the result.
Airport security has several gates in a row. A passenger needs a valid ticket and a passport at the first gate. At the second gate, any one approved form of ID will do. At the third gate, nothing on a prohibited list may be found in the bag. Pass all three and you board. A segment’s top-level rules are those gates, and each gate has its own style of checking.
Before building a segment in the dashboard, write it as a plain sentence on paper. Mark every “and”, “or” and “not”. Each “or” tells you where an “any” rule belongs, and each “not” tells you where a “none” rule belongs. This prevents most logic mistakes.
5Comparison Operators: Equals, Not Equals and Ordering
The first family of operators asks whether a trait matches, differs from or ranks above or below a value.
Equals and not equals
“Equals” is the simplest condition: it is true when the trait’s value is the same as the one you typed. It suits fixed vocabularies such as plan names, country codes and roles. “Not equals” is its opposite, true when the trait’s value differs from the one you typed. Both are strict. A trait of “Premium” does not equal “premium” if the system treats letter case as significant, which is common, so agree on one style and check how your version behaves.
Greater than and less than
The ordering operators compare numbers. “Greater than” is true when the trait is above the value, and “less than” when it is below. Flagsmith also offers inclusive forms, “greater than or equal” and “less than or equal”, which are true when the trait equals the value as well. The difference matters at the edge. A rule that says “orders greater than 5” excludes someone with exactly five orders, while “greater than or equal to 5” includes them.
| Operator | Plain meaning | Example condition | Matches when trait is |
|---|---|---|---|
| Equals | Exactly the same | plan equals pro | pro |
| Not equals | Anything else | plan not equals free | pro, enterprise, or any other set value |
| Greater than | Strictly above | orders greater than 5 | 6, 7, 8 and so on |
| Greater than or equal | At or above | orders at least 5 | 5, 6, 7 and so on |
| Less than | Strictly below | age less than 18 | 17, 16, 15 and so on |
| Less than or equal | At or below | age at most 18 | 18, 17, 16 and so on |
A roller coaster has a sign: riders must be at least 120 centimetres tall. “At least” includes the child who is exactly 120. If the sign said “taller than 120”, that same child would be turned away. The words are close, the outcomes differ, and both are easy to confuse when written quickly. Operators in Flagsmith are the same: the boundary value is where mistakes hide.
Semantic versions
App versions such as 4.2.0 and 4.10.0 are not ordinary numbers or ordinary text. As text, “4.10.0” sorts before “4.2.0” because the character “1” comes before “2”. As a decimal number, it is not even a valid number. Flagsmith therefore supports comparing semantic versions, where each dot-separated part is compared as a number in turn. When you want to say “app version at least 4.2.0”, the condition value must be marked as a semantic version, which the dashboard offers as an option in recent versions. Check your documentation for the exact way it is marked in your version, and always test with versions on both sides of the boundary.
Real-world example: hiding features from old app versions
Mobile companies such as Spotify and Uber, which have publicly described shipping features across many app versions at once, face the problem that an old installed app cannot display a new screen. Targeting on app version lets the server withhold the feature from old versions and offer it only to those able to show it. The segment rule is short, but the harm of getting it wrong, an unusable screen, is large.
Never compare version numbers as plain text. A rule that says “version greater than 4.2” in text terms treats 4.10 as lower than 4.2. Always use the version-aware comparison, and test with a ten, a nine and a single-digit version to prove it works.
6Text and Presence Operators
The second family of operators looks inside text, checks lists, and asks whether a trait exists at all.
Contains and does not contain
“Contains” is true when the trait’s text includes the given piece anywhere inside it. A segment for a partner company’s staff might say “email contains partner.example.com”. “Does not contain” is the reverse. These operators are flexible, but they are also easy to over-match. The text “pro” is contained in “professional” and in “improve”, so a short fragment can capture people you never intended. Prefer longer, more distinctive fragments, or use an exact equals when the vocabulary is fixed.
The “in” operator
“In” checks whether the trait’s value is one of a list of values, separated by commas. It is shorter and clearer than a long “any” rule full of separate equals conditions. For example, “country in IN, NP, BD” means the country is India, Nepal or Bangladesh. Because it matches whole values, not fragments, it avoids the over-matching trouble of “contains”.
Is set and is not set
Sometimes the question is not what a trait is, but whether you know it at all. “Is set” is true when the identity has a value for the trait. “Is not set” is true when it does not. These are the correct way to handle missing information. For example, you might give a feature to everyone for whom a “preferred_language” is not set, using a default. Do not try to test emptiness with a not-equals condition, because the way missing traits are treated in other operators may surprise you, as later chapters explain.
Regular expressions
A regular expression, often shortened to regex, is a compact pattern language for describing text. It can express things that “contains” cannot, such as “starts with a letter followed by exactly four digits” or “ends with either .edu or .ac.uk”. Flagsmith’s regex operator is true when the trait’s text matches the pattern you supply. Regex is powerful, and it is also the easiest operator to get subtly wrong. Patterns that look right can match more or less than you expect, and the exact flavour of pattern language depends on the engine evaluating it, so keep them short and test them on many sample values.
| Operator | Plain meaning | Example | Best used for |
|---|---|---|---|
| Contains | Text includes this piece | email contains partner.example.com | Domains and tags |
| Not contains | Text lacks this piece | email not contains test | Excluding obvious test accounts |
| In | Value is on this list | country in IN, NP, BD | Short fixed lists |
| Is set | The trait exists | company is set | Detecting known data |
| Is not set | The trait is missing | company is not set | Handling unknown data |
| Regex | Text fits a pattern | user code fits a pattern | Structured identifiers |
Searching a library is similar. “Contains” is like searching for any book with the word “river” anywhere in the title, which finds rivers, riverboats and Riverdale. “In” is like asking for a specific list of titles. “Is set” is like asking whether the book has an author on its record at all. A regular expression is like a librarian’s advanced search form, powerful but needing careful instructions.
Over-matching is the classic text mistake. A condition such as “email contains admin” will also match “radmin” and “administrator-fan@example.com”. When a wrong match could expose a feature to the wrong people, prefer exact operators and complete values.
For any regex condition, keep a short list of three values that must match and three that must not. Test all six after every edit to the pattern. Six quick checks catch most pattern mistakes.
7Special Operators and Built-in Properties
Some conditions do not look at a trait you sent. They look at the identity itself, at the environment, or at a number made from the identity.
Percentage split
The percentage split operator is true for a chosen share of users, such as ten percent. It does not look at any trait. Instead, Flagsmith turns the user’s identifier, mixed with something unique to the segment, into a number between zero and one hundred, and the condition is true when that number falls under your chosen percentage. Because the calculation is repeatable, the same user always lands on the same side. Chapter 10 explains why this stability is so valuable.
Modulo
The modulo operator divides a numeric trait by a number you choose and checks the remainder. It is useful for splitting people into repeating groups by a number they already have, such as a customer number. If you divide by two and look for a remainder of zero, you select every even number. If you divide by ten and look for a remainder of three, you select one tenth of customers, those whose number ends in three. It is an old, dependable trick for creating stable test groups from numeric identifiers, though the percentage split is usually easier.
Built-in properties
Besides traits you send, Flagsmith can expose a few built-in properties to rules. In recent versions, these include the identity’s own identifier and the name of the environment being asked about. A rule on the identifier lets you target a known list of users without inventing a trait for them. A rule on the environment name lets one segment behave differently in Staging and Production, though this should be used sparingly, because it hides environment differences inside the rule itself. Check your version’s documentation for the exact names of these properties and whether they are available to you.
| Operator or property | What it looks at | Typical use | Caution |
|---|---|---|---|
| Percentage split | A repeatable number made from the identity | Gradual rollouts | Same user always in the same position |
| Modulo | Remainder of a numeric trait | Stable test groups | Needs a numeric trait |
| Identity identifier | The user’s unique ID | Targeting a named list | Lists grow stale quickly |
| Environment name | Which environment is asking | Rare special cases | Hides differences inside the rule |
A teacher who wants to split a class into groups does not ask each pupil to describe themselves. She uses something already on the register, such as the roll number: even numbers form one group, odd numbers the other. The split needs no questions, and it is the same every day. A percentage split and a modulo condition are digital versions of the register trick.
If you want to give a feature to a small, named list of people, such as your testers, a segment based on identity identifier works. If the list will grow past a dozen or so people, create a trait such as tester instead and send it from your own system, where the list is already maintained.
8Combining Conditions: AND, OR and NOT Without Mistakes
Individual conditions are easy. The errors creep in when you combine them, so a little logic goes a long way.
The three connectors
Every audience description is built from three connecting ideas. AND narrows the audience, because a person must satisfy both sides. OR widens the audience, because a person need satisfy only one side. NOT flips an answer, turning a match into a non-match and the reverse. In Flagsmith, AND and OR are expressed by the “all” and “any” rule types, while NOT is expressed by the “none” rule type, and by operators with a negative meaning such as “not equals”.
Narrows
“Premium and in India” is smaller than either “premium” or “in India” alone. Each added AND shrinks the group.
Widens
“iOS or Android” is larger than either alone. Each added OR enlarges the group.
Flips
“Not a test account” includes everyone except the test accounts. The size depends on how many are excluded.
The two classic traps
The first trap is mixing up the meaning of “none” with “not all”. A “none” rule is true only when every condition inside it is false. If you write “none of: is_test is true, is_staff is true”, then a person who is staff is excluded even though they are not a test account. People who intended to exclude only those who are both test and staff have written the wrong rule. Say aloud what you mean: “exclude anyone who is a test account, and also exclude anyone who is staff” is a “none” rule, while “exclude people who are both” needs a different structure.
The second trap is a negative that does not behave as hoped. Suppose you want everyone who is not on the free plan. A “plan not equals free” condition seems perfect, but if some users have no plan trait at all, the way the missing value is handled may leave them out. The safer wording is often a positive list, such as “plan in pro, team, enterprise”, because it says exactly who should be included instead of describing everyone else.
A restaurant sign says “No shirts, no shoes, no service”. A customer wearing a shirt but no shoes is refused. The word “no” applies to each item separately, so being missing either one is enough to fail. People often read it as “no shirt and shoes together”, which is a different rule altogether. Segment logic has the same pitfall in plain language: the words feel obvious until two readers disagree on what they meant.
A reliable method
Write the audience as one sentence
For example: “Pro customers in India or Nepal who are not test accounts.”
Mark every connector
Circle each and, or and not. Here: and between plan and country, or between the two countries, and not for the test accounts.
Give each group its own rule
One “all” rule for the plan, one “any” rule for the two countries and one “none” rule for the test flag.
Prefer positive wording
Where possible, say who is in, not who is out, to avoid problems with missing data.
Test the edges
Try people who satisfy all but one condition. A correct segment rejects each of them for exactly the right reason.
An “any” rule with a single condition inside it behaves exactly like that condition. An “any” rule with no useful conditions can behave in surprising ways. Do not leave empty or half-built rules in a saved segment, and review the final rule list after every edit.
9Six Worked Examples
Reading about operators is useful. Seeing complete segments for realistic needs is better.
Each example below describes an audience in words, then shows how its rules are put together. They are built for an imaginary online shop called BrightCart, which sends traits named plan, country, orders, app_version, platform, email and is_test.
Example 1: Internal staff
Goal: Show new features to employees first. Rules: One “any” rule with a single condition, email contains the company’s own mail domain. Why it works: staff always use company email addresses. Improve it: a trait such as is_staff sent from your own user database is safer than a text match, because it cannot be faked by someone typing a similar-looking address.
Example 2: Premium customers in selected countries
Goal: Roll out a feature where you have licences. Rules: Rule 1 is an “all” rule with plan equals premium. Rule 2 is an “any” rule with country in IN, NP, BD. Why it works: two top-level rules combine like AND, so a user needs both. Watch: make sure country codes are sent in one consistent style, such as two capital letters.
Example 3: Mobile users on a recent app
Goal: Offer a screen only to apps that can display it. Rules: Rule 1 is an “any” rule with platform in ios, android. Rule 2 is an “all” rule with app_version at least 4.2.0, marked as a version comparison. Why it works: the version check uses semantic ordering, so 4.10.0 correctly beats 4.2.0.
Example 4: Loyal customers
Goal: Reward people who buy often. Rules: One “all” rule with orders at least 10 and plan not equals free. Why it works: both parts must be true. Watch: if some accounts have no plan trait, use a positive list of paid plans.
Example 5: A ten percent trial group, excluding test accounts
Goal: Try a feature on a small, random slice of real customers. Rules: Rule 1 is an “all” rule with a percentage split of ten. Rule 2 is a “none” rule with is_test equals true. Why it works: the split picks a stable ten percent, and the “none” rule removes test accounts. Improve it: keep this segment generic, and raise the percentage over time as confidence grows.
Example 6: Everyone except a small blocked group
Goal: Give a feature to all customers, but withhold it from a handful of accounts under review. Rules: One “none” rule with account_status equals under_review. Why it works: the segment includes everybody not in the blocked state. Watch: users with no account_status trait should be tested explicitly, to confirm they behave as intended.
| Example | Rule types used | Operators used | Main risk |
|---|---|---|---|
| Internal staff | Any | Contains | Look-alike addresses |
| Premium in selected countries | All and any | Equals and in | Inconsistent country codes |
| Recent mobile apps | Any and all | In and version comparison | Comparing versions as text |
| Loyal customers | All | At least and not equals | Missing plan values |
| Ten percent trial | All and none | Percentage split and equals | Forgetting to exclude test accounts |
| Everyone except blocked | None | Equals | Missing status values |
Save a short description with every segment explaining who it is for, who asked for it and which traits it needs. When a trait changes in the application, you will know at once which segments to check.
10Percentage Splits in Depth
A percentage rollout looks trivial, but a surprising amount of good engineering sits behind the phrase “ten percent of users”.
Why not simply flip a coin?
Imagine deciding on every page load, with a random number, whether to show the feature to ten percent of people. A single visitor would see the new design on one page, the old design on the next and the new design again after a refresh. The experience would flicker, bug reports would be impossible to reproduce and any measurement of the feature’s effect would be meaningless. What you want is for each person to be assigned once, and to stay assigned.
How stable assignment works
Flagsmith takes the user’s identifier, mixes it with something specific to the segment, and passes the result through a mathematical scrambling function called a hash. The output looks random but is completely repeatable: the same input always produces the same number. That number, scaled to the range zero to one hundred, is compared with your chosen percentage. Because the same person always produces the same number, they always get the same answer, on every device, as long as their identifier does not change.
Think of a school sorting pupils into four colour houses by the first letter of their birth month. The result looks arbitrary, yet each pupil is always in the same house, every day and in every class, and nobody has to remember anything. A hash is a far better scrambler than a birth month, but the idea is the same: a repeatable rule that spreads people evenly.
Widening a rollout keeps early users
Because assignment depends only on the user’s position in the scrambled order, raising the percentage from ten to twenty-five keeps everyone who was already in and adds more. Nobody who had the feature loses it as you widen. This is why you can start small and expand with confidence, knowing that early users keep a consistent experience.
Different segments pick different people
Since the calculation mixes in something unique to each segment, two segments with the same ten percent do not select the same ten percent of users. This is useful. Two unrelated experiments will not accidentally land on exactly the same unlucky group. If you need two features to reach exactly the same people, build one segment and use it on both flags.
Common mistakes with percentages
Changing the identifier
If your app uses an anonymous ID before login and a different ID after login, the same human may switch sides. Use one stable ID.
Expecting exact numbers
Ten percent is a statistical target. Over a small number of users, the actual share can drift noticeably above or below it.
Rebuilding the segment
Deleting a segment and creating a new one with the same name produces a new scramble, reshuffling everyone.
Mixing in other rules carelessly
Combining a split with other conditions means the percentage applies only to people who meet the other conditions.
Real-world example: Google and live experiments
Google has described in public research how it exposes changes to small, consistently assigned slices of traffic before wider release, measuring effects as it goes. Stable assignment, so that the same user stays in the same group, is what makes such measurements trustworthy.
Agree on a single, permanent identifier for each user across web, mobile and backend services. A stable identity is the foundation of every percentage split.
11Segment Overrides and the Order of Precedence
A segment on its own changes nothing. It becomes meaningful when a flag uses it, and when several segments compete, order decides the winner.
What is a segment override?
A segment override is an instruction attached to a flag, in one environment, saying “for members of this segment, behave like this”. The override can set its own enabled position and, for remote configuration flags, its own value. Members of the segment receive the override’s answer. Everyone else keeps receiving the flag’s default answer for the environment.
When a user belongs to several segments
One person can match many segments at once: a premium customer, in India, on iOS, in the staff group. If the flag has overrides for several of those segments, Flagsmith needs a tie-breaker. It uses the order of the override list. The segments are checked from the top, and the first one the user belongs to supplies the answer. Segments lower down are ignored for that flag. You control the order by dragging overrides up and down in the flag’s screen.
flowchart TD
A["Flag requested for an identity"] --> B{"Identity override exists?"}
B -- "Yes" --> R1["Use the identity override"]
B -- "No" --> C{"In first segment override?"}
C -- "Yes" --> R2["Use the first matching segment override"]
C -- "No" --> D{"In next segment override?"}
D -- "Yes" --> R3["Use that override"]
D -- "No" --> E["Use the environment default value"]
Follow the arrows from the top. When a flag is requested for an identity, Flagsmith first checks whether that specific person has a personal override. If they do, that is the answer, and nothing else is considered. Otherwise it walks down the list of segment overrides in priority order and stops at the first segment the person belongs to. If the person matches none, the environment’s default value is returned. The figure shows only two segment steps, but the list can be longer.
A hotel decides which welcome gift to place in a room. The first rule on the list is “personal request noted in the booking”, which beats everything. Next is “loyalty member”, then “booked through partner site”, then “ordinary guest”. A guest who is both a loyalty member and a partner booking gets the loyalty gift, because that rule comes first. If the hotel swapped the order of the two rules, that same guest would get the partner gift.
Ordering advice
Narrow and special first
Put small, deliberate audiences such as staff and testers at the top, so that their experience is never overridden by broader groups.
Percentage rollouts in the middle
Gradual audiences sit below the narrow ones and above the very broad catch-all groups.
Broad groups last
Wide segments such as “all paying customers” go near the bottom, where they only affect people who matched nothing narrower.
Explicit exclusions near the top
If a group must never see the feature, an override turning it off for that group should come before the audiences that turn it on.
Real-world example: staff first, then the world
GitHub engineers have publicly described releasing changes to employees before the general public. In override terms, that is a staff segment at the top of the priority list with the feature on, followed by wider percentage segments below it. The order of the list is part of the release plan, not an afterthought.
Reordering overrides can change what real users see the moment you save. Treat a priority change in Production with the same care as turning a flag on, and record why it was made.
12The Evaluation Journey from Request to Answer
Watching one request travel from your application to Flagsmith and back makes every earlier chapter click into place.
sequenceDiagram
participant APP as Application
participant SDK as Flagsmith SDK
participant FS as Flagsmith
participant ENG as Rule Engine
APP->>SDK: Identify user with traits
SDK->>FS: Request flags for this identity
FS->>ENG: Evaluate segments for the identity
ENG->>ENG: Check each rule group and condition
ENG-->>FS: Return matching segments
FS->>FS: Apply identity and segment overrides in order
FS-->>SDK: Return flag values for this user
SDK-->>APP: Flags ready to use
The application starts by telling the SDK who the user is and what is known about them. The SDK sends this to Flagsmith, asking for the flags that apply. Flagsmith hands the identity and traits to its rule engine, which walks through every segment relevant to the requested flags, checking each rule group and each condition. The engine reports which segments the user belongs to. Flagsmith then applies the overrides in priority order, as Chapter 11 described, and returns the final flag values. The SDK passes them to the application. This whole journey usually takes a fraction of a second.
Evaluation on your own server
For high-traffic backends, Flagsmith’s server-side SDKs offer a local evaluation mode. Instead of asking Flagsmith each time, the SDK downloads the environment’s complete rule set, including segments and overrides, and runs the same rule engine inside your own service. Answers become extremely fast, and the application continues to work if the network to Flagsmith is briefly interrupted. The trade-off is a short delay before rule changes reach your servers, as the SDK refreshes on a timer. Check your SDK documentation for the refresh interval and any differences in supported features.
Calling a help desk each time you need an answer is like the direct request: always current, but the line can get busy. Keeping a printed copy of the rulebook at your own desk is like local evaluation: instant and robust, but you must replace the printout now and then. Both give the same answers for the same rules. They differ in when you learn that a rule has changed.
What the engine needs from you
A stable identifier
The unique key for the user, used for personal overrides and percentage splits.
Correct traits
Names spelled exactly as the rules expect, with values of the right type.
The right environment key
Segments are shared across the project, but overrides are read from the environment your key belongs to.
Fresh enough rules
With local evaluation, rules are as recent as the last refresh, so allow for that delay when testing.
When something looks wrong, ask three questions in order. What identifier was sent? Which traits came with it? Which environment key was used? More than half of all “the segment is broken” reports end at one of these three answers.
13Edge Cases: Missing, Mismatched and Messy Data
Real data is never as tidy as examples. These are the situations that produce the strangest segment behaviour.
The trait that is not there
Not every user has every trait. A brand-new visitor may have no plan, no country and no order history. For most operators, a condition on a missing trait simply does not match, because there is nothing to compare. This is usually what you want. The surprising cases come from negative operators. A condition such as “plan not equals free” might not match a user with no plan at all, since there is no value to be different from. Behaviour in edge cases can differ between versions and operators, so always test missing traits explicitly instead of assuming.
Wrong type, wrong result
If a number is sent as text, an ordering condition may not behave as expected. The text “9” is considered greater than the text “10” in dictionary order, because “9” comes after “1”. Sending the count of orders as a real number avoids the problem. Similarly, sending the word “true” as text where a true-or-false value was expected can lead to a condition silently failing to match. Agree on types in your application, and keep them consistent across web, mobile and backend code.
Capital letters, spaces and spelling
Strings usually need to match exactly, including letter case and any hidden spaces at the start or end. A plan sent as “Pro ” with a trailing space is not the same as “Pro”, and neither is “pro”. These mistakes are invisible on the screen and very frustrating to find. Clean values in your application before sending them, preferably to a lowercase, trimmed form, and document the permitted vocabulary.
| Situation | Likely result | Safer practice |
|---|---|---|
| Trait missing, positive operator | Condition does not match | Expected, but test it once |
| Trait missing, negative operator | Behaviour may surprise you | Use a positive list or “is not set” |
| Number sent as text | Ordering compares as text | Send real numbers |
| Different letter case | May not match | Normalise values before sending |
| Trailing or leading spaces | Does not match | Trim values before sending |
| Anonymous user, no identity | Segments are not evaluated | Identify the user, or accept defaults |
| Identifier changes at login | User may jump between segments | Use one stable ID |
An airport check-in desk can only verify the details on the passport. A passenger who gives the name “Jon” when the ticket says “Jonathan” is turned away by the computer, even though a human would see they are the same person. Rules are as strict as that computer, and they give a clear answer only when the data arrives clean.
Real-world example: the tidy-data habit
Large online companies such as Amazon and Netflix have long emphasised that decisions at scale depend on consistent, well-defined data. A feature flag system inherits that principle: the audience rule is exactly as reliable as the information fed to it. Teams that agree on a small shared vocabulary of traits avoid most of the strange behaviour described above.
A rule that looks perfect in the dashboard can still fail in production if the application sends the trait under a slightly different name. Compare the exact trait names in your code with the exact names in your conditions whenever a segment seems to match nobody.
14Testing Segments Before Real Users Depend on Them
A segment is a small program written in clicks. Like any program, it deserves tests, and the tests are cheap.
Why test at all?
A wrong segment is a quiet failure. Nothing crashes. A feature simply reaches too many people, too few people or the wrong people, and the mistake can stay hidden for weeks. The cost is not a technical error message but a confused customer, a leaked feature or an experiment whose results cannot be trusted. A few minutes of deliberate testing before a segment goes live is the best value in the whole process.
The test identity matrix
The most reliable technique is to create a small set of test identities, each designed to prove one thing. For every segment, include at least one person who should be inside, and several who should be outside for different reasons: one failing each condition, one with a missing trait and one sitting exactly on a boundary value. Then check, for each of them, what the flag returns.
| Test identity | Traits | Expected result | What it proves |
|---|---|---|---|
| Typical member | plan pro, country IN, orders 12 | In the segment | The main path works |
| Wrong plan | plan free, country IN, orders 12 | Outside | The plan condition is enforced |
| Wrong country | plan pro, country US, orders 12 | Outside | The country condition is enforced |
| On the boundary | plan pro, country IN, orders 5 | Depends on the operator | “Greater than” versus “at least” |
| Missing trait | plan pro, no country | Outside | Missing data is handled |
| Wrong case | plan Pro, country IN | Per your rule | Letter case behaviour |
| Excluded group | plan pro, country IN, is_test true | Outside | The exclusion rule works |
A lock-maker testing a new lock does not only check that the right key opens it. She also tries a key that is slightly too short, one that is slightly too long, one with a worn tooth and one from another lock. A lock that opens for the right key but also opens for the wrong ones is worse than useless. Testing segments is the same: the wrong visitors matter as much as the right ones.
Using the dashboard to help
Flagsmith’s dashboard can show which stored identities currently match a segment, when traits are saved against identities. This is a helpful sanity check: the list should look like the audience you meant. It cannot replace tests that include missing and edge-case data, because those identities may not exist yet. You can also create identities by hand in a non-production environment, give them chosen traits and see the flag values they would receive.
Automated checks
Keep test identities permanent
Give them clear names and keep them in your test environment, so every future edit can be checked against the same people.
Write a small script or test suite
For each test identity, ask the flag service for the flags and compare them with the expected values. A failing check names the segment that drifted.
Run it before and after each change
Run the checks before editing a segment to prove they pass, and again afterwards to prove nothing else broke.
Run it after promotion
After any Production change, run a smaller version of the same checks against Production test identities.
Keep test accounts out of real analytics and out of percentage splits. A trait such as is_test, combined with a “none” rule in your production segments, stops internal testing from polluting your numbers.
15Segments Across Environments
Segments are shared across a project, but their effects are decided separately in each environment. This split is the source of many puzzling moments.
Define once, override separately
When you create a segment, it exists for the whole project. The same name and the same rules are available in Development, Staging and Production. What differs is whether a given flag has an override for the segment in each environment, and what that override says. A flag might give the staff segment the new behaviour in Staging, but have no override for it yet in Production.
One edit, many environments
Because the rules are shared, editing a segment changes it everywhere at once. Add a condition in Development while experimenting, and the same condition is now in force in Production, for every flag that uses the segment. This is convenient and dangerous in equal measure. Experiments with new rules belong in a copy of the segment, or in a feature-specific segment, until you are sure. Never use the shared, production-facing version as a scratchpad.
flowchart LR
SEG["Segment: Premium India, defined once"] --> DEV["Development: override on, value practice"]
SEG --> STG["Staging: override on, value practice"]
SEG --> PRD["Production: override on at 10 percent, value live"]
The figure shows a single segment feeding three environments. The audience definition is identical in all three, because it comes from the one segment. The consequences differ: Production uses the real value and a small percentage, while the lower environments use practice values. When you promote a flag from Staging to Production, you recreate the override in Production, but you do not need to recreate the segment.
A company-wide definition of “senior employee”, say more than ten years’ service, is written once by the head office. Each branch then decides what seniors receive: one branch gives extra holiday, another a parking space. If head office changes the definition to eight years, every branch’s seniors change at once, even though each branch still decides its own benefit. Segments behave this way.
Safe habits
Treat segment edits as Production edits
Because the change is shared, give it the same review as a Production flag change.
Duplicate before experimenting
Copy the segment, work on the copy and swap it in only when proven.
Check where it is used
Before editing, look at which flags use the segment, so you know the reach of the change.
Keep identities separate
Traits sent from a Staging app should describe test users, so they never confuse Production rules.
Real-world example: shared definitions, local decisions
Large organisations such as Etsy have publicly described separating shared definitions of audiences from the individual features that use them, so product teams can reuse well-understood groups. The benefit is the same one a shared segment provides: one place to define a group, many places to use it.
If your project uses change approvals, remember that editing a shared segment may not pass through the same approval flow as a flag change in your version. Confirm how your plan treats segment edits, and add a team habit of review where the tool does not.
16Segment Design Patterns
Most useful segments fall into a handful of familiar shapes. Recognising them speeds up design and makes segments easier for others to read.
Internal staff
Gives employees early access. Usually built from a trusted trait, and placed at the top of priority lists.
Beta programme
A named group who opted in. Built from a trait that records consent, so it is both fair and traceable.
Plan or entitlement
Groups customers by the plan they pay for. Long-lived, tied to product and pricing decisions.
Geography
Targets countries or regions for legal, language or partner reasons. Needs a consistent code vocabulary.
Platform and version
Matches operating system or app version, so that features reach only apps able to show them.
Cohort by date
Groups users by when they joined, such as everyone who signed up this quarter, for fair experiments.
Gradual rollout
A percentage split with exclusions, widened step by step over days or weeks.
Safety exclusion
A group deliberately kept out, such as accounts under review or customers in a regulated state.
Naming that explains itself
Names are the cheapest documentation a segment has. Describe the group in business words, not in rule-language. “Premium customers in India” reads well in an override list. “plan eq premium and country eq IN” explains how the group is built, which anyone can see by opening it, but not why it exists. Keep a single style, and avoid dates, people’s names and temporary words such as “new” or “test2” which are meaningless a month later.
| Weak name | Better name | Why better |
|---|---|---|
| segment1 | internal-staff | Says who is in the group |
| johns-test-group | beta-checkout-testers | Names the purpose, not a person |
| oct-promo-users | promo-eligible-customers | Does not expire with the calendar |
| india-premium-ios-new | premium-india | Short, with other conditions inside the rules |
Small, composable segments
A common design question is whether to build one large segment with many conditions or several small segments. Small segments are easier to understand and reuse. Large ones are easier to read in one place but harder to change safely. A good habit is to keep each segment to one clear idea, such as “premium customers”, and to combine ideas at the flag level through ordered overrides rather than stuffing every possible combination into a single segment.
A kitchen with many small, well-labelled containers is easier to cook in than one giant jar of mixed spices. You can combine exactly what you need, and replacing one container does not spoil the others. Segments built around one idea work the same way: reusable, clear and easy to swap.
For every segment, write a one-line description naming its owner and purpose. When the owner leaves the team, a quick search for orphaned segments tells you exactly where cleanup is needed.
17Anti-patterns to Avoid
An anti-pattern is a habit that looks reasonable and causes trouble later. These five are the most common in targeting rules.
What it looks like
One enormous segment with a dozen rule groups, built to cover every audience a product team might ever want.
Why it hurts
Nobody can read it, nobody dares edit it and one change can reshape the audience of many unrelated flags.
Do this instead
Create several small segments, each with one clear idea, and combine them with ordered overrides on each flag.
What it looks like
A segment that unlocks paid content based on a trait sent by a browser or phone app, such as plan equals premium.
Why it hurts
Anyone able to change the value in their own app can give themselves premium features. Client-side traits can be edited by the person holding the device.
Do this instead
Enforce access on your server using trusted data. Use segments for presentation and rollout, not for protection.
What it looks like
A segment built entirely from “not equals” or “does not contain” conditions to mean “everyone except these”.
Why it hurts
Users with missing traits may fall outside the segment, so the audience is smaller than intended, and the problem only appears with real data.
Do this instead
Use positive lists where possible, or combine “is set” checks with exclusions, and test with missing values.
What it looks like
Hundreds of user identifiers pasted into a single condition to give a feature to a named group.
Why it hurts
The list is stale the day after it is written, hard to review, easy to break by a stray comma and slow to evaluate.
Do this instead
Send a trait such as beta_tester from the system where the list is truly maintained, and write one simple condition on it.
What it looks like
Dozens of segments from old experiments, each with an unclear name, none with an owner, some used by no flag at all.
Why it hurts
New team members cannot tell what is safe to change, and rules based on traits that no longer exist silently match nobody.
Do this instead
Give each segment an owner and purpose, and review the list on a regular schedule, removing what is unused.
Real-world example: complexity as a cost
Engineering writers at companies such as Facebook and Google have often warned that conditional behaviour, left unmanaged, becomes one of the hardest parts of a system to reason about. Targeting rules are conditional behaviour about people. Keeping them small, named and owned is the discipline that stops them from becoming a maze.
18Performance and Scale
A single segment check costs almost nothing. Millions of checks, each against dozens of segments, are worth thinking about.
What makes evaluation heavier?
Evaluating a segment means walking its rules and testing each condition against the user’s traits. A segment with three conditions takes negligible time. A segment with fifty conditions, several regular expressions and long lists of values takes longer, and a flag with twenty overrides multiplies that cost. For one request, the total is still tiny. For a busy service handling thousands of requests each second, small costs add up, and the simplest rules are the cheapest.
Equals, in, is set
Simple exact comparisons are very fast, even over many requests.
Number comparisons
Greater-than and less-than checks on numbers are fast and predictable.
Contains
Searches inside text, so cost grows with the length of the text.
Regular expressions
Complex patterns can be slow, and badly written ones can be very slow on certain inputs.
Habits that keep targeting fast
Send only the traits rules use
Smaller identities travel faster and cost less to store and evaluate.
Prefer exact operators
Use equals and in where the vocabulary is fixed. Reserve regular expressions for the few cases that need them.
Ask for flags once per request
Read the needed flags at the start of handling and reuse the answers, instead of asking repeatedly inside the same request.
Use local evaluation on busy backends
Evaluating inside your own service avoids a network call for every decision.
Retire unused overrides
Every override on a flag is a test to run. Removing dead ones makes every request slightly cheaper.
A concert doorkeeper checking a ticket by looking at its colour is fast. One who must read a long paragraph of small print on every ticket slows the whole queue. Simple rules keep the line moving. If the line gets long, switching to a pre-printed guest list, which is what local evaluation provides, is faster than phoning head office about each person.
Real-world example: decisions close to the traffic
Companies that serve enormous traffic, such as Netflix, have publicly described designs where configuration is cached close to where it is used, so that no central service is asked on every request. Local evaluation of segment rules follows the same principle: the decision is made next to the traffic, using a recent copy of the rules.
Before blaming flags for a slow request, measure. In most systems, flag evaluation is a very small share of the total time. Simplify rules when you have evidence, not on suspicion.
19Privacy, Security and Responsible Targeting
Targeting rules are built from information about people. That information deserves care, whatever the size of your company.
Data minimisation
Data minimisation is the principle of collecting and sending only what is needed for a stated purpose. Every trait you send to a flag service is a piece of personal information in another system. If a segment needs to know whether a customer is in the paid tier, send “paid” or “free”, not their billing history. If it needs a rough region, send a country code, not a home address. Smaller, simpler traits reduce risk, speed up evaluation and make privacy reviews easier.
Traits that should not be sent
Passwords and secrets
No credentials, tokens or keys of any kind belong in a trait.
Sensitive categories
Health, religion, political views and similar details should not drive feature targeting, and may be restricted by law.
Direct contact details
Full email addresses and phone numbers are rarely needed. A domain or a yes-or-no fact usually serves.
Free text from users
Text typed by people is unpredictable and may contain anything, including things you did not mean to collect.
Client-side visibility
When an application running on a user’s own device asks for flags, it can see the answers it receives. Flag values and, in some arrangements, the existence of flags are visible to a determined person inspecting the app. For this reason, never place secrets or private business information in remote values, and never rely on a client-side segment to hide something that is truly confidential. Treat everything a client can read as readable by the user.
A shop assistant who asks for your full life story before selling you a coat is asking for far too much. A good assistant asks only your size. A rule that needs your size should receive your size and nothing else. The more a system knows, the more there is to protect, and the more there is to lose if something goes wrong.
Fairness and responsibility
Targeting decides who gets what, and some decisions have consequences beyond convenience. Offering a discount only to some groups, or withholding a service from others, can raise fairness and legal questions. Before building segments that affect prices, access or opportunity, ask whether the rule could treat people unfairly, and involve your legal and product colleagues where the stakes are real. A simple technical rule can have a serious human effect.
Good practice
- Send the smallest trait that serves the rule
- Use identifiers with no meaning outside your system
- Review traits and segments on a schedule
- Record why each sensitive segment exists
Risky practice
- Sending whole user profiles for convenience
- Using email addresses as identifiers everywhere
- Keeping traits long after their purpose ended
- Targeting prices or access without review
Laws about personal data differ between countries and change over time. Treat this chapter as general good practice and consult your organisation’s privacy or legal team about the rules that apply to you.
20Debugging: Why Isn’t This User in the Segment?
Sooner or later, someone will ask this question. A calm, ordered method answers it quickly almost every time.
flowchart TD
A["User reports wrong flag value"] --> B{"Was the user identified?"}
B -- "No" --> B1["Identify the user and retry"]
B -- "Yes" --> C{"Correct environment key?"}
C -- "No" --> C1["Use the key for the right environment"]
C -- "Yes" --> D{"Traits arrived with right names and types?"}
D -- "No" --> D1["Fix the trait names or types in the app"]
D -- "Yes" --> E{"Each condition true for these traits?"}
E -- "No" --> E1["Correct the condition or the data"]
E -- "Yes" --> F{"Higher priority override wins?"}
F -- "Yes" --> F1["Reorder overrides or adjust the winning one"]
F -- "No" --> G{"Cache or refresh delay?"}
G -- "Yes" --> G1["Wait one refresh period and retest"]
G -- "No" --> H["Check identity overrides and audit log"]
The figure moves from the most common causes to the least. First, confirm the user was identified at all, since anonymous requests skip segments. Second, confirm the key belongs to the environment you think you are looking at. Third, check that the traits arrived with the exact names and types the rules expect. Fourth, work through each condition by hand with the actual trait values. Fifth, look for a higher-priority override that is winning. Sixth, allow for caching delay. Finally, look for a personal identity override and read the audit log for recent changes.
Common symptoms and causes
| Symptom | Likely cause | First check |
|---|---|---|
| Segment matches nobody | Trait name mismatch or missing identification | Compare trait names in code and rules |
| Segment matches everybody | An “any” rule with an always-true condition, or a missing rule | Read the saved rules from the top |
| Some users flicker between values | Unstable identifier | Confirm one ID across login and devices |
| Staff see the old behaviour | A broader override sits above the staff override | Check override priority order |
| Works in Staging, not in Production | Different traits, overrides or keys | Compare environment overrides |
| Recent edit has no effect yet | Cache or local evaluation refresh delay | Wait one refresh period and retest |
| One person always differs | An identity override | Open that identity’s overrides |
A technician fixing a lamp that will not light does not start by replacing the wiring. She checks the plug, the switch, the bulb and the fuse in order, from the simplest and most likely problem to the rarest. The debugging path above follows the same habit: cheap, common checks first, deep investigation last.
Keep one “debug view” in your own tooling that prints the identifier, the traits and the resulting flag values for any user. Being able to see what Flagsmith actually received, not what you believe it received, resolves most questions in minutes.
21Governance and the Segment Lifecycle
Segments are easy to create and easy to forget. A light set of habits keeps the list useful as the product grows.
What is governance?
Governance is simply a set of agreed rules about who may do what, and a way of checking that the rules are followed. For segments, it answers practical questions. Who may create a segment? Who may change one that other people depend on? How do we find segments nobody uses any more? Who decides when a segment is retired? A small team can answer these in a shared document. A large organisation may use roles, reviews and regular audits.
The life of a segment
Proposed
Someone describes the audience in words, names the owner and lists the traits the rules will need.
Built and tested
Rules are created and checked against the test identity matrix before any flag depends on them.
In use
Flags attach overrides to it. Changes are reviewed because they reach every flag that uses the segment.
Reviewed
On a regular schedule the owner confirms the segment still matches its purpose and its traits still exist.
Retired
When no flag uses it and its purpose has ended, the segment is removed, and its name is struck from shared documentation.
Who needs which permission?
| Activity | Typical people | Why limit it |
|---|---|---|
| View segments | Everyone on the project | Transparency helps people reuse existing groups |
| Create new segments | Developers and product owners | Prevents a flood of near-duplicates |
| Edit shared segments | Named owners | An edit reaches every flag that uses it |
| Delete segments | Owners after review | Deleting also removes the overrides that used it |
A library keeps a catalogue. Without a librarian deciding what to add, what to move and what to discard, the shelves fill with duplicates and forgotten pamphlets, and finding the right book becomes a chore. Segments are a catalogue of audiences. A little regular care keeps it a help, not a hindrance.
A simple review routine
Find unused segments
List segments that no flag references, and ask each owner whether they can be removed.
Check trait health
Confirm every trait named in a rule is still sent by the application, under the same name.
Review long-lived segments
Plan, geography and entitlement segments should be rechecked against pricing and legal changes.
Learn and adjust
When a segment caused a surprise, add a test identity that would have caught it.
Tie segment cleanup to flag cleanup. When a release flag is removed, ask which segments it alone was using. Often the answer is “one”, and that segment can leave with it.
22Advantages, Disadvantages and Trade-offs
Segment-based targeting is a powerful idea with real costs. Seeing both sides helps you apply it where it pays.
Advantages
- One definition of an audience, reused on many flags
- Gradual, controlled releases to small groups first
- Changes without redeploying code
- Different behaviour for staff, testers and customers in the same release
- Stable, repeatable assignment for fair experiments
- Clear history of who changed an audience and when
Disadvantages
- Rules depend on the quality of the traits sent by your apps
- Shared edits can affect many flags at once
- Complex rule trees are hard to read and review
- Missing data produces surprising results
- Every extra segment adds a path to test
- Traits are personal data that must be protected
Rules in Flagsmith or logic in your own code?
Sometimes it is not obvious whether a decision belongs in a segment rule or in your own application. A useful guideline is to ask who needs to change it, and how often. If a product manager should be able to widen an audience without a developer, or the answer changes weekly, a segment is a good home. If the decision involves complicated business logic, many data sources or strict security, keep it in code, and send the final yes-or-no result to Flagsmith as a simple trait that segments can use.
| Decision | Better in a segment | Better in your code |
|---|---|---|
| Who sees a new screen first | Yes, it changes often and needs no developer | No |
| Which plan a customer has paid for | No, it is a billing fact | Yes, send the plan as a trait |
| Whether a user may access private data | No | Yes, enforce on the server |
| What percentage of users get a trial | Yes, split rules are built for this | No |
| Eligibility computed from many systems | Only as a final yes-or-no trait | Yes, compute where the data lives |
A company’s dress code can be posted on a noticeboard and updated by the office manager whenever needed. But the question of who is allowed into the vault is not decided by a noticeboard, it is decided by the security system. Both are rules about people. Choosing the right place for each rule is a matter of how often it changes and how much harm a mistake does.
The more logic you put inside segment rules, the more your business behaviour hides inside a dashboard that code reviewers rarely see. Keep rules simple enough that anyone on the team can read them aloud in one breath.
23Best Practices and Common Mistakes
Experienced teams repeat a short list of habits. Newer teams repeat a short list of mistakes. Here are both.
Habits worth building
Agree a trait dictionary
Keep one shared list of every trait name, its type and its allowed values. Treat it as the contract between your applications and your rules.
Write the audience as a sentence first
Describe it in plain words before opening the dashboard, and paste that sentence into the segment’s description.
Keep segments small and named by purpose
One idea per segment, with a name that tells you why it exists.
Test the edges, not only the middle
Include boundary values, missing traits and wrong-case values in your test identities.
Order overrides on purpose
Narrow and special first, wide and general last, with exclusions above inclusions.
Review shared edits like Production edits
A segment change reaches every environment and every flag that uses it.
Retire what you no longer need
Remove unused segments and overrides, so the list reflects what is real today.
Mistakes to catch early
Forgetting to identify the user
The flag returns defaults and the segment appears broken, when it was never evaluated.
Comparing versions as text
Version 4.10 sorts below 4.2 as text. Use the version-aware comparison.
Mixing up “none” and “not all”
A “none” rule excludes anyone matching any listed condition, not only those matching all of them.
Over-matching with “contains”
Short fragments match unintended words. Prefer exact values and lists.
Letting the identifier change
Switching between anonymous and logged-in IDs moves people between percentage groups.
Trusting client traits for security
Traits from the user’s device can be edited. Enforce real access on your server.
Print the “habits” list and the “mistakes” list and pin them next to the team’s release checklist. Short, visible reminders work better than long documents nobody reopens.
24A Complete Worked Scenario
To finish, here is one imaginary feature taken from idea to full release, using everything in this guide.
BrightCart, the imaginary online shop, wants to launch “express reorder”, a button that lets loyal customers repeat a past order in one tap. The team wants staff to try it first, then a beta group who opted in, then ten percent of loyal customers on supported mobile apps, and finally everyone loyal. Nobody who is a test account should ever count in the numbers.
List the traits
The application already sends is_staff, is_test, beta_optin, orders, platform and app_version. All are agreed in the trait dictionary, with fixed types.
Create four small segments
“Internal staff” (is_staff equals true), “Reorder beta” (beta_optin equals true), “Loyal on supported apps” (orders at least 10, platform in ios and android, app_version at least 4.2.0 as a version comparison, and a “none” rule excluding is_test), and “Loyal supported ten percent”, which adds a percentage split of ten to the same conditions.
Test with the identity matrix
Test identities include a staff member, an opted-in tester, a loyal customer on version 4.10.0, one on version 4.1.9, a customer with nine orders, one with exactly ten, a test account and someone with no orders trait. Each is checked against the expected result.
Attach overrides in order
On the express-reorder flag in Staging: staff first, beta second, the ten percent group third. Everyone else gets the default, which is off.
Promote to Production in steps
The same overrides are created in Production, starting with staff only. A day later the beta group is switched on. After a quiet week, the ten percent override is enabled.
Widen with confidence
The ten percent segment is replaced with a fifty percent split, then with the plain “Loyal on supported apps” segment. Because assignment is stable, nobody who had the button loses it as the audience grows.
Clean up
When the feature is permanent, the flag is removed. The two single-purpose segments, “Reorder beta” and the ten percent group, have no flags left and are deleted. “Internal staff” stays, because many flags use it.
Look at the order in step four. Staff sit above beta, and beta above the percentage group, so a staff member who also falls in the ten percent split still receives the staff override. Order is part of the design, not a detail.
What would have gone wrong without the routine?
Suppose the team had compared versions as text. Customers on version 4.10.0 would have been judged older than 4.2.0 and excluded from the feature, while customers on 4.1.9 might have received a button their app could not display. Suppose the team had forgotten the “none” rule on test accounts. The ten percent group would have included automated tests, distorting every number the team measured. Suppose the team had used a percentage split on an identifier that changes at login. Customers would have seen the button appear and vanish as they signed in. Each of these is an ordinary mistake, and each is caught by the habits in this guide.
25Segments with Remote Values and Multivariate Flags
Segments do more than switch features on and off. They can also change the value a flag carries, and even choose between several variants.
Remote values per audience
A Flagsmith flag can carry a value as well as an on or off position. The value might be a banner message, a number such as a maximum upload size, or a small block of settings. A segment override can supply its own value, so different audiences receive different values from the same flag. For example, a flag named upload-limit might carry fifty megabytes for everyone, two hundred for the premium segment and five hundred for the enterprise segment. The application asks one question and each customer receives the answer suited to them.
This is a tidy way to express entitlements and limits. The code reads a single flag and uses whatever number comes back. Pricing and product teams can then adjust each audience’s limit without asking for a new release. The price of this convenience is that the meaning of each value must be agreed in advance, since the application trusts whatever arrives.
A hotel safe has one keypad, but the maximum luggage weight printed on the baggage tag differs by room class. The rule “ask the front desk for your allowance” is the same for everyone, and the answer depends on who you are. A flag with segment-specific values behaves like that desk: one question, an answer tailored to the guest.
Multivariate flags and segments
A multivariate flag has several variants, such as three versions of a button, each with a share of the audience. Segment overrides interact with this in a simple way. A segment override can choose its own enabled state and value, and it takes priority over the environment’s default split for people in that segment. Members of a staff segment might always see variant B so designers can inspect it, while the public sees the default percentage split between variants A, B and C.
Different limits by plan
One flag, one value per plan segment, no code change when pricing shifts.
Tailored messages
A banner text for trial users and a different text for long-time customers.
Pinning a variant for testers
Staff always see a chosen variant so they can review it, while real users are split.
Region-specific settings
Different timeouts or partner choices for different countries from the same flag.
Cautions
Segment values multiply the number of situations you must test. A flag with four segment values has at least five answers, including the default, and each must be right. Keep value formats strict, such as a plain number or a short fixed word, and have your code validate what it receives, falling back to a safe default when a value is missing or unexpected. A mistyped value in a dashboard should never be able to break a page.
| Situation | What the user receives | Why |
|---|---|---|
| Identity has a personal override | The personal value | Identity overrides come first |
| User is in the first matching segment | That segment’s value | Priority order picks the first match |
| User is in no override segment | The environment default, or its variant split | Nothing more specific applies |
| Segment value is empty or malformed | Whatever the code does with it | Validate and fall back in code |
Real-world example: entitlements as configuration
Software companies that sell tiered plans, such as the many developer-tool vendors that offer free, team and enterprise levels, commonly express limits and feature access as configuration read at run time instead of fixed in code. Treating a plan’s allowances as values attached to an audience is the same idea, and it lets pricing change faster than releases.
Values are visible to client apps that ask for them. Never store a secret, a private address or a confidential price in a remote value delivered to a browser or phone, even for a small segment.
26Segments for Rollouts, Experiments and Kill Switches
The same segment tools serve three quite different jobs. Knowing which job you are doing tells you how to build the rules.
Job one: gradual rollouts
A rollout widens an audience over time until everyone has a feature. The audience should grow, never flicker, and be easy to reverse. Segments built around a percentage split fit this job, with staff and beta groups above them. Success is judged by technical health: errors, speed and support messages. The segment rules should be simple, because you will be editing them often while watching the numbers, and a complicated rule makes every edit risky.
Job two: experiments
An experiment compares groups to learn which version of something works better. Here fairness matters more than speed. People must be assigned to groups in a way that is random with respect to anything that might affect the result, and they must stay in their group for the whole test. A percentage split on a stable identifier gives exactly this. Avoid building experiment groups from traits such as “most active customers”, because the groups would differ before the experiment starts, and any difference in results might come from that, not from your change. Do not edit the split while the experiment runs.
Job three: kill switches and exclusions
A kill switch is a flag that lets you turn off a risky or costly behaviour quickly. Segments help by letting you turn it off for only part of the audience, for example a single country where a partner service is failing, instead of for everyone. The rules for a kill-switch segment should be as plain as possible, so that anyone on call can read and apply them without hesitation in the middle of an incident.
| Job | Best segment shape | Key concern | Avoid |
|---|---|---|---|
| Gradual rollout | Staff, then beta, then growing percentage | Safety and reversibility | Complicated rules that are hard to edit quickly |
| Experiment | Stable percentage split with exclusions | Fair, unchanging groups | Groups chosen by behaviour, or edits during the test |
| Kill switch | Plain, broad rules such as a country or platform | Speed and clarity under pressure | Nested rules nobody can read at night |
| Entitlement | Plan-based, long-lived | Accuracy with billing data | Client-supplied traits as the only source |
A hospital uses the same building for emergencies, planned surgery and research trials, but each is run differently. The emergency room is built for speed and clarity, the surgical theatre for careful preparation and the trial for fair, unchanging groups. Segments are one tool serving three very different purposes, and the way you build them should match the purpose.
Keeping the three jobs apart
A common source of confusion is using one segment for two jobs. A segment created for an experiment is later reused as a rollout audience, and then someone edits its percentage mid-test. Give each job its own segment, named for its purpose. When the job ends, retire the segment with it. This small discipline prevents accidental damage to results and keeps every audience’s history clear.
Name it for the feature
For example, “express-reorder-rollout”. It will be deleted when the feature is fully released.
Name it for the question
For example, “checkout-button-colour-test”. It will be frozen while the test runs and archived afterwards.
Name it for the risk
For example, “partner-payments-disabled”. It is simple, visible and rehearsed.
Real-world example: the dark launch
Facebook has publicly described launching Chat in 2008 as a dark launch, in which the code ran for real traffic before users could see the feature, and exposure widened step by step. That is a rollout built from audience rules. The same company has also described careful, separate experiment groups for measuring changes. Treating rollouts and experiments as different jobs, even when the tools overlap, is a habit worth copying.
Before building any segment, write down which of the three jobs it serves. If the honest answer is “two of them”, you probably need two segments.
27Frequently Asked Questions
Short, direct answers to the questions people ask most often about segment rules.
28Summary and Key Takeaways
Segments turn “who should see this?” into a precise, reusable, testable answer. A few clear ideas carry nearly all of the value.
Key Takeaways
- Segments are reusable audiences. Built from rules, which hold conditions, which compare traits with values, they define a group once so many flags can use it.
- Know your connectors. “All” means AND, “any” means OR, “none” means NOT ANY, and several top-level rules combine like AND. Write the audience as a sentence first.
- Data quality decides everything. Identify the user, send traits with consistent names and real types, and test for missing, mixed-case and boundary values.
- Choose operators with care. Prefer exact operators and positive lists, use the version-aware comparison for app versions, and treat regular expressions and “contains” as sharp tools.
- Percentage splits are stable. The same identifier always lands in the same place, so rollouts widen without taking features away, as long as the identifier never changes.
- Order decides overlaps. Identity overrides win, then segment overrides from the top of the list, then the default. Put narrow and special audiences first.
- Test, protect and tidy. Keep permanent test identities, never trust client traits for security, send the minimum personal data, and retire segments nobody uses.