- How to build a condition.
- How operators differ by attribute type.
- How multi-value attributes and trigger outputs behave.
- The
and/ormistake that lets the wrong records through. - Where to place conditions for the lowest cost.
Building a condition
A condition is three parts in order: an attribute, an operator, and a value. You pick the attribute to read, choose how to compare it, and supply the value to compare against. The simplest useful condition gates a Filter so that only the records you care about continue. Consider a workflow on a deal that should proceed only for won deals. Add a Filter immediately after the trigger and configure one condition:
A deal sitting at
Won passes the Filter and the run continues. A deal at Negotiation stops at the Filter, and nothing downstream executes.
To combine tests, chain conditions with and or or. Conditions joined by and must all be true. Conditions joined by or need only one. For logic that mixes the two, such as (A and B) or (C and D), open the condition’s three-dot menu and choose Convert to advanced condition to create a nested group. Nested groups are the only correct way to express mixed precedence. The next sections show why a flat list gets it wrong.
Choosing operators by attribute type
The operators Attio offers depend on the attribute’s type, because comparing text is not the same as comparing a date. You will not findcontains on a number, and you will not find greater than on a status. This table lists the operators available per type.
Suppose you want only enterprise-sized deals to continue. On a
Deal value currency attribute, configure the condition with the greater or equal to operator and the value 50000:
A deal worth 12,000 stops at the Filter. The
empty and not empty operators exist on every type, which is how you guard against missing data. For example, Owner is not empty keeps a routing step from running on an unowned record.
Matching multi-value attributes
Some attributes hold more than one value at once. Multi-selects and multi-reference relationships are the common examples. Attio evaluates a condition against the whole set, and a condition is true if any one value in the set matches. There is no built-in operator that requires every value to match. Take aTags multi-select that can hold Customer, Partner, and Champion on the same record. A condition checking that set behaves like this:
A record tagged
Partner and Customer passes, because one of its tags is Customer. A record tagged only Partner does not. Sometimes you genuinely need the opposite rule, where every value must match. An example is “all tags are in my approved set.” No condition operator does that. Instead, evaluate the rule in an Execute code block and branch on its true-or-false output. The Execute code block costs Variable (complexity-based).
Testing trigger and block outputs
Conditions are not limited to record attributes. A condition can read any output produced by an earlier block in the path. That includes the trigger’s new and previous values, a parsed webhook field, or a match count from a Find block. This turns Filter from a simple record gate into a precise guard. It catches the bugs that show up when a workflow reacts to an event, such as a save firing more than once. The most valuable pattern is the true-transition guard. An attribute-change trigger fires on every save, including re-saves that do not actually change the value you care about. Pair two conditions withand to fire only on a real transition into Won:
A deal moving from
Negotiation to Won passes both conditions, and the run proceeds once. A deal already at Won that is saved again fails the second condition and stops. The same technique builds the standard infinite-loop guard. A condition of Updated by type is not Workflow keeps a workflow from re-triggering on its own writes. After a Parse JSON block, you can route a Switch on any field in the parsed payload.
Avoiding the and/or trap
Mixingand with or in a flat condition list is the single most common way a filter passes records it should not. A flat list does not carry parentheses. The engine applies its own precedence, and the result rarely matches how you read the line. The classic broken filter reads like this:
You probably meant “the deal is closed (won or lost) and owned by Priya Sharma.” Written flat, theStage is WonorStage is LostandOwner is Priya Sharma
and binds tighter. So the filter actually passes any won deal regardless of owner, plus lost deals owned by Priya Sharma. To get the intended logic, convert to an advanced condition and build a nested group: an outer and joining Owner is Priya Sharma with an inner or group of (Stage is Won or Stage is Lost).
Now a won deal owned by jane@acme.com fails, and only Priya Sharma’s closed deals pass. When a filter lets through records it should not, check the
and/or structure first. Attio’s own troubleshooting guidance points to the same culprit.
Placing conditions for lowest cost
Where you put a condition decides what the rest of the workflow costs. Conditions are free. The AI, HTTP, sequence, and write blocks behind them are not. The rule is to put your cheapest, most selective check immediately after the trigger, so the run stops before it reaches anything billable. Compare two shapes of the same workflow. With the Filter first, the Filter stops the run on the 95% of events that do not qualify, and those runs cost nothing because no paid block downstream ever executes. With the web agent first, the agent runs on every single event, and you pay for it before the Filter ever discards the result. Front-loading the Filter is free and saves the entire downstream bill on every run that does not matter. For the per-block credit figures behind that math, see Credits & pricing explained.First match wins, and an empty Default stops silently. A Switch evaluates its cases in order and runs only the first true path, so order cases from most to least specific. If no case matches and the Default path is empty, the run ends quietly at the Switch. Connect a Default (even just a Slack ping) whenever “none matched” should do something.
See also
Source: Attio Workflows block library. Last reviewed against the Attio Help Center, June 2026.