Features  /  Targeting

Targeting

Targeting decides, user by user, what a feature flag shows: on for your testers, on for 10% of everyone, on for one plan, hidden for the rest. You write it as one sentence per flag — for example Beta for Testers + 10% of everyone · others: Hidden — and Onelo turns that sentence into a status your app reads. This page covers the whole model: what decides a user's status, every kind of rule, percentage rollout, groups, recipes, what changes without a paywall, who counts as a known user, how changes reach your app, the same work through MCP, and how to debug a surprise.

The model in one minute

A flag is one feature your code asks about by name. A pack is a named set of flags (see Packs); a rule on a pack applies to every flag in it. Each flag has a status per environment, set in the Registry. How plan rules gate a fixed status is on Plan access.

Flag statusWhat it means
activenewbetacoming_soongreyedhiddenA fixed status: everyone gets the same answer and person, group and percentage rules are not read. With the paywall on, plan rules can still gate a fixed status other than hidden.
targetedAsk the rules. Every rule of the flag (and of its packs) is read for each user, in the order below, and the first match decides.

A rule gives a matching user one visibility. Your app receives it as the flag's status: enabled new beta coming_soon greyed (shown as Locked) upsell hidden. Only a plan rule may give upsell: it points at a purchase, and buying a plan never changes a person, group or percentage match. Users no rule matches get the flag's others see value: Hidden, Upsell or Locked.

Targeting is available on paid Onelo plans. On Free, switching a flag to targeted or adding any rule returns 402; fixed statuses work on every plan.

How one user's status is decided

For a targeted flag, Onelo walks these steps for the user asking and stops at the first one that answers:

Step 1
Suspended?
A banned user gets hidden. Nothing else is read.
Step 2
Person rules
A rule naming this user, on the flag or on one of its packs. First in order wins.
Step 3
Group rules
The first group rule, in order, whose group has this user as a member.
Step 4
Plan and percentage rules
In order: a plan rule for the user's plan, or a percentage the user's bucket falls inside.
Step 5
Others see
Nothing matched: Hidden, Upsell or Locked, as set on the flag.
1

Suspended user

A banned user gets hidden for every targeted or plan-gated flag.
2

Person rules win over everything below

A person rule (also called a per-user override) is keyed to one user's id. Rules on the flag and on the packs it belongs to form one ordered list; the first that names this user decides.
3

Group rules come before any plan or percentage rule

Group rules are checked as a set before plan and percentage rules, wherever they sit in the list. If the user is in several groups with rules, the first of those rules in order decides.
4

Plan and percentage rules, in order

The first rule that matches wins: a plan rule matches users on that plan; a percentage rule matches users whose sticky bucket is below the percentage (and, for a percentage of a plan, who are on that plan).
5

Others see

With the paywall on, a non-hidden others-see value carries the cheapest higher plan that unlocks the flag, which your app shows as "Available in Pro". Without a paywall it behaves differently — see Paywall off vs on.
Steps 2 and 3 need a known user, and so does a percentage. An anonymous caller — nobody signed in, or an unverified user id while Require verified users is on — skips person, group and percentage rules. It has no plan either, so it lands on others see.

Every rule kind, worked through

Each row is one flag with a single rule and others see: Hidden, with the paywall on. The answer in brackets is the reason Inspect shows.

RuleMatching userSigned-in user it does not matchAnonymous caller
PersonBeta for [email protected]Ana: beta (user_override)hidden (default)hidden (default)
GroupBeta for TestersA member of Testers: beta (group)hidden (default)hidden (default)
PlanPro plan onlyA Pro user: enabled (plan)A Free user: hidden (default)hidden (default)
Percentage of everyone10% of everyoneA user whose bucket is 0–9: enabled (rollout)A user whose bucket is 10–99: hidden (default)hidden (default), even at 100%
Percentage of a plan10% of Free planA Free user whose bucket is 0–9: enabled (rollout)A Free user above the bucket, or a user on another plan: hidden (default)hidden (default)

Change others see to Upsell and every "hidden (default)" above becomes upsell (reason plan) pointing at the cheapest plan above the user's own that a plan rule turns on — when there is one. When no higher plan unlocks it, the user gets greyed with no upgrade hint, so nobody is told to buy a plan that would not help.

Inspect names the matched condition: group with the group ("member of Testers") and rollout with the percentage ("in the 10 % rollout of Free"). Your app's SDK knows a fixed set of reasons, so on the wire a group match arrives as user_override and a percentage match as plan; the status is the same.

