Auto-tag orders by shipment status, with Mechanic.

Mechanic is a development platform for Shopify. :)

Auto-tag orders by shipment status

Easily segment your orders by shipment status. Tagging your orders as "Delivered", or "Out for delivery", or "Attempted delivery", or any other status, allows you to stay on top of your order flow. And, adding these tags makes it easier to wire up additional automation, keeping the connection live between your customers and their orders.

Runs when a fulfillment is created, when a fulfillment is updated, when a user triggers the task, and when a bulk operation finishes. Configuration includes shipping statuses and tags and limit to orders matching this query for manual runs.

15-day free trial – unlimited tasks

Documentation

Easily segment your orders by shipment status. Tagging your orders as "Delivered", or "Out for delivery", or "Attempted delivery", or any other status, allows you to stay on top of your order flow. And, adding these tags makes it easier to wire up additional automation, keeping the connection live between your customers and their orders.

This task monitors fulfillments for your orders. Whenever a fulfillment is updated, this task removes any shipment-related tags that might already be on the order, then adds whatever tag is relevant for the current shipment status. If there are multiple fulfillments for the order, and they have different statuses, this task will add more than one tag. Use the "Run task" button to scan all orders. To process orders older than 60 days, enable "Read all orders".

This task comes pre-configured with friendly tags, but feel free to update the tag names on the right-hand side. Do not modify the labels on the left! These correspond directly to shipment statuses as they're recorded by Shopify.

For a reference on Shopify's fulfillment statuses, see the FulfillmentDisplayStatus documentation. (More details may be available in the REST documentation for Fulfillment.shipment_status.)

The "Limit to orders matching this query for manual runs" option uses the same query syntax as the "Orders" section of the Shopify admin area. For example, to only include paid orders, use this query:

financial_status:paid

Developer details

Mechanic is designed to benefit everybody: merchants, customers, developers, agencies, Gurus, everybody.

That’s why we make it easy to configure automation without code, why we make it easy to tweak the underlying code once tasks are installed, and why we publish it all here for everyone to learn from.

Open source
View on GitHub to contribute to this task
Events
when a fulfillment is created (shopify/fulfillments/create)
when a fulfillment is updated (shopify/fulfillments/update)
when a user triggers the task (mechanic/user/trigger)
when a bulk operation finishes (mechanic/shopify/bulk_operation)
Options
shipping statuses and tags (keyval, required), limit to orders matching this query for manual runs
Script
{% comment %}
Options ordering:
  {{ options.shipping_statuses_and_tags__keyval_required }}
  {{ options.limit_to_orders_matching_this_query_for_manual_runs }}
{% endcomment %}

{% if event.topic contains "shopify/fulfillments/" %}
  {% capture query %}
    query {
      order(id: {{ fulfillment.order.admin_graphql_api_id | json }}) {
        id
        tags
        fulfillments {
          displayStatus
        }
      }
    }
  {% endcapture %}

  {% assign result = query | shopify %}

  {% if event.preview %}
    {% capture result_json %}
      {
        "data": {
          "order": {
            "id": "gid://shopify/Order/1234567890",
            "tags": [],
            "fulfillments": [
              {
                "displayStatus": "IN_TRANSIT"
              },
              {
                "displayStatus": "CANCELED"
              },
              {
                "displayStatus": "OUT_FOR_DELIVERY"
              }
            ]
          }
        }
      }
    {% endcapture %}

    {% assign result = result_json | parse_json %}
  {% endif %}

  {% assign orders = array %}
  {% assign orders[0] = result.data.order %}

{% elsif event.topic == "mechanic/user/trigger" %}
  {% assign orders_query = nil %}

  {% if options.limit_to_orders_matching_this_query_for_manual_runs != blank %}
    {% assign orders_query = options.limit_to_orders_matching_this_query_for_manual_runs %}
  {% endif %}

  {% capture bulk_operation_query %}
    query {
      orders(
        query: {{ orders_query | json }}
      ) {
        edges {
          node {
            id
            tags
            fulfillments {
              displayStatus
            }
          }
        }
      }
    }
  {% endcapture %}

  {% action "shopify" %}
    mutation {
      bulkOperationRunQuery(
        query: {{ bulk_operation_query | json }}
      ) {
        bulkOperation {
          id
          status
        }
        userErrors {
          field
          message
        }
      }
    }
  {% endaction %}

{% elsif event.topic == "mechanic/shopify/bulk_operation" %}
  {% if event.preview %}
    {% capture objects_jsonl %}
      {"id":"gid:\/\/shopify\/Order\/1234567890","tags":[],"fulfillments":[{"displayStatus":"IN_TRANSIT"},{"displayStatus":"CANCELED"},{"displayStatus":"OUT_FOR_DELIVERY"}]}
      {"id":"gid:\/\/shopify\/Order\/2345678901","tags":[],"fulfillments":[{"displayStatus":"DELIVERED"}]}
    {% endcapture %}

    {% assign bulkOperation = hash %}
    {% assign bulkOperation["objects"] = objects_jsonl | parse_jsonl %}
  {% endif %}

  {% assign orders = bulkOperation.objects %}
{% endif %}

{% for order in orders %}
  {% assign tags_to_add = array %}
  {% assign tags_to_remove = array %}

  {% assign display_statuses = order.fulfillments | map: "displayStatus" %}

  {% for keyval in options.shipping_statuses_and_tags__keyval_required %}
    {% assign shipping_status = keyval.first %}
    {% assign tag = keyval.last %}

    {% if display_statuses contains shipping_status %}
      {% unless order.tags contains tag %}
        {% assign tags_to_add[tags_to_add.size] = tag %}
      {% endunless %}
    {% elsif order.tags contains tag %}
      {% assign tags_to_remove[tags_to_remove.size] = tag %}
    {% endif %}
  {% endfor %}

  {% if tags_to_add != empty or tags_to_remove != empty %}
    {% action "shopify" %}
      mutation {
        {% if tags_to_add != empty %}
          tagsAdd(
            id: {{ order.id | json }}
            tags: {{ tags_to_add | json }}
          ) {
            userErrors {
              field
              message
            }
          }
        {% endif %}

        {% if tags_to_remove != empty %}
          tagsRemove(
            id: {{ order.id | json }}
            tags: {{ tags_to_remove | json }}
          ) {
            userErrors {
              field
              message
            }
          }
        {% endif %}
      }
    {% endaction %}
  {% endif %}
{% endfor %}
Mechanic tasks are written in Liquid, which makes them easy to write and easy to modify. Learn more about our platform.
Defaults
Shipping statuses and tags
{"ATTEMPTED_DELIVERY"=>"Delivery attempted", "CANCELED"=>"Fulfillment Canceled", "CONFIRMED"=>"Delivery confirmed", "DELIVERED"=>"Delivery complete", "FAILURE"=>"Delivery failed", "FULFILLED"=>"Fulfilled", "IN_TRANSIT"=>"Delivery in transit", "LABEL_PRINTED"=>"Shipping label printed", "LABEL_PURCHASED"=>"Shipping label purchased", "LABEL_VOIDED"=>"Shipping label voided", "MARKED_AS_FULFILLED"=>"Marked as fulfilled", "NOT_DELIVERED"=>"Not delivered", "OUT_FOR_DELIVERY"=>"Out for delivery", "PICKED_UP"=>"Picked up", "READY_FOR_PICKUP"=>"Delivery ready for pickup", "SUBMITTED"=>"Submitted"}