Creating Custom Conditions Using Twig Templates
A Custom Condition lets you write your own test in Twig when the built-in conditions don't cover it. Add a Condition step, choose Custom Condition, give it a Condition Title, and write your template in Custom Twig Code.
The rule is simple: the condition passes if the rendered output contains the word true (any capitalization). Print nothing, or print false, and it fails. Keep the output to just true or nothing, so text from a product title or tag can't accidentally match.
Let Mr. Arigato write it
Mr. Arigato is the AI assistant built into the workflow editor. It knows Arigato's tokens and every filter in this app, which general-purpose AI tools don't. Describe what you want in plain English, for example "pass if any line item has the tag preorder", and paste the result into Custom Twig Code.
- Canvas workflows: select the Custom Condition, then open the Mr. Arigato tab in the editor's side panel.
- Classic workflows: click the magic wand icon on the Custom Condition card. A chat window opens.
If you already have code from ChatGPT or another tool, paste it in and ask Mr. Arigato to convert it to Arigato Twig. Most pasted code is Liquid, which looks similar but won't run here (see the next section).
Arigato uses Twig, not Liquid
Shopify themes use Liquid. Arigato uses Twig. The two look alike and AI tools mix them up. If you get an error like Unexpected token "punctuation" of value ":", you have Liquid syntax.
| Liquid | Twig |
|---|---|
{% assign x = 5 %} |
{% set x = 5 %} |
{{ qty | plus: 2 }} |
{{ qty + 2 }} or {{ qty | plus(2) }} |
{{ x | default: "none" }} |
{{ x | default("none") }} |
{% if tags contains "sale" %} |
{% if "sale" in tags_array %} |
{% if a != b %} (!== is invalid) |
{% if a != b %} |
{% elsif %} |
{% elseif %} |
{{ s | upcase }} |
{{ s | upper }} (upcase also works) |
Product recipes
Product has a tag starting with a prefix (for example color:)
{% for tag in product.tags_array %}
{% if tag[:6] == "color:" %}true{% endif %}
{% endfor %}
tag[:6] is the first six characters. Change the number to match your prefix length.
Product has both tags
{{ "VIP" in product.tags_array and "Wholesale" in product.tags_array ? "true" : "false" }}
Any variant is in stock
{% for variant in product.variants %}
{% if variant.inventory_quantity > 0 %}true{% endif %}
{% endfor %}
Any variant price ends in .77
{% for variant in product.variants %}
{% if variant.price | slice(-3) == ".77" %}true{% endif %}
{% endfor %}
Product was created in the last 90 days
{{ product.created_at | date("U") > "-90 days" | date("U") ? "true" : "false" }}
Title or vendor contains a word
{% if "Shirt" in product.title or "Shirt" in product.vendor %}true{% endif %}
in is case-sensitive. For a case-insensitive match use {% if product.title | icontains("shirt") %}.
Inventory is 10 or less, or over 100
{% if product.inventory_quantity <= 10 or product.inventory_quantity > 100 %}true{% endif %}
Published in a given year, or has exactly one tag
{{ product.published_at | date("Y") == "2019" ? "true" : "false" }}
{{ product.tags_array | length == 1 ? "true" : "false" }}
Order recipes
Any line item SKU is in a list
{% set wanted = ["ABC-1", "DEF-2", "GHI-3"] %}
{% for item in order.line_items %}
{% if item.sku in wanted %}true{% endif %}
{% endfor %}
Every line item SKU is in a list (the order contains only these products)
{% set wanted = ["ABC-1", "DEF-2"] %}
{% set all = true %}
{% for item in order.line_items %}
{% if item.sku not in wanted %}{% set all = false %}{% endif %}
{% endfor %}
{{ all ? "true" : "false" }}
Every line item's product has a tag
{% set all = true %}
{% for item in order.line_items %}
{% if "preorder" not in item.product.tags_array %}{% set all = false %}{% endif %}
{% endfor %}
{{ all ? "true" : "false" }}
item.product is the full product, so item.product.tags_array, item.product.vendor and item.product.metafields all work. Check the product title with item.product.title, not item.title, which is the variant title.
Shipping method contains "same day" (case-insensitive)
{% for line in order.shipping_lines %}
{% if line.title | icontains("same day") %}true{% endif %}
{% endfor %}
A note attribute is present
{% if order.note_attributes["eBay Order ID"] is not empty %}true{% endif %}
Note attributes are keyed by name, so use the name in square brackets. To test the value: {% if order.note_attributes["Gift"] == "yes" %}.
Order has products from two or more vendors
{% set vendors = [] %}
{% for item in order.line_items %}
{% if item.vendor not in vendors %}{% set vendors = vendors | merge([item.vendor]) %}{% endif %}
{% endfor %}
{{ vendors | length >= 2 ? "true" : "false" }}
Line item is assigned to a specific location
{% for fo in order.fulfillment_orders %}
{% if fo.assigned_location_id == 64207585395 %}true{% endif %}
{% endfor %}
Find the location ID in Shopify under Settings, Locations (it's in the URL).
Time recipes
It's after 8:30 in a timezone
{{ "now" | date("H:i", "Asia/Kolkata") > "08:30" ? "true" : "false" }}
Leave the timezone out to use your store's timezone.
It's a weekend
{{ "now" | date("N") in ["6", "7"] ? "true" : "false" }}
N gives 1 for Monday through 7 for Sunday.
Order is older than 3 business days
{{ order.created_at | date("U") < "-3 weekdays" | date("U") ? "true" : "false" }}
Using variables
Workflow Variables and Global Variables are available in any Custom Condition:
{% if order.total_price > workflow_vars["threshold"].value %}true{% endif %}
{% if product.vendor in global_vars["blocked_vendors"].value | split(",") %}true{% endif %}
Values stored in the Arigato Database: {{ shop.database["my_key"] }}.
Debugging a condition that never passes
- Add a Log a message action before the condition with
{{ order | debug }}(orproduct,customer). It prints the full object as JSON in the workflow logs, so you can see the real field names and values. - In Canvas workflows, check the Activity page. A skipped item shows which condition failed.
- Print the value you're comparing:
{{ order.note_attributes["Gift"] }}on its own, then look at the log. - If you set a variable inside a
{% for %}loop and read it after the loop, declare it before the loop first ({% set all = true %}). Twig drops variables that are first created inside a loop. - Compare the right object. Inside an order,
item.titleis the variant title; the product title isitem.product.title. - Other apps may add tags or metafields a few seconds after Shopify sends the webhook. If a condition passes when you test it by hand but fails live, add a short Wait step before it.
Filters you'll use most
| Filter | Example | Result |
|---|---|---|
icontains |
{{ title | icontains("shirt") }} |
true if found, ignoring case |
in (operator) |
{{ "sale" in product.tags_array }} |
true if present (case-sensitive) |
slice / [a:b] |
{{ sku[:3] }}, {{ price | slice(-3) }} |
first 3 chars, last 3 chars |
split |
{{ "a,b,c" | split(",") }} |
list |
length |
{{ order.line_items | length }} |
count |
date |
{{ order.created_at | date("Y-m-d", "America/New_York") }} |
formatted date |
date_modify |
{{ "now" | date_modify("-7 days") | date("Y-m-d") }} |
shifted date |
default |
{{ product.metafields.custom.size.value | default("one size") }} |
fallback when empty |
plus, minus, times, divided_by |
{{ price | times(0.8) }} |
arithmetic |
merge |
{{ list | merge(["x"]) }} |
combined list |
map |
{{ order.line_items | map("sku") }} |
list of one field |
to_json, debug |
{{ order | debug }} |
JSON for logs |
raw |
{{ text | raw }} |
unescaped HTML |
The complete list of filters and functions is in the app under Code Reference.