Identity Traits in Flagsmith
How Flagsmith knows who is asking, how small facts about each user, called traits, drive who sees which feature, and how to design, send, protect, test, and debug them, explained from the very first idea to production-grade practice.
Imagine a friendly shopkeeper in a small town. A stranger walks in, and the shopkeeper offers the standard welcome. Then a regular customer arrives, and the shopkeeper says, “Good morning, Mrs. Rao. Your usual tea is ready, and we have the new biscuits you wanted to try.” What changed? The shopkeeper knows who is standing at the counter and a few small facts about her: her name, her favourite tea, her interests. Those facts allow the shop to offer exactly the right thing to exactly the right person.
A feature flag platform without any knowledge of users is like the shopkeeper facing only strangers. It can say “on for everybody” or “off for everybody,” but nothing in between. Flagsmith adds the missing knowledge through two simple ideas: the identity, which says who is asking, and the traits, which are small facts about that identity, such as country, subscription plan, app version, or the date they joined. With these two ideas, a team can say “show the new checkout to premium users in India on app version 5.2 or higher” without writing a line of new code.
This guide teaches identities and traits from the ground up. We will learn what each one is, how to choose a good identifier, how to design a clean set of traits, how they travel from your application to Flagsmith, how they drive segments and feature states, what goes wrong when types or spellings disagree, how to protect people’s privacy, how to test and debug the whole thing, and how to avoid the mistakes that trip up many teams. We assume you know nothing yet. Every new word is explained the first time it appears, and every big idea comes with an everyday comparison.
Flagsmith is a living product. Screen names, plan limits, and some options change between versions. This guide teaches the lasting ideas. When you need an exact option name, trait limit, or price, check the official Flagsmith documentation for the version you use.
1Why a Flag Platform Needs to Know Who Is Asking
Before learning the words identity and trait, let us feel the problem they solve. It is the problem of treating everybody the same when they are not.
The all-or-nothing switch
The simplest feature flag is a switch with two positions: on or off. When a developer flips it, every user of the product gets the same answer at the same moment. That is fine for a tiny product or an emergency. But most real launches are not all-or-nothing. A team wants to show a new feature to its own employees first, then to a few hundred volunteers, then to ten percent of customers, then to a whole country, and only at the end to everyone. Each of these steps needs the platform to answer a different question: is this particular person in the group that should see it?
What the platform needs to answer that question
To decide if a person belongs to a group, the platform needs two things. First, a way to recognise the person from one visit to the next, so that the answer stays steady. That is the identity. Second, some facts about that person that the group rules can look at, such as which country they live in or which plan they pay for. Those are the traits.
Employees first
Release a new feature to staff accounts before anyone else. This needs a trait that tells staff apart from customers.
Paying customers
Unlock a capability only for people on a premium plan. This needs a trait holding the plan name.
Region by region
Launch in one country where the law allows. This needs a trait holding the country.
Old apps stay safe
Show a feature only to app versions that contain the code. This needs a trait holding the app version.
Steady experience
A person who sees the new design today must see it tomorrow. This needs a stable identity.
A fair slice of users
Release to a random ten percent that never changes for each person. This needs a stable identifier to hash.
Think of a hotel that gives each guest a key card. The card identifies the guest, and the hotel’s computer remembers a few facts: room number, membership level, and checkout date. When the guest taps the card at the lift, the lift decides which floors to open. The key card is the identity. The remembered facts are the traits. The lift’s decision is the feature state the guest receives.
A short story
Ananya works at a language-learning app. Her team has built a new lesson player. They want it to appear only for learners who joined in the last thirty days, because new learners have no old habits to disturb. They also want it only on app versions that contain the new player’s code. Without identities and traits, they would need two separate releases, one for each audience. With them, one feature is released once, and two simple rules decide who sees it. The rules read two traits: the day each learner joined, and the version of the app on their phone.
2What Is an Identity in Flagsmith?
An identity is Flagsmith’s record of one user, device, or account, recognised by a unique identifier that your application supplies.
A quick map of Flagsmith
Flagsmith is an open-source platform for feature flags and remote configuration. A feature flag is a switch that turns behaviour on or off without a new release. Remote configuration means storing values, such as numbers or text, that an application reads while it runs. Flagsmith arranges things in a tree: an organisation contains projects, a project contains features and segments, and a project also contains environments, such as Development, Staging, and Production. Each environment has its own keys, its own feature states, and its own identities.
flowchart TB
ORG["Organisation"] --> PRJ["Project: Language App"]
PRJ --> FEAT["Features and segment definitions, shared"]
PRJ --> ENV1["Environment: Development"]
PRJ --> ENV2["Environment: Production"]
ENV2 --> ID1["Identity: learner 1001 with its traits"]
ENV2 --> ID2["Identity: learner 1002 with its traits"]
ENV2 --> ID3["Identity: learner 1003 with its traits"]
ENV1 --> ID4["Identity: test learner A with its traits"]
ENV1 --> ID5["Identity: test learner B with its traits"]
The simplest definition
An identity is a named person, device, or account that your application tells Flagsmith about. It is recognised by an identifier, a unique piece of text such as a user number. When the application asks Flagsmith for feature answers and includes an identifier, Flagsmith treats that request as coming from one identity, and can give an answer tailored to it.
Four facts every beginner should know
Identities live inside an environment
An identity in Production is a different record from an identity with the same identifier in Staging. The two do not share traits or overrides. This keeps test users and real users apart.
The identifier is chosen by you
Flagsmith does not create the identifier. Your application chooses what to send, and Flagsmith treats whatever you send as the name of the identity.
Identities are created on first use
In the usual way of working, you do not need to register an identity in advance. The first time your application asks for flags using a new identifier, Flagsmith creates the identity, and later requests find it again.
Identity is optional
An application can ask for flags without any identity. It then receives the environment’s default answers and no personalised ones. Identities are what unlock segments and personal overrides.
What an identity unlocks
- Segment matching. A segment is a saved group defined by rules over traits. Only identities with traits can match.
- Stable percentage rollouts. The identifier is the input that decides whether a person falls in the ten percent that sees a feature, and keeps them there.
- Multivariate variations. A person is placed in one variation of an experiment, and stays there.
- Personal overrides. A feature state can be given to exactly one identity, such as a beta customer.
- A debugging view. The dashboard can show a particular identity and every feature state it would receive, which is a precious tool when investigating a report.
The identifier you send becomes the name by which Flagsmith knows a person, and it may appear in screens, logs, and exports. Never use an email address, a phone number, or a full name as the identifier unless you have a clear reason and the right to do so. A random internal number is almost always the better choice.
3What Is a Trait?
A trait is one small fact about an identity, stored as a name and a value, that rules can read to decide who belongs in a group.
The simplest definition
A trait is a pair made of a key and a value. The key is the name of the fact, such as “country” or “plan.” The value is the fact itself, such as “India” or “premium.” An identity can carry many traits at once, just as a person can have a country, a plan, an age group, and a favourite language all at the same time.
| Trait key | Example value | Kind of value | What a rule might say |
|---|---|---|---|
| country | IN | Text | Country equals IN |
| plan | premium | Text | Plan equals premium |
| app_version | 5.2.1 | Text, treated as a version | App version is at least 5.2.0 |
| days_since_signup | 12 | Whole number | Days since signup is less than 30 |
| is_staff | true | True or false | Is staff equals true |
| lifetime_spend | 2499.50 | Decimal number | Lifetime spend is more than 2000 |
The kinds of values a trait can hold
Traits can usually hold text, whole numbers, decimal numbers, and true or false values. Choosing the right kind matters, because comparing “is greater than” works on numbers, while “contains” works on text. We will see in a later chapter how mixing the two kinds is a classic source of confusion.
Traits versus feature values
It is easy to confuse traits with feature values, because both are small pieces of information stored with a name. The difference is direction. A trait describes the user and flows from your application to Flagsmith. A feature value describes the behaviour and flows from Flagsmith to your application. Traits are the questions Flagsmith uses. Feature values are the answers it gives.
Trait
A fact about the user. Sent by your application. Used by segment rules. Example: plan equals premium.
Feature value
A setting for behaviour. Stored in Flagsmith. Read by your application. Example: show ten items.
Think of a library membership card. The facts printed on it, such as membership level, home branch, and age group, are traits. The rules at the desk, “members of the gold level can borrow ten books,” are segment rules. The number of books the clerk lets you take is the answer, the feature value. The card describes you, and the rules decide what you are given.
Traits are not secrets and not a database
Traits are meant to be small, useful facts for decision making. They are not a place to copy your whole customer database. Each extra trait is another thing to keep correct, another thing to protect, and another thing that every environment must send. A good team keeps its trait list short and writes down why each one exists.
Before creating a trait, ask: “Which rule will read this?” If you cannot name a segment or a rollout that needs it, do not send it. Traits sent “just in case” become privacy risk and clutter.
4The Anatomy of an Identity Record
Let us open an identity and look inside, to see everything Flagsmith keeps about one person in one environment.
flowchart LR
REC["Identity record in one environment"]
REC --> A["Identifier: the unique name you chose"]
REC --> B["Traits: key and value pairs"]
REC --> C["Identity overrides: special feature states for this person"]
REC --> D["Environment: which place this record belongs to"]
REC --> E["Created and last seen details"]
B --> B1["country: IN"]
B --> B2["plan: premium"]
B --> B3["app_version: 5.2.1"]
C --> C1["new_checkout: enabled"]
Identifier
The unique name you supply, such as a user number. It is what your application sends each time it asks for flags.
Traits
The facts about the person that segment rules can read. They can be added, updated, or removed over time.
Identity overrides
Special feature states for just this person, such as early access to a beta feature. They beat segment overrides and defaults.
Environment link
The identity belongs to exactly one environment. The same identifier in another environment is another record.
Segments are not stored on the identity
Notice what is not inside the record: the list of segments the person belongs to. Segment membership is not stored. It is worked out every time, by checking the identity’s traits against each segment’s rules. This means that when you change a segment’s rules, or when a trait changes, membership updates by itself, with nothing to migrate. It also means that a segment can only ever be as accurate as the traits behind it.
What a feature answer looks like for an identity
When your application asks Flagsmith for the flags of an identity, the reply lists every feature in the environment, with its enabled position and its value, already worked out for that person. The application does not need to know about segments or overrides. It receives the final result, and uses it to choose behaviour.
| Question | Where the answer lives | Changes how often |
|---|---|---|
| Who is this person? | The identifier, sent by your application | Almost never |
| What are they like? | Traits, sent by your application and stored | Sometimes: plan changes, version updates |
| Which groups do they belong to? | Worked out on demand from traits and segment rules | Whenever traits or rules change |
| What should they see? | Worked out on demand from feature states and layers | Whenever states, groups, or traits change |
Think of an airline’s frequent flyer profile. The profile stores your number and your facts: total miles, home airport, and so on. It does not store a permanent label saying “Gold member.” Your tier is worked out from the miles each time it is needed. If the airline changes the rules, everyone’s tier updates without anyone editing a single profile.
5Choosing the Identifier Wisely
The identifier is the single most important choice you make about identities. A good one keeps experiences steady and privacy safe. A poor one causes puzzling behaviour for months.
What makes a good identifier
- Unique. No two people share it.
- Stable. It does not change when the person changes their email, name, or phone.
- Opaque. It reveals nothing about the person. A random number or an internal key is better than an email.
- Available early. Your application knows it at the moment it asks for flags.
- The same in every system. Your website, mobile app, and back-end services should send the same identifier for the same person, so that the person gets the same answers everywhere.
Who or what is the identity?
The identity does not have to be a person. It can be a device, an account, an organisation, or a session. Each choice has consequences.
| Choice | Good for | Watch out for |
|---|---|---|
| User identifier | Consumer products where a person has one account | People who use several accounts or share one |
| Account or company identifier | Business products, where every employee of a customer should see the same thing | Rules about an individual’s role must use traits, not the identity |
| Device identifier | Apps that work before sign-in, or tests tied to hardware | The same person on a phone and a laptop gets two experiences |
| Anonymous generated identifier | Visitors who have not signed in | The identity changes when they sign in, so the experience may change |
| Session identifier | Very short-lived decisions | The experience changes every session, which spoils experiments |
The anonymous visitor problem
A visitor who has not signed in has no stable identifier. Applications usually create a random one, store it in the browser or on the device, and send it as the identity. That works, but when the visitor signs in, the application starts sending the account identifier, which is a different identity, and so a different set of traits and possibly a different experience. Plan for this moment. Some teams keep using the anonymous identifier even after sign-in for the length of an experiment. Others accept the change and avoid running experiments across the sign-in boundary.
Do not change your identifier scheme casually. If you switch from user numbers to account numbers, every person becomes a new identity with no stored traits and no overrides, and every percentage rollout reshuffles who is in the group. Plan such changes like a migration, and tell everyone who watches the rollout numbers.
Use case: choosing the company as the identity
A project-management tool is used by teams. The product team wants a new reporting screen to appear for entire companies at once, since two colleagues comparing screens would be confused if one saw the new report and the other did not. They use the company number as the identifier, and send the person’s job role as a trait. A rule such as “role equals manager” still works, because the trait travels with each request, while the percentage rollout and company-level overrides use the stable company identity.
Questions to ask before you lock in the identifier
A short meeting on identifiers saves months of rework. Gather the people who build the website, the mobile apps, the back-end services, the analytics, and customer support, and ask each group the same questions. Does your system know the identifier at the moment it asks for flags? Does it stay the same when the person changes their email address, their name, or their phone? Can two people share it by accident, for example members of one family using one login? Can one person own two of them, for example a work account and a personal account? The answers often reveal that two teams have been using two different numbers for the same human being.
Write the final decision on one page, and keep it next to the trait dictionary. The page should say what the identifier is, where it comes from, who is allowed to create it, and what happens to the identity when a customer closes their account. This small document answers many later arguments before they begin.
Think of the roll number in a school. It is given once, never reused, never changed when a child changes their nickname, and every teacher, the library, and the sports department use the same one. Nobody has to guess which Rahul is meant. Your identifier should be the roll number of your product.
6Designing a Clean Set of Traits
A trait is cheap to create and expensive to live with. A little design at the start prevents years of confusion.
Start from the rules, not from the data
The best way to choose traits is to work backwards from the decisions you want to make. List the groups you expect to need: employees, premium customers, new users, regions, app versions. For each group, ask which fact would describe it. The answer is your trait. This keeps the list short and every trait purposeful.
A trait dictionary
Keep one shared document, a trait dictionary, that lists every trait the product sends. For each one, it should say the exact key, the kind of value, the allowed values, who sends it, and which segments use it. It sounds like paperwork, but it prevents the most common failure of all: two teams sending the same fact under two names.
| Key | Kind | Allowed values | Sent by | Used by |
|---|---|---|---|---|
| plan | Text | free, plus, premium | Web, mobile, back end | Premium access segment |
| country | Text | Two-letter codes, upper case | Web, mobile | Regional launch segments |
| app_version | Text | Version in the form 5.2.1 | Mobile only | Version gate segments |
| is_staff | True or false | true, false | Back end | Employees segment |
| signup_days | Whole number | Zero or more | Back end | New user segments |
Naming rules
- One style, everywhere. Choose lower-case words joined by underscores, and never mix styles, because “Plan,” “plan,” and “user_plan” are three different keys to a computer.
- Say what it is, not how it is used. “plan” lasts longer than “premium_check.”
- Keep the key stable. Renaming a trait silently breaks every segment that reads it.
- Prefer positive names. “is_staff” is clearer than “not_customer.”
- Avoid personal data in the key or value. A trait called “email” is a risk. A trait called “email_domain_is_company” may be enough for your rule.
Value rules
- Choose one spelling and one case. Decide that countries are upper-case two-letter codes, and keep to it.
- Use real numbers for numbers. Send 12, not the text “twelve,” if a rule will ask whether it is bigger than ten.
- Prefer a few clear values over free text. A trait with five possible values is easy to write rules for. A trait that holds anything is not.
- Turn dates into useful numbers. Instead of storing a date of birth, store “age_band” or “days_since_signup,” which is what the rule actually needs and is less sensitive.
- Keep values small. Traits are not the place for paragraphs of text.
Think of the form that a school gives to parents each year. If every class teacher invents their own form, some ask for “Mobile,” some for “Phone,” and some for “Contact,” and the office cannot combine them. One standard form with fixed boxes lets the office answer any question quickly. A trait dictionary is that one standard form for your product.
Do the derived work in your own code, not in Flagsmith. If a rule needs “customers who joined in the last thirty days,” compute the number of days in your application and send it as a trait. Segment rules are best when they compare simple, ready-made facts.
7How Traits Travel From Your Application to Flagsmith
Traits do not appear by magic. Your application must send them. Understanding the routes tells you when a trait is current and when it is stale.
The SDK and the environment key
An SDK, or software development kit, is a small library that you add to your application so it can talk to Flagsmith in its own programming language. When the SDK starts, it is given the environment key, which tells Flagsmith which environment the application belongs to. Every later request carries this key, so the identity and its traits are recorded in the right environment.
Four ways traits reach Flagsmith
With the identify request
When the application asks for the flags of an identity, it can include traits in the same request. Flagsmith stores them on the identity, and uses them straight away to work out the answer.
By setting a single trait
The SDK offers a way to set one trait at a time, for example when a customer upgrades their plan, and to refresh the flags afterwards.
Through the management interface
Scripts, back-end jobs, or people with permission can add or change traits on an identity using the Admin API or the dashboard.
Supplied only for the moment
In local evaluation, a back-end server decides for itself using the traits you pass in the call, without storing them in Flagsmith at all.
sequenceDiagram
participant U as User
participant A as Application
participant SDK as Flagsmith SDK
participant FS as Flagsmith
U->>A: Signs in and opens the app
A->>A: Collect identifier and traits from own data
A->>SDK: Get flags for identity with traits
SDK->>FS: Request using environment key, identifier, and traits
FS->>FS: Create or find the identity in this environment
FS->>FS: Save or update the traits sent
FS->>FS: Match traits against segment rules
FS->>FS: Work out feature states for this identity
FS-->>SDK: Enabled position and value for each feature
SDK-->>A: Flags kept in memory
A-->>U: Shows the right version of the app
Stored traits versus transient traits
In the usual way of working, traits sent to Flagsmith are stored on the identity, and are remembered for the next request. This is convenient, because traits sent once, such as the date of sign-up, stay available. But in some situations you do not want Flagsmith to remember anything. Flagsmith supports sending transient information, meaning the identity, or particular traits, are used for working out the answers during that request and then forgotten. This is useful for privacy-sensitive facts, for very large numbers of short-lived visitors, and for facts that are only true right now, such as the current page or the current network speed.
What happens with local evaluation
With local evaluation, a back-end server downloads all the rules and states of an environment, and works out answers itself, from memory. It never has to ask Flagsmith about each user. In that mode, the traits come from you, supplied in every call, and they are used for that call only. This is fast and private, but it means your application must always provide the traits it wants rules to see, since there is no stored copy to fall back on.
| Aspect | Remote evaluation, stored traits | Local evaluation, supplied traits |
|---|---|---|
| Who decides the answer | Flagsmith’s servers | Your own server |
| Where traits live | Saved on the identity in Flagsmith | Passed in each call, not stored |
| If you forget to send a trait | An older stored value may still be used | The rule sees no value at all |
| Speed | A network trip per fetch | Almost instant, from memory |
| Privacy | Traits are held by Flagsmith | Traits stay inside your server |
With stored traits, an old value can linger. If a customer downgrades from premium to free but your application only sends traits at sign-up, Flagsmith may still believe they are premium. Decide when each trait is refreshed, and send it every time it could have changed.
Choosing the right moment to send traits
The moment you send traits decides how current they are. Three moments matter most. At application start, the application knows the customer and can send everything. At sign-in, the identity changes from visitor to customer, so traits must be sent again under the new identifier. At a life event, such as an upgrade, a change of country, or a new app version after an update, the relevant trait should be updated immediately and the flags refreshed, so the person sees the change without waiting for the next visit.
Many teams forget the second moment. A visitor who browsed anonymously and then signed in is a new identity to Flagsmith, with no traits at all until the application sends them. Always send the full trait set right after sign-in, before showing any screen that depends on a flag.
8Traits and Segments: Turning Facts Into Groups
Traits by themselves do nothing. They become powerful when segment rules read them. This chapter shows how facts become groups.
What a segment is
A segment is a saved, named group defined by rules. It is created once at the project level, so every environment can use it. A segment does not contain a list of people. It contains rules, and anyone whose traits satisfy those rules is in the group at that moment. Examples are “Premium customers in India” or “New users on recent app versions.”
The building blocks of a rule
A segment is built from rules, and each rule is built from conditions. A condition has three parts: the trait key to look at, an operator that says how to compare, and the value to compare against.
| Operator idea | Plain meaning | Good for |
|---|---|---|
| Equals, not equals | The trait is exactly this value, or is not | Plan, country, staff flag |
| Greater than, less than, and with equal | Number comparisons | Days since signup, spend, counts |
| Contains, not contains | Text includes a piece of text | Email domains, labels |
| Regular expression | Text matches a pattern | Flexible text matching, used with care |
| Percentage split | A stable share of identities, from a hash | Gradual rollouts |
| In a list | The trait is one of several listed values | A group of countries or plans |
| Is set, is not set | The trait exists or is missing | Handling people with no data |
| Version comparison | Compare dotted versions the way people expect | App version gates |
Exact operator names, and which ones exist, depend on your Flagsmith version. Read the segment screen in your own dashboard to see the current list, and prefer the simple operators wherever they are enough.
Combining conditions: ALL, ANY, and NONE
A rule can say that all its conditions must be true, that any one of them is enough, or that none of them may be true. A segment can hold several rules, and a person must satisfy every rule to be in the segment. Used together, these let you express most real groups.
Every condition must hold
Plan is premium AND country is IN. Both facts must be true. Like needing both a ticket and an ID card at the gate.
One condition is enough
Country is IN OR country is SG OR country is MY. Any one will do. Like a coupon valid at any of three shops.
No condition may hold
Is test account is true must NOT be the case. Like a rule that says nobody on the banned list may enter.
flowchart TB
SEG["Segment: Premium learners on new apps"]
SEG --> R1["Rule 1, ALL of:"]
SEG --> R2["Rule 2, ANY of:"]
SEG --> R3["Rule 3, NONE of:"]
R1 --> C1["plan equals premium"]
R1 --> C2["signup_days less than 30"]
R2 --> C3["country equals IN"]
R2 --> C4["country equals SG"]
R3 --> C5["is_staff equals true"]
What happens when a trait is missing
Not everyone has every trait. A visitor who has not signed in has no plan. A new identity may not yet have a country. When a condition looks at a trait that the identity does not have, the usual result is that the condition is not satisfied, so the identity does not match a rule that needs it. The one exception is a “not equals” or “none of” style test, which may behave in ways that surprise beginners. Always test the people with no data, because they are often the largest group.
Imagine a bouncer at a club with a clipboard of rules: “Members only, over eighteen, not on the banned list.” Every guest shows a card. If a guest’s card has no age printed on it, the bouncer cannot confirm the rule, so he does not let them in through that door. Missing information means the rule is not proven true.
Segments are shared, overrides are not
The definition of a segment is the same in every environment of the project. But what the segment does, meaning which feature states it overrides, is set separately in each environment. So “Premium customers” means the same group in Staging and Production, while the feature it unlocks can be switched on in Staging and still be off in Production.
Use case: a premium preview
A music app creates a segment called “Premium preview,” made of two conditions: plan equals premium, and app version is at least 7.0.0. In Staging, the segment turns on a new lyrics screen. Testers who are given premium plans and a recent version see the screen. In Production, the same segment is attached to the feature but left off until the launch day. On launch day, a product manager changes one setting in Production, and every matching listener sees the new screen on their next refresh.
Reading the matrix with three questions
When you design or review a rollout that uses traits, three questions keep the thinking clear. First, who is this for: which traits describe the people who should receive the feature, and are those traits reliably present on every platform? Second, who must be protected: which people, such as old app versions, test accounts, or regulated regions, must never see the feature, and have you excluded them with explicit conditions? Third, what happens to everyone else: is the default safe, is it tested, and does the application behave sensibly when Flagsmith gives it no personal answer at all?
Teams that write the answers to these three questions into the ticket before building anything find that most arguments about targeting vanish. The answers become the acceptance test for the segment, and the persona matrix is simply those answers turned into a table. Teams that skip them often discover the missing answer in Production, in front of customers, which is the most expensive place to learn anything.
Finally, remember that a rollout is a story told over days and weeks, not a single switch. Each step should have a named owner, a watched measure, and a clear condition for moving on or going back. Traits and segments give you the dials, but people still have to decide when to turn them, and a calm, written plan makes those decisions easier for everyone involved.
9How Flagsmith Evaluates an Identity Step by Step
When your application asks for flags, Flagsmith performs a short, repeatable routine. Knowing it lets you predict every answer.
The order of authority
For every feature, Flagsmith asks the same questions in the same order. The first layer that has something to say wins, and the later layers are not consulted.
flowchart TB
START["Request: identifier and traits"] --> LOAD["Find or create the identity, save the traits"]
LOAD --> F1{"Is there an identity override for this feature?"}
F1 -- Yes --> OUT1["Use the identity override"]
F1 -- No --> F2{"Does the identity match any segment that overrides this feature?"}
F2 -- Yes --> PRI["Pick the matching segment with the highest priority"]
PRI --> OUT2["Use that segment's state or value"]
F2 -- No --> F3{"Is the feature multivariate or a percentage split?"}
F3 -- Yes --> HASH["Hash identifier and feature to choose a variation"]
HASH --> OUT3["Use the chosen variation"]
F3 -- No --> OUT4["Use the environment default state"]
Locate the identity
Using the environment key and the identifier, Flagsmith finds the identity or creates it, and saves any traits sent with the request.
Look for a personal override
If this exact person has been given a special state for the feature, it wins immediately.
Check the segments
Flagsmith tests the traits against the rules of every segment that overrides the feature in this environment. Those that match become candidates.
Choose by priority
If several segments match, the one placed highest in the priority order wins. The order is set per feature, so you can control it with care.
Apply multivariate choice
If no override applies and the feature has variations, a stable hash picks one for this person.
Fall back to the default
If nothing else spoke, the environment’s own state for the feature is used.
A worked example
A feature called “new player” has these settings in Production. The default is off. A segment “Employees” turns it on and sits first in the priority order. A segment “New learners” sets it on with a value of “tour” and sits second. Beta customer number 884 has a personal override that turns it off.
- Learner 884 has the personal override, so the player is off, even if they are an employee. The personal layer wins.
- An employee who is also a new learner matches both segments. Employees is higher in priority, so the player is on with the Employees setting.
- A new learner who is not an employee matches only the second segment, so the player is on with the value “tour.”
- Everyone else falls to the default, so the player is off.
Think of a school with house rules. A note from a parent about one child beats the class rule. The class rule beats the school rule. The school rule applies to everyone left over. When two class rules apply to the same child, the head teacher’s ranked list decides which comes first. Flagsmith’s layers work the same way: the most specific instruction wins.
Priority matters only when two segments disagree for the same feature. If you never look at the order, a new segment added later can quietly take over for people who matched an older one. After adding a segment override, always open the priority list and confirm the order is what you intend.
Predicting an answer before you open the dashboard
With practice, you can predict any answer by walking down the layers in your head. Ask first whether this person has a personal override. If yes, you are finished. If not, list the segments that override this feature in this environment, test the person’s traits against each one, and keep the ones that match. From those, choose the highest in the priority list. If none match, check for variations and a percentage rule. If still nothing, read the environment default. Doing this by hand a few times builds trust in the system, and makes surprising results easy to explain to colleagues.
Remember also that evaluation is about this feature only. Two features can give the same person opposite answers, because each feature has its own overrides, its own priority list, and its own hash recipe. A person can be in the first ten percent for one feature and the last ten percent for another.
10Type and Spelling Pitfalls
Most trait bugs are not clever. They are small disagreements about spelling, case, or type. Learn the usual suspects once and avoid them forever.
Text that looks like a number
The text “10” and the number 10 look identical on a screen but are different things to a computer. If your application sometimes sends the number and sometimes sends the text, rules that compare “greater than” may behave differently for each. Choose one kind per trait and keep it. Even better, record that choice in the trait dictionary.
The case and spelling trap
To a computer, “Premium,” “premium,” and “PREMIUM” are three different values. A segment written for “premium” will quietly ignore someone whose trait says “Premium.” The same goes for stray spaces: “premium ” with a space at the end is not “premium.” The safe cure is a single normalising step in your own code, which trims spaces and puts values into the agreed case before sending.
True, false, and the words “true” and “false”
A real true or false value and the text “true” are different. Some SDKs and some old code send one, some send the other. A segment condition written for one may not match the other. Pick real true or false values for flags like is_staff, and check what your SDK actually sends.
Versions are not numbers
The version “5.10.0” is newer than “5.9.0,” but as plain text “5.10.0” sorts before “5.9.0,” because the character “1” comes before “9.” Comparing versions as text gives wrong answers. Use the version-aware comparison if your Flagsmith offers one, and send versions in one consistent shape, such as three numbers separated by dots.
| Pitfall | What you see | Cure |
|---|---|---|
| Number sent as text | Comparison rules misbehave | Send real numbers for number traits |
| Mixed case | Some premium users do not match | Normalise case before sending |
| Trailing spaces | Values look equal but do not match | Trim every text value |
| Boolean as text | Staff flag rule matches nobody | Send real true or false |
| Version as plain text | 5.10 judged older than 5.9 | Use version comparison |
| Renamed key | Segment stops matching without error | Never rename, add a new key and migrate |
| Different keys per platform | Web users match, mobile users do not | One trait dictionary for all platforms |
| Empty text sent as value | Trait looks set but holds nothing | Omit or remove traits that have no value |
Think of a postal sorting office. A letter addressed to “Flat 4B,” another to “flat 4b,” and a third to “4-B” may all be meant for the same home, but a sorting machine that matches exact text will send them to three different boxes. People fix this by agreeing on one address format at the start. Traits need the same agreement.
Build one small function in your application, a “trait builder,” that every platform uses to produce the trait set. It fixes case, trims spaces, converts types, and drops empty values in one place. When someone later asks why a user did not match, you have exactly one place to look.
Use case: the invisible premium bug
A video service launches a premium-only feature. Within an hour, support receives complaints from paying users who cannot see it. Engineers open one affected identity in the dashboard and see the trait plan with the value “Premium,” capitalised. The segment rule says “premium.” The mobile app, written by a different team, had used capital letters for years. The fix takes one line in the trait builder, and the team adds a rule to their review checklist: every new trait must be entered in the dictionary with its exact allowed values.
11Freshness and the Life of a Trait
A trait is a photograph of a moment. People change, and photographs go out of date. Good teams decide how traits are refreshed, and how they are retired.
The life of a trait
stateDiagram-v2
[*] --> Proposed: Team needs a new fact
Proposed --> Documented: Added to the trait dictionary
Documented --> Sending: Application starts sending it
Sending --> InUse: A segment or rollout reads it
InUse --> Sending: Value refreshed when it changes
InUse --> Deprecated: No rule needs it any more
Deprecated --> Removed: Stop sending and delete stored values
Removed --> [*]
When to refresh
- Every session start. Simple and safe: send all traits whenever the application begins, and no value stays old for long.
- On the event that changes it. When a customer upgrades or changes country, update that trait at once and refresh the flags.
- On a schedule. For values that drift, such as days since signup, a daily job can recompute them. Or, better, compute them in the application at request time.
- Never for permanent facts. A date of signup does not change, so it need be sent only once, though sending it again does no harm.
Removing traits
Traits can also be removed from an identity. Removing is important when a fact stops being true, or when a person asks you to forget something. Setting an empty value is not the same as removing. If a condition checks whether the trait exists, an empty value still counts as present. Use the removal feature of the SDK or API when you mean “this fact no longer exists.”
Drift between systems
The truth about a customer lives in your own database. The traits in Flagsmith are a copy. Like every copy, it can fall behind. If the plan in your billing system changes to free, and the copy says premium, the person keeps premium features until the copy is updated. Decide which system is the source of truth, and make updates flow one way, from your database to Flagsmith, never the other way.
Think of the signboard outside a restaurant that says “Today’s soup: tomato.” The kitchen changes the soup, but nobody remembers to change the board. Customers order tomato soup and are told it is finished. The kitchen is the source of truth, and the board is the copy. A good restaurant gives one person the job of updating the board each time the menu changes.
Beware of traits that are used for money or access. If a stale trait gives a free user a paid feature, you lose revenue. If it takes access from a paying user, you lose trust. For such traits, check the truth in your own system as well, and treat Flagsmith as a convenience layer, not the only gate.
Choosing an owner for every trait
A trait without an owner decays. Nobody notices when it is wrong, nobody removes it when it is useless, and nobody answers questions about it. Give each trait one named owner, a person or a team, who is responsible for three things: that the value is correct at the source, that it is sent whenever it changes, and that it is removed when the last rule that reads it disappears.
Hold a short review every quarter. Open the dictionary and ask of each trait: is any segment still reading it, is the value still correct, is the data still permitted, and could a less sensitive fact do the same job? Traits that fail the review are marked deprecated, then removed. This steady gardening keeps the set small, and keeps the number of surprises small too.
Handling a trait whose meaning changes
Sometimes a business changes what a word means. The plan called “plus” may be split into “plus monthly” and “plus yearly.” If you quietly change the allowed values, every segment that reads “plus” stops matching the new customers. The safe route has four steps. First, add the new values to the dictionary. Second, update every segment that reads the old value so it accepts both. Third, start sending the new values. Fourth, after the old value has disappeared from live identities, tidy the segments. Never change meaning in place.
When a trait must change shape, run old and new side by side for a while. Two traits for a few weeks cost almost nothing, while a silent break in a rollout can cost a whole launch.
12Identity Overrides and Environment Scoping
Sometimes a rule is too broad. You want to treat exactly one person differently. That is an identity override, and it lives in exactly one environment.
What an identity override is
An identity override is a feature state attached to one specific identity in one specific environment. It beats every segment and the default. It answers needs such as “give this customer the beta early,” “switch the new design off for the complaining executive,” or “let our tester see the feature in Production.”
Strengths
- Fastest way to help one person.
- Wins over all other layers, so the result is certain.
- Needs no new segment or trait.
- Visible on the identity’s page in the dashboard.
Weaknesses
- Does not scale to many people.
- Easily forgotten, and then keeps winning when it should not.
- Hidden from anyone who looks only at segments.
- Not copied when you copy an environment.
Why each environment keeps its own identities
Identities, traits, and overrides belong to one environment. Your test user in Staging is not the same as the same-named person in Production. This protects real customers from test data, and lets testers experiment freely. It also means that a trait or override you set in Staging does not follow you to Production. You must set up the same behaviour there on purpose.
| Item | Shared by the whole project? | Separate per environment? |
|---|---|---|
| Feature definitions | Yes | No |
| Segment definitions and rules | Yes | No |
| Segment overrides on a feature | No | Yes |
| Identities | No | Yes |
| Traits | No | Yes |
| Identity overrides | No | Yes |
| Environment keys | No | Yes |
A clean habit with overrides
Give every identity override a reason and an end date, written somewhere your team can see, such as the ticket that asked for it. Review them on a schedule. An override created for a launch week and forgotten for two years becomes a mystery that engineers will spend hours solving.
Think of a theatre with a signed note on the door: “Let Mr. Shah in free, he is the author.” It is useful on opening night. Years later, a new doorkeeper keeps obeying the note for a man nobody remembers. A note with a date and a reason would have been removed. An override is that note.
When one-person overrides begin to repeat, you have discovered a segment. If you have created the same override for ten customers, define a trait such as “beta_tester” and a segment on it, then delete the ten overrides.
13Percentages, Experiments, and Stable Hashing
Gradual rollouts and experiments need a fair, steady way to place each person in a group. The identifier makes this possible.
What hashing is
A hash is a recipe that turns any piece of text into a number in a fixed range, always giving the same number for the same text. Flagsmith combines the identity and the feature, turns them into a number between zero and one hundred, and compares it to the percentage you set. If the number is below the percentage, the person is in the group.
flowchart LR
I["Identifier: learner 1001"] --> H["Combine with feature and compute hash"]
FEAT["Feature: new player"] --> H
H --> N["Stable number from 0 to 100, say 37"]
N --> D{"Is 37 below the rollout percentage?"}
D -- "Rollout 30 percent" --> OUT1["No: not in the group"]
D -- "Rollout 50 percent" --> OUT2["Yes: in the group"]
Why this is so useful
- Stability. A person at 37 stays at 37. They never flip between experiences from visit to visit.
- Growth without churn. Moving from thirty to fifty percent keeps everyone already in, and adds more. Nobody loses the feature.
- Independence between features. Because the feature is part of the recipe, the group chosen for one feature differs from another, so the same unlucky people do not test everything.
- No storage. Flagsmith does not need to remember who is in which group. It recalculates each time.
Multivariate experiments
A multivariate feature has several variations, each with a weight, such as forty percent for blue, forty for green, and twenty for the control. The hash picks one variation for each identity, and keeps them there. This is the foundation of A/B testing, where two or more versions are compared on equal groups.
Mixing traits and percentages
Segments can combine trait conditions with a percentage split. A rule might say “country equals IN, AND percentage split below twenty.” That is a twenty percent trial inside one country. This is how teams roll out region by region and in small steps at the same time.
Experiments are only fair if the identifier is stable. If you use an anonymous identifier that changes when the person signs in, the same human appears as two identities, may land in two variations, and spoils the results. Decide the identity strategy before the experiment begins, and never change it midway.
Think of a school that decides which students join a trip by using the last two digits of each roll number. Roll number 37 is always at 37. If the school allows the first fifty, student 37 joins. The next year it allows seventy, and student 37 still joins. Nobody argues, because the rule is the same and does not depend on mood.
Reading experiment results honestly
Stable groups are only the start of a good experiment. The groups must also be large enough to show a real difference, run long enough to cover a full cycle of behaviour, such as a whole week, and be measured by a goal chosen before the experiment began. Stopping a test the moment the numbers look good is a common way to fool yourself. The feature flag platform gives you the fair split, and your analytics system gives you the evidence. Keep the two connected by recording, with every important event, which variation the person saw.
Also keep in mind that traits can hide unfair splits. If a trait such as country is strongly linked to the result, make sure each variation contains a fair mix of countries. The hash is blind to traits, which usually produces balanced groups for large numbers of people, but small groups can be uneven by chance.
14Traits Across the Delivery Pipeline
A feature is tested in Development, rehearsed in Staging, and shown to real people in Production. Traits must behave the same way in all three, or testing means nothing.
The rehearsal problem
Suppose your segment says “plan equals premium AND country equals IN.” In Production, real customers carry those traits. In Staging, testers often have no traits at all, because nobody set them up. The feature looks broken in Staging, or worse, looks fine because the test user happens to have an override. In Production, the rule behaves differently. The rehearsal did not rehearse the real thing.
Making environments honest
Send the same traits everywhere
The same code that builds traits in Production must run in Development and Staging, fed by test data that looks like the real thing.
Create named test personas
Make a handful of test identities, such as “premium user in India” and “free user in Germany,” with fixed traits. Everyone on the team knows them by name.
Prefer segments to overrides in testing
If testing relies on personal overrides, you are not testing the rules that real users will meet. Let personas match segments by their traits.
Repeat the setup in Production deliberately
Segment definitions are shared, but segment overrides are per environment. Check the Production screen as a separate step of the release checklist.
Verify with a real identity page
After release, open a real, consenting test user in Production and read the identity page to confirm traits and resulting states.
| Environment | Who the identities are | Trait source | Main purpose |
|---|---|---|---|
| Development | Engineers and automated tests | Fixed test values written in code | Build and debug quickly |
| Staging | Testers, product owners, named personas | Realistic test data from a copy of production shapes | Rehearse the real rules |
| Production | Real customers and staff | Your live systems of record | Serve real people safely |
Think of a fire drill. A drill is only useful if the school uses the same exits, the same bell, and the same class lists as in a real fire. A drill where everyone uses a secret side door teaches nothing. Staging must use the same doors as Production.
Use case: the Staging that lied
A travel company tests a new currency selector in Staging. Everything works. In Production, nobody in Europe sees it. Investigation shows that Staging testers all had a trait called “region” with the value “EU,” while the production app sends “country” with two-letter codes, and the segment was written for “country.” The test users had personal overrides that hid the mismatch. After the incident, the team bans overrides for testing, and makes the trait builder run in every environment.
15Testing Traits and Segments
A segment rule is a small program. Like every program, it deserves tests before real people depend on it.
What to test
- The trait builder. Given sample customer data, does it produce the exact keys, types, and spellings in the dictionary?
- The segment rules. Does each persona land in the segments you expect, and only those?
- The edges. What happens to people with a missing trait, an empty value, a very old app version, or a brand new account?
- The priority order. When two segments match, does the winner have the feature state you intended?
- The application behaviour. Does the app really change what it shows for each state?
The persona matrix
The best tool is a small table that lists named personas on one side and the expected outcome on the other. You create each persona as an identity with fixed traits, and then check the result in the dashboard or through the SDK. The table also becomes living documentation.
| Persona | Traits | Expected segments | Expected state of new player |
|---|---|---|---|
| Asha, new premium learner in India | plan premium, country IN, signup_days 5 | Premium, New learners | On, value tour |
| Ben, free user in Germany | plan free, country DE, signup_days 400 | None | Off, default |
| Chitra, staff member | is_staff true, plan free | Employees | On, employee value |
| Dev, visitor with no traits | Nothing sent | None | Off, default |
| Eli, old app version | plan premium, app_version 4.9.0 | Premium only | Off, version gate blocks |
Levels of testing
Dashboard check
Open each persona’s identity page and read the feature states Flagsmith reports. Quick and visual. Good for the first pass.
Automated tests
A test script creates the personas through the SDK in a test environment and asserts the answers. It catches regressions when someone edits a segment.
Behavioural tests
End-to-end tests drive the real application with a persona and check the screen. They prove the whole chain from trait to pixel.
Production smoke check
After release, a consenting internal user in Production confirms the live result. It proves Production’s own overrides are right.
Think of a chef who tastes the soup at every stage: after the stock, after the spices, and before serving. A recipe that was never tasted will surprise the guests. A persona matrix is the spoon.
Always include a “no data” persona. Teams test the happy people and forget the stranger who arrives with nothing. That stranger is often the biggest group, and the one most likely to hit a surprise.
16Advantages, Disadvantages, and Trade-offs
Identity traits are powerful, but every power has a price. Seeing both sides helps you decide how much to use.
Advantages
- Targeting without new releases: change who sees a feature by editing rules.
- Safe, gradual launches by country, plan, version, or percentage.
- Personalised experience with one codebase.
- Fast support: a person’s exact states can be read on their page.
- Shared definitions: one segment can drive many features.
- Experiments with stable, fair groups.
Disadvantages
- Traits are a copy of the truth and can go stale.
- Extra data about people means extra privacy duty.
- Hidden complexity: many segments make behaviour hard to predict.
- Type and spelling mismatches cause silent failures.
- Stored identities add volume and cost at large scale.
- Every new trait must be sent by every platform.
Key trade-offs
| Decision | Option A | Option B | How to choose |
|---|---|---|---|
| Where traits are kept | Stored in Flagsmith: remembered between requests | Sent each time, not stored: more private | Store stable facts, send sensitive or fast-changing ones only for the moment |
| Evaluation place | Remote: always current, one network trip | Local: fast and private, rules cached | Remote for browsers and mobile, local for high-traffic servers |
| Number of traits | Many: flexible rules | Few: simple and safe | Only traits that a real rule reads |
| Identifier | User: personal experience | Account: team-wide experience | Depends on who should see the same thing |
| Targeting tool | Segments: scalable, reusable | Identity overrides: precise, one-off | Segments by default, overrides for exceptions |
| Refresh style | Every session: simple | On change: efficient | Combine both for critical traits |
Context
Our product has anonymous visitors, signed-in users, and company accounts. We need stable experiments and company-wide launches.
Decision
Use the internal user number as the identifier after sign-in, a random stored visitor number before sign-in, and send the company number as a trait for company-wide rules.
Consequences
Experiments are stable for signed-in users. Visitors may switch identity at sign-in, so no experiment spans that moment. Company rules use a trait, so they work without a separate identity.
Think of a tailor’s shop. Taking many measurements makes a better-fitting suit, but takes longer, needs more records, and carries more risk if the notebook is lost. A good tailor takes only the measurements needed for the garment being made.
Deciding how much targeting is enough
Every new targeting dimension multiplies the number of experiences your product can have. Three plans, ten countries, and four app versions already make one hundred and twenty possible combinations, and each combination must be tested, supported, and understood. Teams that target heavily find that a bug report becomes a puzzle: which of the hundred and twenty versions did this person see? The cure is restraint. Use the smallest set of traits that supports your real business needs, and prefer broad groups over narrow ones. When the number of segments for one feature grows past a handful, pause and ask whether the feature is trying to do too much.
17Privacy, Security, and Compliance
Traits describe people. Anything that describes people carries a duty of care. This chapter lists the main risks and the habits that keep them small.
Why traits need special care
An identity and its traits can reveal who someone is, where they live, what they pay, and how they behave. Laws such as the European GDPR and the California CCPA treat information like this as personal data. They give people rights to see, correct, and delete it. Even where no law applies, customers expect you to be careful.
The main risks
Personal data in identifiers
Emails or phone numbers used as identifiers spread through logs, dashboards, exports, and third-party integrations.
Sensitive traits
Health, religion, politics, or finances stored as traits create legal and ethical exposure for little benefit.
Client-side exposure
Anything that runs in a browser or phone can be inspected. A user can see their own traits and the answers returned, and may try to change them.
Over-trusting traits
A trait sent by a client is a claim, not proof. A user could tamper with it to unlock paid features.
Leaked keys
A server-side key allows reading rules and identities. If it leaks, an attacker may learn your targeting and edit identities.
Leftover data
Traits for people who left, or for facts you no longer use, remain in storage and increase the damage of any breach.
Habits that reduce risk
- Collect the minimum. Only send a trait if a rule reads it.
- Use opaque identifiers. Random internal numbers, never emails.
- Prefer derived facts. Send “age_band” instead of a birth date, “is_company_email” instead of the email.
- Use transient mode for sensitive data. Let rules see a fact for one request without storing it, where your Flagsmith version supports it.
- Keep secrets on servers. Use the public client-side key in browsers and apps, and keep the server-side key out of any code that ships to users.
- Never use traits as the only gate for money or safety. Verify entitlements on your own server.
- Plan for deletion. When a person asks to be forgotten, remove their identity and traits from every environment and from any systems connected to Flagsmith.
- Control who can edit. Give edit rights for identities and segments only to people who need them, and review the audit log.
flowchart TB
DATA["Fact about a person"] --> Q1{"Does any rule read it?"}
Q1 -- No --> DROP["Do not send it"]
Q1 -- Yes --> Q2{"Is there a less sensitive derived version?"}
Q2 -- Yes --> DER["Send the derived version"]
Q2 -- No --> Q3{"Must Flagsmith remember it?"}
Q3 -- No --> TRANS["Send as transient, or use local evaluation"]
Q3 -- Yes --> STORE["Store it, document it, and plan its deletion"]
Think of a doctor’s clinic. The clinic keeps only the records it needs, files them under a patient number rather than shouting names across the waiting room, locks the cabinet, and destroys old files on schedule. A trait store deserves the same manners.
This guide explains engineering practice, not legal advice. Rules on personal data differ by country and by industry. Ask your privacy or legal team which traits you may collect and how long you may keep them.
18Monitoring, Logging, and Debugging
When a person says “I cannot see the feature,” you need a calm, repeatable way to find out why. This chapter gives you that method.
The identity page is your best friend
The dashboard can show an individual identity: its identifier, its traits, its overrides, and the feature states it would receive. This is the first stop in any investigation. It answers the question “what does Flagsmith believe about this person right now?” in seconds.
A debugging routine
Confirm the environment
Is the application using the Production key or the Staging key? Many mysteries end here.
Find the identity
Search by the exact identifier. If it does not exist, the application never sent it, or sent a different one.
Read the traits
Check keys, spelling, case, and type against the dictionary. Look for missing, stale, or empty values.
Look for a personal override
An old override may be winning over everything.
Check segment matches and priority
Which segments match? Which one is highest in the priority list for this feature?
Check the application side
Did the app refresh flags after the trait changed? Is it showing cached answers? Is the state being used the way the developer intended?
Fix the cause, not the symptom
Correct the trait builder or the rule instead of adding an override, and add a test that would have caught it.
What to measure
| Signal | Why it matters | Warning sign |
|---|---|---|
| Share of requests with an identity | Shows how many people can be targeted | Sudden drop after a release |
| Share of identities holding each key trait | Shows the coverage of your data | A key trait missing from a whole platform |
| Trait value distribution | Reveals spelling variants | Both “premium” and “Premium” appear |
| Segment size over time | Detects broken rules or data | A segment shrinks to zero overnight |
| Count of identity overrides | Shows manual exceptions piling up | Hundreds of one-person overrides |
| Errors and latency of flag requests | Protects user experience | Slow identify calls at peak |
| Audit log entries | Shows who changed rules and when | Unexpected edits before an incident |
Logging with care
Log the identifier and the resulting flag states when it helps diagnosis, but avoid logging the full trait set if it holds personal facts. Many teams log only a hashed identifier and the names of the segments matched. Connect Flagsmith’s audit log and webhooks, where available, to your alerting, so that an unexpected rule change is noticed quickly.
Think of a mechanic who hears a strange noise. The mechanic does not guess. She checks the fuel, the battery, the oil, and the tyres, always in the same order. A fixed routine finds faults faster than clever guesses.
Working with support teams
Customer support is often the first to hear that a feature is missing for someone. Give support a simple, safe way to look up an identity, with permission to read but not to change traits and overrides. Give them a short page that explains the four usual causes: wrong environment, missing or misspelt trait, a competing override, and a stale cached answer in the application. Most tickets can then be answered in minutes, without waking an engineer.
Teach support to record the identifier, the time of the report, the app version, and the platform. With these four facts, an engineer can open the identity, read the traits, and often find the cause on the first look. Without them, the first hour is spent asking questions.
Alerting on rule changes
Because a single edit to a segment can change the experience of millions, treat such edits with the care you give code changes. Many teams require a second person to approve changes in Production, use the audit log to see who changed what, and send notifications to a shared channel when a segment or override is edited. If a rollout metric moves right after such an edit, the audit log tells you exactly what changed and when, which turns a long hunt into a short one.
Think of the log book kept by a lift engineer. Every visit is written down: who came, what was changed, and when. When the lift stops working, the first thing anyone does is read the book. The audit log is the log book for your rules.
19Performance and Scale
A handful of testers is easy. Millions of users, each with traits, is another world. Here is how to keep the system quick and affordable.
Where the cost comes from
- Number of identities. Every stored identity is a record. Millions of short-lived visitors can fill storage with data nobody will ever read again.
- Number and size of traits. More traits mean larger payloads and slower requests.
- Frequency of requests. Asking Flagsmith on every screen change multiplies traffic.
- Segment complexity. Many segments with long rules take more work to evaluate.
Ways to keep it light
Fetch once, keep in memory
Ask for flags at app start or sign-in, keep them in memory, and refresh on a sensible timer or when a trait changes.
Use local evaluation on busy servers
Servers that handle huge traffic can download rules once and decide in memory, avoiding a network trip for each user.
Do not store anonymous visitors
For visitors who may never return, use transient identities so records do not pile up.
Send few, small traits
Keep values short and keys few. Compute derived values yourself.
Cache with a plan
If you cache answers, choose how long, and make sure a plan change or sign-out clears the cache.
Have a safe default
If Flagsmith cannot be reached, the application should use a built-in default for each flag and keep working.
flowchart LR
APP["Application"] --> CACHE{"Fresh flags in memory?"}
CACHE -- Yes --> USE["Use them immediately"]
CACHE -- No --> CALL["Ask Flagsmith with identity and traits"]
CALL --> OK{"Reply received in time?"}
OK -- Yes --> SAVE["Keep in memory and use"]
OK -- No --> DEF["Use built-in safe defaults"]
Freshness versus speed
Caching makes the app fast but allows stale answers. A short refresh time gives fresher answers but more traffic. For most features a few minutes is fine. For urgent switches, such as a kill switch for a broken feature, use a shorter refresh or a streaming update, if your Flagsmith offers one. Match the speed to the stakes.
Think of a shopkeeper who writes today’s prices on a small board by the till instead of phoning the supplier for each sale. It is fast. The risk is that the board is out of date if prices change at noon. A wise shopkeeper updates the board at fixed times, and keeps a rule for what to charge if the board is missing.
Real throughput limits, record limits, and prices depend on your plan and on whether you host Flagsmith yourself. Treat any number as something to confirm with Flagsmith documentation or your account contact before planning capacity.
20Design Patterns and Anti-Patterns
Teams have solved these problems many times. Patterns are the solutions that keep working. Anti-patterns are the traps that keep catching people.
Good patterns
Trait builder
One function, shared by all platforms, builds traits with fixed names, cases, and types.
Trait dictionary
A written list of every trait: key, type, allowed values, owner, and users of the trait.
Persona set
Named test identities with fixed traits, used in every environment for testing and demos.
Cohort traits
Traits like “beta_tester” or “pilot_group” that mark a cohort, so segments replace piles of overrides.
Derived traits
Compute “signup_days” or “age_band” in your code, and send the ready-made fact.
Server-side entitlement
Money or safety checks happen on your server. Flagsmith controls presentation and rollout.
Anti-patterns
Anti-patterns
- The data dump. Sending every column of the customer table as traits.
- Email as identifier. Personal data spread across every tool.
- Override sprawl. Hundreds of one-person overrides nobody understands.
- Trait twins. “plan,” “user_plan,” and “Plan” meaning the same thing on three platforms.
- Trusting the client. Letting a browser decide its own plan for paid features.
- Test by override. Testers carrying overrides that hide broken rules.
- Identity roulette. Changing the identifier scheme in the middle of an experiment.
- Zombie traits. Traits still sent years after the last rule that used them was deleted.
Better habits
- Send only traits that a rule reads.
- Use random internal numbers.
- Turn repeated overrides into a cohort segment.
- One dictionary, one builder, one spelling.
- Verify entitlements on the server.
- Test through personas and segments.
- Fix the identifier strategy before any experiment.
- Retire traits when their last rule is gone.
Think of a kitchen. A good kitchen has labelled jars, a standard recipe, and one person who checks the stock. A bad kitchen has unlabelled jars, five versions of salt, and a note on the fridge from three years ago. Patterns are the labels. Anti-patterns are the notes.
21Best Practices and Common Mistakes
If you remember only one chapter for your daily work, make it this one. It gathers the habits that matter most.
Best practices
Decide the identity before you code
Choose what the identifier stands for, and write down how anonymous visitors become signed-in users.
Write the trait dictionary first
List keys, types, allowed values, sources, and users. Review it like code.
Build one trait builder
Normalise spelling, case, and types in a single shared function.
Keep traits few and fresh
Send only what rules read, and refresh when facts change.
Prefer segments, limit overrides
Give every override a reason and an end date.
Protect privacy by design
Opaque identifiers, derived facts, transient mode for sensitive data, deletion plans.
Test with personas
Include the no-data stranger, and repeat the tests in every environment.
Always keep safe defaults
Every flag needs a built-in default so the app survives an outage.
Common mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Forgetting to send traits on one platform | Segments work on web, not on mobile | Shared trait builder and dictionary |
| Using an email as the identifier | Privacy exposure, identity changes when email changes | Use an opaque internal number |
| Renaming a trait key | Segments silently stop matching | Add a new key, migrate, then retire the old one |
| Never refreshing a plan trait | Downgraded users keep paid features | Update on the event and verify on the server |
| Relying on overrides in testing | Rules untested | Personas that match segments |
| Changing priority without review | Wrong state for overlapping groups | Check the order after every change |
| Treating the client as trusted | Users can unlock paid features | Server-side entitlement checks |
| No default when Flagsmith is down | Features break during an outage | Built-in defaults for every flag |
Add a short checklist to every pull request that touches traits: Is the key in the dictionary? Is the type right? Is the value normalised? Does any rule read it? Is it personal data? Five questions catch most problems before they ship.
A simple adoption path for a new team
A team new to identities and traits does not need to do everything at once. A gentle path works well, with each step useful on its own.
Week one: identity only
Send a stable identifier from every platform. Use percentage rollouts and read the identity page. No traits yet.
Week two: three traits
Add the three facts you need most, perhaps plan, country, and app version. Write them in the dictionary and build the trait builder.
Week three: first segments and personas
Create two or three segments and a small set of personas. Test in Staging without overrides.
Month two: privacy and cleanup
Review every trait for need and sensitivity, add transient mode where useful, and start the quarterly review.
Month three: culture
Add the pull request checklist, train support, and make trait changes a normal part of design reviews.
Questions to ask in every design review
- Who is the identity for this feature, a person, an account, or a device?
- Which traits does the rule read, and are they already in the dictionary?
- What does the rule do for a visitor with no data?
- What is the safe default if Flagsmith cannot be reached?
- Does any trait here count as personal or sensitive data, and is there a safer version?
- Who removes this segment and these traits when the launch is finished?
These six questions take five minutes and prevent most of the incidents described in this guide. They also teach new engineers how experienced engineers think about targeting, which is a gift that grows over time.
22Real-World and Industry Examples
The ideas of identity and traits are not unique to Flagsmith. Large companies have used the same thinking for years. Here are well-known patterns, described in general terms.
The company examples below describe publicly known practices in broad strokes, written from general knowledge and not from searching for fresh sources. Details inside each company are private and change over time, so use them as illustrations of ideas, not as exact descriptions.
Large technology companies
Staged launches by group
Large social networks are widely known to release new features to employees first, then to small slices of users, then wider. Group membership depends on facts about each account, which is the same idea as traits and segments.
Experiments on stable groups
Streaming services run many controlled experiments on artwork, rows, and playback. Each viewer must stay in the same variation, so a stable identifier decides the group.
Region and marketplace rules
A global shop must vary behaviour by country, language, and marketplace. Facts like location and account type decide what each customer sees.
Gradual rollouts
Browsers and apps roll out updates in small percentages, watch health signals, and widen slowly. Stable hashing of an identifier is the standard way to pick the percentage.
Continuous delivery with flags
These companies helped popularise dark launches, where a feature is deployed but visible only to chosen groups, before the wider public sees it.
Careful entitlement
Financial apps combine flags with server-side checks, so presentation can be rolled out gradually while access to money is always verified on the server.
A famous warning: Knight Capital
In 2012, the trading firm Knight Capital lost a very large sum in under an hour after a deployment went wrong. Reports said that old code, controlled by a switch that had been reused for a new purpose, was accidentally activated on one of its servers. The lesson is not about traits directly. It is about control: switches must be named clearly, retired when finished, rolled out the same way everywhere, and watched closely. Old overrides, old traits, and reused names are the same kind of danger in smaller form.
An invented story to tie it together
Mira leads the platform team at a company that sells online cooking classes. Her team wants to launch live cooking chat. They follow these steps.
Decide the identity
They use the internal learner number after sign-in, and a random stored number before sign-in. They send the company’s school number as a trait for school accounts.
Write the dictionary
Five traits: plan, country, app_version, is_staff, signup_days. Each has a type and allowed values.
Build and test personas
Six personas cover staff, new premium learners, free learners, old app versions, a school account, and a visitor with no data. They test in Staging by traits, with no overrides.
Roll out in steps
Day one: staff only. Day three: premium learners in one country at ten percent. Day seven: thirty percent. Day ten: all premium learners on version 6 and above.
Watch and react
A dashboard shows chat errors per segment. On day eight, errors rise for one old app version. They add a condition to the segment to exclude it, and the problem disappears with no new release.
Clean up
After full launch, they remove the segment overrides, retire the percentage rule, and delete the one trait that no rule uses any more.
Use case: private details, public benefit
A health-information website wants to show a new reading layout only to older visitors who prefer larger text. A trait recording a medical condition would be risky and unnecessary. Instead, the app sends one derived trait, “prefers_large_text,” taken from a setting the visitor chose, and uses transient mode so nothing is stored. The rule is easy, the data is harmless, and the visitor’s privacy is respected.
23Frequently Asked Questions
Short answers to the questions beginners ask most.
Do I need identities to use Flagsmith?
No. Without an identity you receive the environment’s default states. Identities become necessary when you want segments, stable percentages, experiments, or personal overrides.
Is a trait the same as a segment?
No. A trait is a fact about one person. A segment is a group defined by rules that read traits. Traits are the ingredients, and segments are the recipes.
Where are segment memberships stored?
They are not stored. Membership is worked out each time from the identity’s current traits and the segment rules, so changes take effect without any migration.
Can the same identifier exist in two environments?
Yes, and the two are separate records. Traits and overrides in one environment do not appear in the other.
Should I use the email address as the identifier?
Usually not. Emails are personal data, can change, and spread through logs and tools. A random internal number is safer and steadier.
What happens if I send a trait that no segment uses?
Nothing changes for the person’s flags. But you are storing and transmitting data for no reason, which adds cost and privacy risk. Send only what rules read.
Why does one user not match my segment although the trait looks right?
Check case, trailing spaces, and type, then check whether another segment or an identity override is winning. Reading the identity page usually reveals the cause.
Are traits updated immediately?
Traits are saved when your application sends them, and used from that request on. But your application must then refresh its flags to see the new result. Cached answers stay until refreshed.
Can a user fake a trait?
If the trait is set by code that runs on the user’s device, yes, in principle. Never use client-supplied traits as the only protection for paid or sensitive features. Verify on your server.
What is the difference between stored and transient traits?
Stored traits are remembered by Flagsmith for later requests. Transient traits are used to work out one answer and then forgotten. Check your Flagsmith version for exactly how to request each.
How many traits are too many?
There is no magic number, and limits depend on your plan or setup. A good rule is that each trait must be read by at least one rule, and that you can name its owner.
Should I use many overrides or one segment?
If the same exception applies to more than a few people, create a cohort trait and a segment. Keep overrides for true one-off cases, with a reason and an end date.
What if Flagsmith is unreachable?
Your application should keep working using flags kept in memory or built-in defaults. Design every flag so that its default is safe.
How do I handle a deletion request from a customer?
Remove the identity and its traits in every environment, check connected systems and logs, and follow your legal team’s process. Plan this before the first request arrives.
24Summary and Key Takeaways
We began with a shopkeeper who treats a regular customer differently from a stranger. We end with a system that does the same for millions of people, safely.
An identity is the name by which Flagsmith knows one user, device, or account in one environment. A trait is a small fact about that identity, such as plan, country, or app version. Segments are saved groups defined by rules over traits, and membership is worked out fresh each time. Flagsmith then evaluates in layers: a personal override first, then the highest-priority matching segment, then a multivariate choice by stable hashing, then the environment default. The first layer with something to say wins.
Because traits describe people, they must be designed, documented, kept fresh, tested through personas, and protected. Most failures come from small disagreements in spelling, type, and ownership, which a trait dictionary and a single trait builder prevent. Most risks come from collecting too much, so send the minimum, use opaque identifiers, prefer derived facts, and never let a client-supplied trait be the only gate for money or safety.
Key Takeaways
- An identity says who is asking, and traits say what they are like. Together they let one feature give many right answers.
- Choose a unique, stable, opaque identifier, and decide the anonymous-to-signed-in story before you write code.
- Keep a trait dictionary and one trait builder, so keys, types, and spellings never drift apart across platforms.
- Flagsmith evaluates in layers: identity override, then segment by priority, then multivariate hash, then the default.
- Use segments for groups and overrides only for rare exceptions, each with a reason and an end date.
- Send only traits a rule reads, protect privacy with derived facts and transient mode, and verify paid access on your server.
- Test with named personas, always including the visitor with no data, in every environment, and keep safe defaults for every flag.