Target a feature at one user

A person rule — a per-user override — gives one user their own answer. In the editor, add a rule for a person and type their e-mail; the address must belong to a user of your app. Because person rules are read before groups, plans and percentages, it is the precise tool for early access ("turn this on for these two testers") or an exception ("this QA account gets everything") without changing what any plan grants. The rule is keyed to the user's Onelo id, which the SDK knows once they sign in. For more than a handful of people, a group is easier to keep up to date.

Percentage rollout

A percentage rule turns a flag on for a share of users — of everyone, or of one plan. Each user has a bucket from 0 to 99 for each flag or pack, computed from your app, the flag (or pack) and the user id. A user is in the rollout when their bucket is below the percentage.

  • Sticky. The same user gets the same bucket on every call, on every device and after every deploy, because it depends only on the user id and the flag.
  • Raising keeps everyone in. Going from 5% to 25% to 100% only adds users: a bucket below 5 is also below 25. Lowering the percentage takes out the users above the new value. A user with bucket 74 is out at 74% and in at 75%.
  • Per flag. Buckets differ between flags, so the same 10% of users is not in every 10% rollout. A rule on a pack uses the pack's bucket for all its flags.
  • Deleting and re-creating keeps the same users, since the bucket does not depend on the rule.
  • Anonymous callers are never in, not even at 100%. Only a known user id is bucketed.
  • Percentage of a plan. 10% of Free matches Free users in the bucket and nobody else. 100% of a plan is saved as that plan's plain plan rule; 100% of everyone stays a percentage rule, so anonymous callers still stay out.
  • The editor offers 1, 5, 10, 25, 50 and 100% as one click, or any whole number from 1 to 100. One flag has at most one percentage rule per plan and one for everyone; setting it again changes the number in place.

Groups

A group is a named list of your app's users — Testers, Pilot customers — that any number of rules can name, on any flag or pack, in both environments. The Groups bar at the top of the Targeting tab lists them with their member counts.

  • Testers is there from the start. Every app has a default Testers group, and you are in it once you have an account in your app: the group starts with you if you already have one, and otherwise you join it automatically when you sign up to your app with your Onelo account’s e-mail address. Until then it shows Testers (0). Remove yourself and you stay removed.
  • Create a group with a name of up to 100 characters.
  • Add members by searching, or paste a list of e-mail addresses (up to 500 per change). Addresses that are not users of the app are listed back and skipped; the rest are saved. Members are Onelo users of this app — a group cannot hold an id your app made up.
  • Remove a member the same way.
  • Rename a group, Testers included. Rules name a group by its id, so they keep working under the new name and there is nothing to deploy.
  • Delete a group only once no rule names it, in either environment. While one does, Onelo refuses and lists those flags and packs: remove their group rules and deploy first. So deleting a group never changes what anyone sees. Its member list goes with it and cannot be restored. The default Testers group cannot be deleted.
  • Membership applies at once, in both environments, with no deploy. Apps connected over the live stream re-read the changed users' features straight away. The group rules themselves are per environment and deploy like every other rule.

The who-sees-it editor

The Targeting tab lists your flags, each with one sentence saying who sees it, then your packs. Open a flag with edit — or click its name in the Registry — to change the sentence in place:

  • Each row reads [visibility] for [condition]. Add a rule and choose its condition: a person (by e-mail), a group, a plan, or a percentage of everyone or of a plan. Plan rules need a plan your products grant, so with no products the plan choice is unavailable.
  • Others sets what users no row matches see: Hidden, Upsell or Locked. With Upsell or Locked, a checkbox — Tapping it opens the upgrade flow — decides whether the app offers the purchase when the user taps the locked feature.
  • While a flag has no rules, the editor offers recipes that fill it in one click (see below).
  • Order. The rows read in the order users are checked: people first, then groups, then plan and percentage rules. Within groups, and within plans and percentages, the first match decides, so the arrows beside a row move it up or down among its own kind. A new rule goes last among its kind. Save stores the order shown; like any change it reaches users with the next release.
  • Save replaces the flag's whole rule set in the active environment in one step. If anything is refused, nothing is saved: an address that is not a user of the app, the same plan, group or person twice (a plan and a percentage of that plan count as the same), a plan your products do not grant, a plan one of the flag's packs already grants, or more than 200 rules.
  • The first rule makes the flag targeted, whatever fixed status it had. Removing the last rule asks which fixed status (active, new, beta, coming soon, greyed, hidden) it returns to.
  • People are counted in the sentence, never named: Beta for 2 people · others: Hidden.
  • A pack's sentence is edited the same way. Group and percentage rules on a pack need every flag in the pack to be targeted in that environment first.
