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 }} (or product, 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.title is the variant title; the product title is item.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.