Auto-tag customers when they purchase a matching product, with Mechanic.

Mechanic is an automation development platform for Shopify. :)

Auto-tag customers when they purchase a matching product

by Isaac Bowen (team@usemechanic.com)

Configure this task with search terms that describe certain products, and this task will apply the tags of your choice to every customer who purchases a matching product or product variant. Run this task manually to tag all customers who have a qualifying order already on file.

Runs when an order is paid, when a user triggers the task, and when a bulk operation finishes. Configuration includes search query, search for products, search for product variants, customer tags to apply, and test mode.

15-day free trial – unlimited tasks

Documentation

This task auto-tags customers who have paid orders on file for products or product variants that match the search query you add.

Sample searches:

  • A specific SKU: search product variants for sku:ABC123
  • All products with a certain tag: search products for tag:holiday
  • All products with a certain type: search products for product_type:"Gift Card"
  • A product with a certain title: search products for title:"Short sleeve t-shirt"

To ensure expected results, use this task with test mode enabled, before disabling test mode.

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.

Events
when an order is paid (shopify/orders/paid)
when a user triggers the task (mechanic/user/trigger)
when a bulk operation finishes (mechanic/shopify/bulk_operation)
Options
search query (required), search for products (boolean), search for product variants (boolean), customer tags to apply (required, array), test mode (boolean)
Script
{% comment %}
  Ordering the task options:

  {{ options.search_query__required }}
  {{ options.search_for_products__boolean }}
  {{ options.search_for_product_variants__boolean }}
  {{ options.customer_tags_to_apply__required_array }}
  {{ options.test_mode__boolean }}
{% endcomment %}

{% if options.search_for_products__boolean and options.search_for_product_variants__boolean %}
  {% error "Choose only one of 'Search for products' and 'Search for product variants'. :)" %}
{% elsif options.search_for_products__boolean == false and options.search_for_product_variants__boolean == false %}
  {% error "Choose either 'Search for products' and 'Search for product variants'." %}
{% endif %}

{% assign cursor = nil %}
{% assign qualifier_resource_ids = array %}
{% assign qualifier_resource_summaries = array %}
{% assign jobs = array %}