SentenceReads as
EveryoneFixed status active: no rules read. With the paywall on and no plan rule, it is locked for everyone (see below).
Hidden for everyoneFixed status hidden.
Beta for Testers · others: HiddenMembers of Testers get beta; everyone else hidden.
Pro plan only · others: UpsellPro users get it on; everyone else sees the upsell.
Beta for Testers + 10% of Free plan · others: HiddenTesters and a sticky 10% of Free users get beta; the rest hidden.

Recipes

A recipe writes a known rule set into the editor; you still review and Save. Each one writes exactly this:

RecipeRulesOthers seeFlag status
Only me & testersTesters group → betaHiddentargeted
Gradual 5→100%5% of everyone → enabled (raise it later)Hiddentargeted
<plan> plan onlyThat plan → enabled (one recipe per plan your products grant)Upselltargeted
EveryoneNo rulesunchangedactive

Paywall off vs on

Without a paywall there are no plans to buy, so only the plan dimension goes inert. Statuses, people, groups and percentages of everyone keep working, which is how you run a closed beta in an app that sells nothing.

For a targeted flagPaywall onPaywall off
Person, group or percentage-of-everyone rule matchesThat rule’s visibilityThat rule’s visibility
Plan rule, or percentage of a plan, matches the user’s planThat rule’s visibilityenabled (paywall_off), whatever the rule says
Nothing matches, others see Hiddenhidden (default)hidden (default)
Nothing matches, others see Upsell or Lockedupsell / greyed, with the plan that unlocks itenabled (paywall_off) — for everyone, anonymous included
Fixed status other than hiddenWith no plan rule: locked for everyone (paywall_no_plan). With a plan rule: users whose plan has a rule get it, everyone else gets others seeThe fixed status
Fixed status hiddenhiddenhidden
The sentence does not know about the paywall. It describes the rules, not the answer, so with the paywall off Pro plan only · others: Upsell is on for everyone, a plan rule of Beta or Hidden answers enabled, and with the paywall on Everyone is locked while no plan rule grants the flag. Check a user in Inspect when in doubt.
Without a paywall, others see: Upsell or Locked means on for everyone — there is no plan to sell, so there is nothing to lock. To keep a flag to your testers, set others see to Hidden.

Identity: who is asking

Person, group and percentage rules, and plans, all need to know the user. On client platforms the signed-in Onelo Auth user is that identity; a backend passes the user id with the secret key (see SDK integration). A caller with no user is anonymous and gets others see.

Your publishable key ships inside your app and is public, so by default a request that simply names a userId is trusted — anyone holding the key could ask for another user's features. Require verified users for Features (Dashboard → Applications → your app → Security → Features user verification) closes that: a publishable-key request that names a user without a valid Onelo sign-in token is answered as anonymous — no person, group, percentage or plan match. It is off by default. Secret-key calls from your backend are unaffected, and a request that sends a token that fails to verify is refused with 401 invalid_user_token rather than quietly downgraded.

Turn it on once your users run an SDK version that sends the token with every Features call:

SDKFirst version that sends the token
JavaScript (@onelo/js)0.60.0
Electron0.48.0
React Native0.40.0
Swift3.88.0
Android1.42.0
Flutter1.39.0

Server SDKs (Node, Python, PHP) use the secret key and are not affected. The Security page shows how many requests in the last seven days named a user without a token, and from which SDK versions, so you can see who would lose their targeted features before you switch it on. The switch reaches every server within about a minute.

