Send an email when a product's price goes below its cost, with Mechanic.

Mechanic is a development and ecommerce automation platform for Shopify. :)

Send an email when a product's price goes below its cost

This task watches for product updates, and sends an email to the configured recipients for each variant that's found to have a unit cost that's greater than the variant's for-sale price.

Runs Occurs whenever a product is updated, ordered, or variants are added, removed or updated. Configuration includes recipient emails.

15-day free trial – unlimited tasks

Documentation

This task watches for product updates, and sends an email to the configured recipients for each variant that's found to have a unit cost that's greater than the variant's for-sale price.

This task stores the known price and cost for each variant in a metafield, so subsequent updates to a product will only fire this notification if those values change.

Developer details

Mechanic is designed to benefit everybody: merchants, customers, developers, agencies, Shopifolks, 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.

(By the way, have you seen our documentation? Have you joined the Slack community?)

Open source
View on GitHub to contribute to this task
Subscriptions
shopify/products/update
Tasks use subscriptions to sign up for specific kinds of events. Learn more
Options
recipient emails (array, required)
Code
{% assign recipient_emails = options.recipient_emails__array_required %}

{% if event.topic == "shopify/products/update" %}
  {% capture query %}
    query {
      product(id: {{ product.admin_graphql_api_id | json }}) {
        legacyResourceId
        title
        variants(first: 2048) {
          nodes {
            id
            legacyResourceId
            sku
            displayName
            price
            inventoryItem {
              unitCost {
                amount
              }
            }
            known_cost_and_price: metafield(
              namespace: "mechanic"
              key: "known_cost_and_price"
            ) {
              id
              value
            }
          }
        }
      }
    }
  {% endcapture %}

  {% assign result = query | shopify %}

  {% if event.preview %}
    {% capture result_json %}
      {
        "data": {
          "product": {
            "legacyResourceId": "1234567890",
            "title": "ACME Widget",
            "variants": {
              "nodes": [
                {
                  "id": "gid://shopify/ProductVariant/1234567890",
                  "legacyResourceId": "1234567890",
                  "sku": "ABC123",
                  "displayName": "ACME Widget - Red",
                  "price": "5.00",
                  "inventoryItem": {
                    "unitCost": {
                      "amount": "10.0"
                    }
                  }
                }
              ]
            }
          }
        }
      }
    {% endcapture %}

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

  {% assign product = result.data.product %}

  {% assign metafields_to_set = array %}
  {% assign metafields_to_delete = array %}

  {% for variant in product.variants.nodes %}
    {% assign unit_cost = variant.inventoryItem.unitCost.amount | times: 1 %}
    {% assign price = variant.price | times: 1 %}
    {% assign known_cost_and_price = variant.known_cost_and_price.value | default: "{}" | parse_json %}

    {% assign current_cost_and_price = hash %}
    {% assign current_cost_and_price["cost"] = unit_cost %}
    {% assign current_cost_and_price["price"] = price %}

    {% log
      variant_id: variant.id,
      known_cost_and_price: known_cost_and_price,
      current_cost_and_price: current_cost_and_price
    %}

    {% if price >= unit_cost and variant.known_cost_and_price != blank %}
      {% assign metafield_to_delete = hash %}
      {% assign metafield_to_delete["ownerId"] = variant.id %}
      {% assign metafield_to_delete["namespace"] = "mechanic" %}
      {% assign metafield_to_delete["key"] = "known_cost_and_price" %}
      {% assign metafields_to_delete = metafields_to_delete | push: metafield_to_delete %}

    {% elsif price < unit_cost and known_cost_and_price != current_cost_and_price %}
      {% assign variant_name
        = variant.sku
        | default: variant.displayName
        | remove: " - Default Title"
      %}

      {% capture email_subject %}
        {{ variant_name }} was priced lower than its cost
      {% endcapture %}

      {% capture email_body %}
        Hello,

        {{ variant_name }} was found to have a unit cost of {{ unit_cost | currency }}, while its price is set to {{ price | currency }}.

        <a href="{{ shop.admin_url }}products/{{ product.legacyResourceId }}/variants/{{ variant.legacyResourceId }}">Manage this in Shopify</a>

        Thanks,
        Mechanic, for {{ shop.name }}
      {% endcapture %}

      {% action "email" %}
        {
          "to": {{ recipient_emails | json }},
          "subject": {{ email_subject | strip | json }},
          "body": {{ email_body | unindent | strip | newline_to_br | json }},
          "reply_to": {{ shop.customer_email | json }},
          "from_display_name": {{ shop.name | json }}
        }
      {% endaction %}

      {% assign metafield_to_set = hash %}
      {% assign metafield_to_set["ownerId"] = variant.id %}
      {% assign metafield_to_set["namespace"] = "mechanic" %}
      {% assign metafield_to_set["key"] = "known_cost_and_price" %}
      {% assign metafield_to_set["type"] = "json" %}
      {% assign metafield_to_set["value"] = current_cost_and_price | json %}
      {% assign metafields_to_set = metafields_to_set | push: metafield_to_set %}
    {% endif %}
  {% endfor %}

  {% if metafields_to_set != blank %}
    {% assign groups_of_metafields_to_set = metafields_to_set | in_groups_of: 25, fill_with: false %}

    {% for group_of_metafields_to_set in groups_of_metafields_to_set %}
      {% action "shopify" %}
        mutation {
          metafieldsSet(
            metafields: {{ group_of_metafields_to_set | graphql_arguments }}
          ) {
            metafields {
              id
              namespace
              key
              type
              value
              owner {
                ... on ProductVariant {
                  id
                  sku
                  displayName
                }
              }
            }
            userErrors {
              code
              field
              message
            }
          }
        }
      {% endaction %}
    {% endfor %}
  {% endif %}

  {% if metafields_to_delete != blank %}
    {% assign groups_of_metafields_to_delete = metafields_to_delete | in_groups_of: 250, fill_with: false %}

    {% for group_of_metafields_to_delete in groups_of_metafields_to_delete %}
      {% action "shopify" %}
        mutation {
          metafieldsDelete(
            metafields: {{ group_of_metafields_to_delete | graphql_arguments }}
          ) {
            deletedMetafields {
              ownerId
              namespace
              key
            }
            userErrors {
              field
              message
            }
          }
        }
      {% endaction %}
    {% endfor %}
  {% endif %}
{% endif %}
Task code is written in Mechanic Liquid, an extension of open-source Liquid enhanced for automation. Learn more