{% for n in (0..100) %}
  {% capture query %}
    query {
      {% if options.search_for_products__boolean %}
        resources: products(
      {% else %}
        resources: productVariants(
      {% endif %}
        first: 250
        after: {{ cursor | json }}
        query: {{ options.search_query__required | json }}
      ) {
        edges {
          node {
            id
            legacyResourceId
            {% if options.search_for_products__boolean %}
              displayName: title
            {% else %}
              displayName
            {% endif %}
          }
        }
      }
    }
  {% endcapture %}

  {% assign result = query | shopify %}

  {% if event.preview %}
    {% capture result_json %}
      {
        "data": {
          "resources": {
            "edges": [
              {
                "node": {
                  "id": "gid://shopify/Product/1234567890",
                  "displayName": "Bundle",
                  "legacyResourceId": "1234567890"
                }
              }
            ]
          }
        }
      }
    {% endcapture %}

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

  {% log %}
    {
      "qualifier_resources": {{ result.data.resources.edges | map: "node" | json }}
    }
  {% endlog %}

  {% assign qualifier_resource_ids = result.data.resources.edges | map: "node" | map: "legacyResourceId" | concat: qualifier_resource_ids %}

  {% if result.data.resources.pageInfo.hasNextPage %}
    {% assign cursor = result.data.resources.edges.last.cursor %}
  {% else %}
    {% break %}
  {% endif %}
{% endfor %}

{% if event.topic contains "shopify/orders/" %}
  {% if event.preview %}
    {% capture order_json %}
      {
        "financial_status": "paid",
        "name": "#1234",
        "customer": {
          "email": "customer@example.com",
          "tags": "",
          "admin_graphql_api_id": "gid://shopify/Customer/1234567890"
        },
        "line_items": [
          {
            "product_id": 1234567890,
            "variant_id": 1234567890,
            "title": "IPod Nano - 8GB"
          }
        ]
      }
    {% endcapture %}

    {% assign order = order_json | parse_json %}
  {% endif %}

  {% assign order_qualifies = false %}
  {% assign order_qualifying_resource = nil %}

  {% if order.financial_status == "paid" and order.customer %}
    {% for line_item in order.line_items %}
      {% if options.search_for_products__boolean %}
        {% assign id = line_item.product_id | append: "" %}
      {% else %}
        {% assign id = line_item.variant_id | append: "" %}
      {% endif %}

      {% if qualifier_resource_ids contains id %}
        {% assign order_qualifies = true %}
        {% assign order_qualifying_resource = line_item.title %}
        {% break %}
      {% endif %}
    {% endfor %}
  {% endif %}

  {% if order_qualifies %}
    {% assign job = hash %}
    {% assign job["customer_id"] = order.customer.admin_graphql_api_id %}
    {% assign job["customer_email"] = order.customer.email %}
    {% assign job["customer_existing_tags"] = order.customer.tags | split: ", " %}
    {% assign job["reason"] = order_qualifying_resource | append: ", in order " | append: order.name %}
    {% assign jobs[jobs.size] = job %}
  {% endif %}
{% elsif event.topic == "mechanic/user/trigger" %}
  {% assign orders_query = "financial_status:paid" %}

  {% capture bulk_operation_query %}
    query {
      customers(
        query: "orders_count:>0"
      ) {
        edges {
          node {
            __typename
            id
            email
            tags
            orders(
              query: "financial_status:paid"
            ) {
              edges {
                node {
                  __typename
                  id
                  name
                  lineItems {
                    edges {
                      node {
                        __typename
                        id
                        {% if options.search_for_products__boolean %}
                          resource: product {
                            legacyResourceId
                            displayName: title
                          }
                        {% else %}
                          resource: variant {
                            legacyResourceId
                            displayName
                          }
                        {% endif %}
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  {% 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 bulkOperation_json %}
      {
        "objects": [
          {
            "__typename": "LineItem",
            "resource": {
              "legacyResourceId": "1234567890",
              "displayName": "IPod Nano - 8GB"
            },
            "__parent": {
              "name": "#1234",
              "__parent": {
                "id": "gid://shopify/Customer/1234567890",
                "email": "customer@example.com",
                "tags": []
              }
            }
          }
        ]
      }
    {% endcapture %}
    {% assign bulkOperation = bulkOperation_json | parse_json %}
  {% endif %}

  {% assign lineItems = bulkOperation.objects | where: "__typename", "LineItem" | where: "resource" %}
  {% for lineItem in lineItems %}
    {% assign resource = lineItem.resource %}
    {% assign order = lineItem.__parent %}
    {% assign customer = order.__parent %}

    {% if qualifier_resource_ids contains resource.legacyResourceId %}
      {% assign job = hash %}
      {% assign job["customer_id"] = customer.id %}
      {% assign job["customer_email"] = customer.email %}
      {% assign job["customer_existing_tags"] = customer.tags %}
      {% assign job["reason"] = resource.displayName | append: ", in order " | append: order.name %}
      {% assign jobs[jobs.size] = job %}
    {% endif %}
  {% endfor %}
{% endif %}

{% assign customer_ids_with_jobs = jobs | map: "customer_id" | uniq %}
{% for customer_id in customer_ids_with_jobs %}
  {% assign customer_jobs = jobs | where: "customer_id", customer_id %}
  {% assign customer_existing_tags = customer_jobs[0].customer_existing_tags %}
  {% assign customer_email = customer_jobs[0].customer_email %}
  {% assign reasons = customer_jobs | map: "reason" %}

  {% assign tags_to_add = array %}
  {% for tag in options.customer_tags_to_apply__required_array %}
    {% unless customer_existing_tags contains tag %}
      {% assign tags_to_add[tags_to_add.size] = tag %}
    {% endunless %}
  {% endfor %}

  {% if options.test_mode__boolean %}
    {% action "echo" %}
      {
        "customer_id": {{ customer_id | json }},
        "customer_email": {{ customer_email | json }},
        "customer_purchases": {{ reasons | json }},
        "customer_existing_tags": {{ customer_existing_tags | json }},
        "customer_tags_to_add": {{ tags_to_add | json }}
      }
    {% endaction %}
  {% elsif tags_to_add == empty %}
    {% capture log_message %}Customer {{ customer.id }} already has all applicable tags ({{ tags_applicable | join: ", " }}); nothing to do.{% endcapture %}
    {% log log_message %}
  {% else %}
    {% action "shopify" %}
      mutation {
        tagsAdd(
          id: {{ customer_id | json }}
          tags: {{ tags_to_add | json }}
        ) {
          userErrors {
            field
            message
          }
        }
      }
    {% 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
Search query
sku:ABC123
Search for product variants
true
Test mode
true