Test and Live, deploy, promote, discard

  • Two environments. Each flag's status, others see and rules exist separately in Test and Live. Groups and their members are shared by both.
  • Staged, then deployed. Every edit is staged: the dashboard shows it, your app does not. The pending counter tells you there is undeployed work, and Inspect shows deployed → staged for anything that will change.
  • Deploy publishes one environment. Removing an already-deployed rule is soft until then: the app keeps it, and adding it back before you deploy recovers it.
  • Promote to Live copies Test's statuses, plan rules, packs and targeting — person, group and percentage rules included — into Live as staged changes. Deploy to Live publishes them. Live becomes a copy of Test: for each flag and pack it carries, Live's plan, group and percentage rules become Test's rules in Test's order. Rules that exist only in Live are removed (a deployed one stays in your app until you deploy Live), and a rule you removed in Test is not copied. Person rules are mirrored, and so are “others see” and the upgrade-flow setting. You can hold back parts of a promote in its preview; what you hold back stays as it is in Live.
  • Discard changes throws away one environment's staged edits; what your app sees does not change.
  • How fast it arrives. A deploy moves the environment's version: apps on the live stream get the new answer right away, apps on the polling fallback on their next poll, offline apps when they reconnect. Group membership and purchases do not need a deploy; the changed user's apps on the live stream re-read at once. An app on the polling fallback may not see it until it starts again or the environment is deployed.

More on each step in Environments & Promote.

Doing the same through MCP

An agent connected to Onelo's MCP server does the same work with the feature_targeting tools. Every call that works on one environment names it (env: test or live). Rule writes are staged exactly as a dashboard edit is: by default they need no approval of their own (you can require one for any write in your MCP settings) and reach nobody until a release. Groups and their members apply at once, in both environments.

TaskOperation
See every rule, group, others see and overridefeature_targeting.get_state
Set who sees one flag or pack in one step, or apply a recipefeature_targeting.set_who_sees_it — rules, or recipe testers / gradual / plan_only / everyone; removing the last rule needs fixed_status
Roll out to a percentagefeature_targeting.set_rollout — percent 1–100, optional plan
Create a group, add or remove membersfeature_targeting.create_group, feature_targeting.set_group_members — applies at once, unknown addresses listed back
Rename or delete a groupfeature_targeting.rename_group, feature_targeting.delete_group — a delete is refused while any rule names the group
Give a group a visibilityfeature_targeting.set_group_rule
Give named people their own answerfeature_targeting.set_user_override — by e-mail; one unknown address saves nothing
Plan rules: add, edit, remove, orderset_plan_rule, update_rule, delete_rule, reorder_rules — or send set_who_sees_it the rules in the new order: it stores the order it is given
Check what one user gets, staged and releasedfeature_targeting.inspect_user
Publishfeatures.release — always waits for you to click Approve in the Onelo panel
Copy Test into Live, or throw away staged editsfeatures.promote (read features.get_promote_preview first), features.discard_changes

set_rollout and set_group_rule refuse a flag in a fixed status other than active (an active flag becomes targeted with the first rule); set_user_override needs the flag targeted already. Switch it with features.set_flag_state first, or use set_who_sees_it, whose first rule makes any flag targeted. features.promote needs hold_back: the agent shows you each change in the preview and asks which to hold back ([] moves everything). Called without it, promote moves nothing and returns the list to ask about. The approval for features.release lists every change it publishes. The dashboard and MCP go through the same server code, so a rule set written in one reads the same in the other and both refuse the same things.

Reading it in your app

Your code never sees rules — only the resolved status per flag for the current user. Read it by status (isEnabled, isVisible, …), wait for the SDK to be ready before the first paint so a targeted flag does not flash, and let updates arrive on their own: over the live stream, a deploy, a membership change or a purchase reaches the app without a restart. Setup, identity per platform and the helpers are in SDK integration.

Troubleshooting: a user sees X, I expected Y

Start with Inspect: search the user by e-mail in the environment their app reads. It shows the status they get, the reason, and — for a group or percentage — which one matched.

What you seeLikely cause
Inspect shows deployed → stagedThe change is not deployed yet. Deploy that environment.
Reason staticThe flag has a fixed status, so rules are not read. Save a rule to make it targeted.
Reason default for a user you targetedNo rule matched: check the rule is in this environment (Test vs Live), the user is in the group, their plan, or that their bucket is below the percentage.
Right in Inspect, wrong in the appThe app reads the other environment, or calls anonymously — not signed in, or an SDK too old to send the token while Require verified users is on.
A group member gets the group’s answer despite a plan rule above itGroup rules are read before plan and percentage rules, wherever they sit.
One person differs from their groupA person rule wins over group rules.
Everyone gets it without a paywallOthers see is Upsell or Locked; without a paywall that means enabled. Set it to Hidden.
Locked with no upgrade hintNo plan above the user’s own turns the flag on, so there is nothing to upsell.
Reason suspendedThe user is banned.

Next

Targeting — Features — Onelo Docs