A feature in Union is a funnel built from events your code declares: people who saw it, people who started it, people who finished it. Declaring it in code is a definition, not a suggestion — a build from TestFlight or the App Store creates the feature in the panel.
Declare a feature
let checkout = Union.feature("checkout")
checkout.screen("Checkout") // discovery
checkout.start("checkout_started") // start
checkout.use("shipping_selected") // use
checkout.success("order_placed", properties: ["items": 3]) // success
checkout.failure("payment_failed", properties: ["reason": "card_declined"]) // failureDefine each feature key once (a constant or a static handle) and reuse it — a typo creates a second feature.
Roles
| Role | Meaning |
|---|---|
| discovery | Saw that the feature exists and has not tried it yet. feature.screen(…) sets it for you. |
| start | Made an attempt whose outcome is not known yet. The funnel’s denominator — without it there is no funnel. |
| use | Working inside the feature; may happen many times per attempt. Counted towards adoption, not a step of its own. |
| success | The feature gave the person what they came for. Once per attempt. |
| failure | The attempt failed from the person’s point of view: permission denied, no results, a save that did not happen. |
The funnel in the panel has three steps — Discovery → Adoption → Success — where adoption counts everyone who started or used the feature.
Rules the server enforces
- One event name is one (feature, role) pair everywhere in the code. The same name as
successin one place andfailurein another is a conflict the panel shows and never resolves for you. - Giving up is its own event name (
onboarding_abandoned), not a property on the completed event. - A feature is something a person can fail to adopt. A core surface everyone touches on day one (
home,items) reports 100% adoption and says nothing — send those events without a feature. - Declare only what you instrument. A declared feature nothing emits reads as zero adoption.
A DEBUG build only pre-fills the feature editor, so experimenting locally never adds features to the panel. Declarations from TestFlight and App Store builds do.
Changing a feature later
The SDK only ever adds: a new event or role in a later build joins the feature, and nothing you set in the panel is removed or overwritten. A feature you created by hand with the same name is adopted instead of duplicated. When the panel’s definition changes, history is recomputed from the raw events.
Suggestions
Events you did not declare are grouped by name (comment_opened, comment_posted → comment) into suggestions. Nothing is created until you approve one under Features → Review.
Updated Oct 23, 2026 · Markdown