Targeting
Targeting rules are set per form in Share → Mobile app. The SDK downloads them with its configuration and evaluates them on the device. Nothing about the user is sent to a server to make the decision.
From trigger to survey
Section titled “From trigger to survey”- Your app calls
trackorscreen, or the app launches. - The SDK collects the surveys with a matching trigger. See Track events & screens.
- Each of them goes through the eligibility checks below. The first eligible survey is selected.
- If the survey has a delay, the SDK waits. When the delay ends it runs the checks again, and for a screen trigger it also checks that the user is still on that screen.
- The display guard, if you set one, gets the last say.
- The survey loads in the background and appears once it is ready.
Every matched survey that does not make it produces a surveyNotShown callback with a reason, and a line in the debug log.
Order of checks
Section titled “Order of checks”The checks run in this order. The first one that fails gives the reason.
| # | Check | Set in the Mobile app tab | Reason when it fails | Triggers | showSurvey |
|---|---|---|---|---|---|
| 1 | Tracking is enabled | disabled | yes | yes | |
| 2 | The Survey ID exists and its channel is on | Channel switch | survey_not_found | yes | |
| 3 | No other survey is visible or waiting for its delay | another_survey_visible | yes | yes | |
showSurvey with force stops here and shows the survey | |||||
| 4 | Targeting is not paused | paused | yes | no | |
| 5 | Now is inside the schedule | Schedule: from, until | outside_schedule | yes | yes |
| 6 | The platform is selected | Audience: platforms | platform_mismatch | yes | yes |
| 7 | The app ID is listed | Audience: app IDs | app_mismatch | yes | yes |
| 8 | The language is listed | Audience: languages | locale_mismatch | yes | yes |
| 9 | The user is identified, or not, as required | Audience: identified / not identified users | audience_mismatch | yes | yes |
| 10 | User-attribute conditions hold | Audience: conditions, all / any | audience_mismatch | yes | yes |
| 11 | Frequency allows another display | Frequency | already_completed, frequency_limit, recontact_wait | yes | yes |
| 12 | The team-wide pause between surveys has passed | Frequency: pause between surveys | global_cooldown | yes | no |
| 13 | The install is inside the share of users | Audience: share of users | sampled_out | yes | no |
An empty audience setting means no restriction: no platforms selected is every platform, no languages is every language, no conditions is every user.
After selection, three more things can stop a survey: the user left the screen during the delay (screen_changed), the display guard said no (vetoed), or the survey could not be loaded (load_failed, survey_unavailable). All reasons are explained in Testing & debugging.
Audience
Section titled “Audience”Platforms and app IDs
Section titled “Platforms and app IDs”The platform is ios or android. React Native, Flutter and Unity apps report the platform they run on.
The app ID is the bundle identifier on iOS and the application ID on Android. The comparison is exact and case-sensitive. List app IDs when one team ships several apps, or to keep a survey out of a build with its own ID such as com.acme.app.debug.
Languages
Section titled “Languages”The SDK’s language is the value you set with setLocale, or else the device’s preferred language, as a tag like en-US.
An entry in the list matches when it equals the tag or is a prefix of it up to a hyphen. Case is ignored and _ counts as -.
| List entry | Device language | Match |
|---|---|---|
pt | pt-BR | yes |
pt-BR | pt-BR | yes |
pt-BR | pt-PT | no |
pt_br | pt-BR | yes |
Identified users
Section titled “Identified users”A user is identified when a user ID is set, that is after identify and before reset. The rule can require identified users, require users who are not identified, or accept both.
Conditions
Section titled “Conditions”Conditions compare user attributes (the traits from identify and setAttributes) with a value. With all, every condition must be true. With any, one is enough. Property conditions on an event trigger use the same operators against the properties of the track call, and all of them must be true.
| Operator | True when |
|---|---|
| exists | The attribute is set. |
| does not exist | The attribute is not set. |
| equals | The attribute is set and equal to the value. |
| does not equal | The attribute is not set, or is different. |
| contains | The attribute is set and its text contains the value. |
| does not contain | The attribute is not set, or its text does not contain the value. |
| greater than, greater or equal, less than, less or equal | The attribute is set and compares that way. |
How values are compared:
- Equals. Two numbers compare as numbers and two booleans as booleans. Anything else compares as text, ignoring case.
"Pro"equals"pro". - Contains. Ignores case. A number or boolean is treated as its text:
5,49.9,true. - Greater / less. Two numbers compare as numbers. So do strings that are plain decimal numbers, such as
"12.5". Two other strings compare as text, character by character and case-sensitive. A boolean never compares as greater or less. - Dates. A date attribute is stored as text like
2026-11-10T12:00:00Z, which sorts correctly as text. Enter dates in conditions in the same form, for example “signed_upless than2026-01-01T00:00:00Z”.
Share of users
Section titled “Share of users”The percentage is a stable sample of installs, not a dice roll on every trigger.
- Each install gets a fixed position from 0 to 99 for each survey, derived from the install ID and the Survey ID. The install is in the sample when its position is below the percentage.
- The answer for one install never flips between sessions, so a survey does not appear and disappear.
- Raising the percentage keeps everyone who was already in and adds more installs. Lowering it removes some.
- Different surveys sample different installs.
resetkeeps the install ID, so the position stays. Reinstalling the app creates a new install ID and a new position.- With few users the real share can differ from the percentage.
The share applies to triggers only. showSurvey ignores it.
Frequency
Section titled “Frequency”Frequency is counted per install. A display is counted when the survey becomes visible, whether the respondent answers or closes it. A survey that never became visible (vetoed, cancelled during the delay, failed to load) is not counted.
| Mode | Shown when | Then |
|---|---|---|
| Once | It has never been shown on this install. | Never again, completed or not. |
| Until completed | It has not been completed, the maximum number of displays is not reached, and the days between displays have passed. | Stops for good once completed. |
| Repeatedly | The maximum number of displays is not reached and the days between displays have passed. | Keeps coming back, also after a completed response. |
| Every time | The maximum number of displays is not reached. | Appears every time the trigger matches. |
Reasons you will see: already_completed (completed, in once or until completed), frequency_limit (already shown in once, or the maximum is reached), recontact_wait (the days between displays have not passed).
Pause between surveys
Section titled “Pause between surveys”One setting applies to the whole team: a number of hours that must pass between any two surveys shown by triggers, whatever the form. It keeps several active surveys from stacking up on the same user. A survey blocked by it reports global_cooldown.
The clock starts when a survey is shown by a trigger. Surveys shown with showSurvey neither wait for it nor restart it.
Schedule
Section titled “Schedule”A survey is eligible from the from time up to, but not including, the until time. Either bound can be empty. The device clock is used.
Several surveys on one trigger
Section titled “Several surveys on one trigger”When one call matches more than one survey, the SDK takes the first eligible one in the order of the configuration and reports the others as another_survey_selected. Do not rely on that order. If two surveys can match the same trigger for the same user, separate them with audience or frequency rules.
Only one survey is on screen at a time. A trigger that fires while another survey is visible or waiting for its delay reports another_survey_visible and is not retried later.
What showSurvey skips
Section titled “What showSurvey skips”showSurvey is your explicit request, so three checks do not apply to it: pause, the pause between surveys, and the share of users. The delay is skipped as well. Audience, schedule and frequency still apply.
With force, audience, schedule, frequency and the display guard are skipped too. See Show a survey manually.
State lives on the install
Section titled “State lives on the install”Display history, event counts and the sampling position are stored on the device, per install.
- A user with two devices can see a once survey on each.
reset(for example on logout) clears display history and event counts, so frequency starts over on that device.- Reinstalling the app clears everything.
When changes take effect
Section titled “When changes take effect”The SDK caches the configuration for about 10 minutes and refreshes it when the app starts or returns to the foreground with an expired cache. A change you save in the Mobile app tab reaches a device within that time. See Testing & debugging.