Skip to main content
Targeting is the set of rules that decide which experience shows, to whom, and when. Every dimension the trigger event, the audience, the schedule window, the frequency cap, and the optional LLM classifier is evaluated on the backend by ConversationRouterService. The browser SDK never makes this decision: it reports activity and identity, the server resolves eligibility, composes the widget, and pushes the finished result over Socket.IO. This page is the map of the targeting model; each dimension links to the concept page where the field semantics live.
Because eligibility is server-side, the browser cannot force a widget to show. You call notifyActivity() or send a message; the server decides whether anything appears. That is also why targeting only works when you feed it accurate identity and traits see Feed it data below.

How targeting is evaluated

When the server SDK observes a message, it posts the turn to the backend, which runs an ordered pipeline. The trigger type is resolved from the message role first; then audience narrows by trait rules; then the classifier (if configured) acts as an LLM gate; then schedule and frequency caps apply; and finally, among everything still eligible, the highest-priority experience wins. Only then is the widget composed (Anthropic claude-sonnet-4-6) and pushed to the browser. The dimensions are filters applied in sequence an experience must pass all of them to be shown. Reading the diagram top-to-bottom is the order they run in.

Triggers the event that makes an experience eligible

A trigger is the event that opens the window for an experience. The available triggers depend on the experience type: chat_open fires when the chat opens, after_user_message after the user sends a message, after_idle after a configured number of seconds of inactivity, and on_custom_event when your app emits a named event. Guides additionally support after_user_and_agent_message (after the user message and the agent’s reply). The idle timer is driven from the browser call notifyActivity() on keystroke, click, or send to reset it, otherwise after_idle will fire too eagerly. The most powerful trigger is conversation_classifier, which runs an LLM gate before showing the experience. You configure custom instructions, the provider and model, a confidence floor, a TTL, a resolution mode, the context window (how many turns the model sees), and signal masking (which data it sees). Use it for intent-driven experiences like “offer help when the user seems stuck” something no static rule can express. The full trigger table and classifier fields are documented in Triggers & audience.

Conditions & operators gate on traits and prior answers

Triggers can carry conditions that test user traits (traits.*) or prior survey answers (answers.<questionId>). Conditions are how you combine “this event happened” with “and this is true about the user,” for example: fire after_idle only when traits.plan equals free. The same operator set powers both trigger conditions and segment rules, so a rule you learn once applies everywhere.

Audience who is eligible

Audience targeting decides who can see an experience. The two modes are all (every user) and segment (only users in a named segment). A segment is a saved set of trait rules using the operators above computed by the backend against the audience directory. If a segment referenced by an experience is later deleted, targeting falls back to “all users” rather than showing nothing, so a deleted segment never silently hides an experience. Set an experience’s audience to a segment and only matching users qualify. The audience directory itself names, emails, traits, tags, session counts, and segment membership is populated entirely from the identity you send, which is why the Feed it data section below matters as much as the rules themselves.

Schedule, frequency, priority & placement

Beyond who and when, four settings shape delivery. Schedule controls the active window start now or at a date/time, with an optional expiration. Frequency caps how often a user sees an experience: once, limited (per session, day, week, or lifetime), or always (the default for guides). Priority breaks ties when more than one experience is eligible for the same turn, the higher priority wins and the rest are suppressed. Device narrows to all, desktop, or mobile, and placement controls where the widget renders (overlay, inline, above-composer, or full-page). These all live under the experience’s settings; see Triggers & audience for the per-mode detail.

Feed it data

Targeting is only as good as the traits you send segment rules and trait conditions can only match fields that actually exist on the user. Set identity early (on login) and update it whenever traits change, from either side of the connection:
Pass the same userId from both sides and the traits attribute to one user. The browser user prop and the server identify() helper write to the same audience record; the merged traits are what audience segments and traits.* conditions evaluate against. You can also update traits at runtime from the instance with ff.setUser({ id, traits }) see Identity & traits.

A worked example

Suppose you want to nudge free-plan users toward an upgrade guide, but only when they seem to be hitting limits. Combine the dimensions: a conversation_classifier trigger with the instruction “user is asking about usage limits or pricing” and a confidence floor; a segment audience whose rule is traits.plan equals free; a frequency cap of limited (once per day) so it never nags; and a high priority so it beats lower-value announcements competing for the same turn. The user types about hitting a quota, the server runs the classifier on the recent turns, confirms the segment match from the plan trait you sent, checks the daily cap, and if all pass composes and pushes the guide. None of that touches the browser until the finished widget arrives.

Next

Author the rules on the Triggers & audience and Audience & segments concept pages, then make sure your Identity & traits integration is sending the fields you target on.