Discount for customers with a tag
A Shopify discount Function that takes a percentage off the order for signed-in customers with a tag such as VIP or wholesale. Tested JavaScript.
- Function API
- Discount
- Target
- cart.lines.discounts.generate.run
- Discount class
- ORDER
- Plan
- Any plan in a public app; Shopify Plus in a custom app
- App scope
- write_discounts
- API version
- 2026-10
- Last checked
In short
This discount Function takes a percentage off the order subtotal, 10% by default, for signed-in customers who have one of your tags, such as VIP. Tags, percentage and message live in the discount’s JSON metafield, and the tags reach the query as variables. It uses the cart.lines.discounts.generate.run target of the Discount Function API, version 2026-10, with the order class.
How to use it
- Create an app with Shopify CLI 4.9.0 or later and add the extension: shopify app generate extension --template discount, with JavaScript.
- Replace the generated shopify.extension.toml and src/ files with the files below.
- Run the fixtures with shopify app function run --input tests/tagged-customer.input.json.
- Deploy with shopify app deploy and create an automatic discount with discountAutomaticAppCreate, discountClasses: [ORDER].
- Set the discount’s $app:function-configuration metafield, for example {"customerTags": ["VIP"], "percentage": 15, "message": "VIP 15% off"}.
Code
shopify.extension.tomlapi_version = "2026-10"
[[extensions]]
name = "Discount by customer tag"
handle = "discount-by-customer-tag"
type = "function"
[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/cart_lines_discounts_generate_run.graphql"
input_variables = { namespace = "$app", key = "function-configuration" }
export = "cart-lines-discounts-generate-run"
[extensions.build]
command = ""
path = "dist/function.wasm"
src/cart_lines_discounts_generate_run.graphqlquery CartLinesDiscountsGenerateRunInput($customerTags: [String!]) {
cart {
buyerIdentity {
customer {
hasAnyTag(tags: $customerTags)
}
}
}
discount {
discountClasses
metafield(namespace: "$app", key: "function-configuration") {
jsonValue
}
}
}
src/cart_lines_discounts_generate_run.js// @ts-check
/**
* @typedef {import("../generated/api").CartLinesDiscountsGenerateRunInput} CartLinesDiscountsGenerateRunInput
* @typedef {import("../generated/api").CartLinesDiscountsGenerateRunResult} CartLinesDiscountsGenerateRunResult
*/
/**
* Settings stored as JSON in the discount's metafield. The same metafield
* feeds the query's $customerTags variable (see input_variables in
* shopify.extension.toml), so Shopify checks the tags.
*/
const DEFAULT_CONFIG = {
percentage: 10,
message: "Member discount",
};
/** @type {CartLinesDiscountsGenerateRunResult} */
const NO_DISCOUNT = { operations: [] };
/**
* @param {CartLinesDiscountsGenerateRunInput} input
* @returns {CartLinesDiscountsGenerateRunResult}
*/
export function cartLinesDiscountsGenerateRun(input) {
// A Function may only return operations for the classes the discount was created with.
if (!input.discount.discountClasses.includes("ORDER")) return NO_DISCOUNT;
// Guests have no customer record; tags only apply after the customer signs in.
if (!input.cart.buyerIdentity?.customer?.hasAnyTag) return NO_DISCOUNT;
const config = { ...DEFAULT_CONFIG, ...input.discount.metafield?.jsonValue };
return {
operations: [
{
orderDiscountsAdd: {
candidates: [
{
message: config.message,
targets: [{ orderSubtotal: { excludedCartLineIds: [] } }],
value: { percentage: { value: String(config.percentage) } },
},
],
selectionStrategy: "FIRST",
},
},
],
};
}
Test input and expected output
tests/guest-checkout.input.json{
"cart": { "buyerIdentity": { "customer": null } },
"discount": {
"discountClasses": ["ORDER"],
"metafield": { "jsonValue": { "customerTags": ["VIP", "wholesale"], "percentage": 15, "message": "VIP 15% off" } }
}
}
tests/guest-checkout.output.json{ "operations": [] }
tests/tagged-customer.input.json{
"cart": { "buyerIdentity": { "customer": { "hasAnyTag": true } } },
"discount": {
"discountClasses": ["ORDER"],
"metafield": { "jsonValue": { "customerTags": ["VIP", "wholesale"], "percentage": 15, "message": "VIP 15% off" } }
}
}
tests/tagged-customer.output.json{
"operations": [
{
"orderDiscountsAdd": {
"candidates": [
{
"message": "VIP 15% off",
"targets": [{ "orderSubtotal": { "excludedCartLineIds": [] } }],
"value": { "percentage": { "value": "15" } }
}
],
"selectionStrategy": "FIRST"
}
}
]
}
tests/untagged-customer.input.json{
"cart": { "buyerIdentity": { "customer": { "hasAnyTag": false } } },
"discount": {
"discountClasses": ["ORDER"],
"metafield": { "jsonValue": { "customerTags": ["VIP", "wholesale"], "percentage": 15, "message": "VIP 15% off" } }
}
}
tests/untagged-customer.output.json{ "operations": [] }
Written by Lintel. MIT license: free to use in your own store and in client work.
Limits and edge cases
- The customer must be signed in; guests have no tags.
- Tags are checked by Shopify with hasAnyTag and the $customerTags variable, so changing them doesn’t need a deploy.
- Whether it combines with other discounts follows the discount’s combinesWith settings.
Questions
- How do I give a discount to tagged customers on Shopify?
- Create a discount backed by a Function that checks the customer’s tags with hasAnyTag and returns an order discount, as this example does.
- What if the customer signs in during checkout?
- The Function runs on the current cart. Once the customer is signed in, the tag check passes and the discount applies.
- Can I exclude sale items from the VIP discount?
- Yes. Add the cart lines to the query and put their IDs in excludedCartLineIds on the orderSubtotal target.
Shopify documentation
- Written for Function API version 2026-10 and checked against Shopify’s reference on the date shown. Shopify releases a new version every quarter.
- Custom apps that contain Functions only run on Shopify Plus stores; a public app with the same Function runs on any plan unless the page says otherwise.
- Every example ships with test fixtures, and we run them before publishing. Run them again after you change the code: shopify app function run.
- MIT license. Use the code in your own store or in client work.
Need this built, tested and maintained for your store? See Shopify Functions development.
