11 best Shopify script examples – with script editor instructions

11 best Shopify script examples – with script editor instructions

Although Shopify Scripts are only available with one version of Shopify – Shopify Plus – they can make a big difference to your store. 

 

They’re small pieces of code that enable you to create a more personalised experience for your customers, in their cart and when they come to checkout. 

Shopify Scripts are often used to apply discounts to customers’ shopping cart, depending on factors like the items in the cart. But that’s not all they can do – you might also use them to customise your store’s payment and delivery options.  

And if you’re still unsure what we mean, here are some of our favourite Shopify Script examples, complete with instructions on how to use the Shopify Script Editor. 

 

How to use these scripts in Shopify Script Editor

 

You can use and modify any of the below Shopify script examples by first heading to the Shopify admin and then to Apps > Script Editor. Then, click ‘Create Script’, followed by ‘Line items’, ‘Shipping rates’ or ‘Payment gateways’, depending on which of these categories the script falls into. 

Select ‘Blank template’ and then ‘Create script’, before deleting the default line of code, Output.cart = Input.cart, in the Ruby source code section. You’ll then be able to copy one of the below scripts and paste it into the Ruby source code section. 

Edit the ‘Customizable Settings’ section of the script to get it to work in your store. Finally, once you’ve tested and debugged the script to ensure it functions, click ‘Save draft’ to save an unpublished draft of it, or click ‘Save and publish’ to create and publish the script on the site. 

So now that you know the basics of creating and publishing a Shopify script, here are 11 of the finest Shopify script examples to try:

 

#1 Tiered discount by spend 

Category: Line items 

Do you want to give your shoppers a bigger percentage discount, the more they spend – for example, a £10 discount if they spend £30, or 15% off on orders of £50 or more? 

Well in that case, this script could be just the thing – and as you can see, this example gives a 20% discount on orders of at least £100, too.  

 

# ================================ Customizable Settings ================================ # ================================================================ # Tiered Discounts by Spend Threshold # # If the cart total is greater than (or equal to) an entered # threshold, the associated discount is applied to each item in # the cart. # # - 'threshold' is the spend amount needed to qualify # - 'discount_type' is the type of discount to provide. Can be # either: # - ':percent' # - ':pound' # - 'discount_amount' is the percentage/pound discount to # apply (per item) # - 'discount_message' is the message to show when a discount # is applied # ================================================================ SPENDING_THRESHOLDS = [ { threshold: 30, discount_type: :percent, discount_amount: 10, discount_message: 'Spend £30 and get 10% off!', }, { threshold: 50, discount_type: :percent, discount_amount: 15, discount_message: 'Spend £50 and get 15% off!', }, { threshold: 100, discount_type: :percent, discount_amount: 20, discount_message: 'Spend £100 and get 20% off!', }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # DiscountApplicator # # Applies the entered discount to the supplied line item. # ================================================================ class DiscountApplicator def initialize(discount_type, discount_amount, discount_message) @discount_type = discount_type @discount_message = discount_message @discount_amount = if discount_type == :percent 1 - (discount_amount * 0.01) else Money.new(pennies: 100) * discount_amount end end def apply(line_item) new_line_price = if @discount_type == :percent line_item.line_price * @discount_amount else [line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].max end line_item.change_line_price(new_line_price, message: @discount_message) end end # ================================================================ # TieredDiscountBySpendCampaign # # If the cart total is greater than (or equal to) an entered # threshold, the associated discount is applied to each item in # the cart. # ================================================================ class TieredDiscountBySpendCampaign def initialize(tiers) @tiers = tiers.sort_by { |tier| tier[:threshold] }.reverse end def run(cart) applicable_tier = @tiers.find { |tier| cart.subtotal_price >= (Money.new(pennies: 100) * tier[:threshold]) } return if applicable_tier.nil? discount_applicator = DiscountApplicator.new( applicable_tier[:discount_type], applicable_tier[:discount_amount], applicable_tier[:discount_message] ) cart.line_items.each do |line_item| next if line_item.variant.product.gift_card? discount_applicator.apply(line_item) end end end CAMPAIGNS = [ TieredDiscountBySpendCampaign.new(SPENDING_THRESHOLDS), ] CAMPAIGNS.each do |campaign| campaign.run(Input.cart) end Output.cart = Input.cart

 


#2 Tiered discount by quantity 

Category: Line items 

Again, this is a tiered discount script, albeit based on the number of items the customer purchases of a particular type, rather than the amount they spend. 

So you can use it to give a 10% discount to customers who buy two or more of a certain item category, such as a hat, or 15% off if they purchase at least five of those items. 

 

# ================================ Customizable Settings ================================ # ================================================================ # Tiered Discount by Quantity # # If the total quantity of matching items is greater than (or # equal to) an entered threshold, the associated discount is # applied to each matching item. # #   - 'product_selector_match_type' determines whether we look for #     products that do or don't match the entered selectors. Can #     be: #       - ':include' to check if the product does match #       - ':exclude' to make sure the product doesn't match #   - 'product_selector_type' determines how eligible products #     will be identified. Can be either: #       - ':tag' to find products by tag #       - ':type' to find products by type #       - ':vendor' to find products by vendor #       - ':product_id' to find products by ID #       - ':variant_id' to find products by variant ID #       - ':all' for all products #   - 'product_selector' is a list of identifiers (from above) for #     qualifying products. Product/Variant ID lists should only #     contain numbers (ie. no quotes). If ':all' is used, this #     can also be 'nil'. #   - 'tiers' is a list of tiers where: #     - 'quantity' is the minimum quantity you need to buy to #       qualify #     - 'discount_type' is the type of discount to provide. Can be #       either: #         - ':percent' #         - ':pound' #     - 'discount_amount' is the percentage/pound discount to #       apply (per item) #     - 'discount_message' is the message to show when a discount #       is applied # ================================================================ PRODUCT_DISCOUNT_TIERS = [   {     product_selector_match_type: :include,     product_selector_type: :tag,     product_selectors: ["your_tag"],     tiers: [       {         quantity: 2,         discount_type: :percent,         discount_amount: 10,         discount_message: '10% off for 2+',       },       {         quantity: 5,         discount_type: :percent,         discount_amount: 15,         discount_message: '15% off for 5+',       },     ],   }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # ProductSelector # # Finds matching products by the entered criteria. # ================================================================ class ProductSelector   def initialize(match_type, selector_type, selectors)     @match_type = match_type     @comparator = match_type == :include ? 'any?' : 'none?'     @selector_type = selector_type     @selectors = selectors   end   def match?(line_item)     if self.respond_to?(@selector_type)       self.send(@selector_type, line_item)     else       raise RuntimeError.new('Invalid product selector type')     end   end   def tag(line_item)     product_tags = line_item.variant.product.tags.map { |tag| tag.downcase.strip }     @selectors = @selectors.map { |selector| selector.downcase.strip }     (@selectors & product_tags).send(@comparator)   end   def type(line_item)     @selectors = @selectors.map { |selector| selector.downcase.strip }     (@match_type == :include) == @selectors.include?(line_item.variant.product.product_type.downcase.strip)   end   def vendor(line_item)     @selectors = @selectors.map { |selector| selector.downcase.strip }     (@match_type == :include) == @selectors.include?(line_item.variant.product.vendor.downcase.strip)   end   def product_id(line_item)     (@match_type == :include) == @selectors.include?(line_item.variant.product.id)   end   def variant_id(line_item)     (@match_type == :include) == @selectors.include?(line_item.variant.id)   end   def all(line_item)     true   end end # ================================================================ # DiscountApplicator # # Applies the entered discount to the supplied line item. # ================================================================ class DiscountApplicator   def initialize(discount_type, discount_amount, discount_message)     @discount_type = discount_type     @discount_message = discount_message     @discount_amount = if discount_type == :percent       1 - (discount_amount * 0.01)     else       Money.new(pennies: 100) * discount_amount     end   end   def apply(line_item)     new_line_price = if @discount_type == :percent       line_item.line_price * @discount_amount     else       [line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].max     end     line_item.change_line_price(new_line_price, message: @discount_message)   end end # ================================================================ # TieredPricingCampaign # # If the total quantity of matching items is greater than (or # equal to) an entered threshold, the associated discount is # applied to each matching item. # ================================================================ class TieredPricingCampaign   def initialize(campaigns)     @campaigns = campaigns   end   def run(cart)     @campaigns.each do |campaign|       product_selector = ProductSelector.new(         campaign[:product_selector_match_type],         campaign[:product_selector_type],         campaign[:product_selectors],       )       applicable_items = cart.line_items.select { |line_item| product_selector.match?(line_item) }       next if applicable_items.nil?       total_applicable_quantity = applicable_items.map(&:quantity).reduce(0, :+)       tiers = campaign[:tiers].sort_by { |tier| tier[:quantity] }.reverse       applicable_tier = tiers.find { |tier| tier[:quantity] <= total_applicable_quantity }       next if applicable_tier.nil?       discount_applicator = DiscountApplicator.new(         applicable_tier[:discount_type],         applicable_tier[:discount_amount],         applicable_tier[:discount_message]       )       applicable_items.each do |line_item|         discount_applicator.apply(line_item)       end     end   end end CAMPAIGNS = [   TieredPricingCampaign.new(PRODUCT_DISCOUNT_TIERS), ] CAMPAIGNS.each do |campaign|   campaign.run(Input.cart) end Output.cart = Input.cart

 



#3 Buy one get one (BOGO) discount 

Category: Line items 

If a customer purchases a particular number of one product, why not give them a percentage discount on another item? 

That’s what this script allows you to do – for example, enabling your customer to buy a hat for 10% less than the standard price if they order two T-shirts.

 

# ================================ Customizable Settings ================================ # ================================================================ # Buy V of Product W, Get X of Product Y for Z Discount # # Buy a certain number of "matching" items, get a certain number # of a different set of "matching" items with the entered discount # applied. For example: # #   "Buy 2 t-shirts, get 1 hat for 10% off" # #   - 'buy_product_selector_match_type' determines whether we look #     for products that do or don't match the entered selectors. #     Can be: #       - ':include' to check if the product does match #       - ':exclude' to make sure the product doesn't match #   - 'buy_product_selector_type' determines how eligible products #     will be identified. Can be: #       - ':tag' to find products by tag #       - ':type' to find products by type #       - ':vendor' to find products by vendor #       - ':product_id' to find products by ID #       - ':variant_id' to find products by variant ID #       - ':all' for all products #   - 'buy_product_selectors' is a list of identifiers (from above) #     for qualifying products. Product/Variant ID lists should only #     contain numbers (ie. no quotes). If ':all' is used, this #     can also be 'nil'. #   - 'quantity_to_buy' is the number of products needed to #     qualify #   - 'get_selector_match_type' is the same idea as the "Buy" #     version above #   - 'get_product_selector_type' is the same idea as the "Buy" #     version above #   - 'get_product_selectors' is the same idea as the "Buy" #     version above #   - 'quantity_to_discount' is the number of products to discount #   - 'allow_incomplete_bundle' determines whether a portion of #     the items to discount can be discounted, or all items #     need to be present. Can be: #       - 'true' #       - 'false' #   - 'discount_type' is the type of discount to provide. Can be #     either: #       - ':percent' #       - ':pound' #   - 'discount_amount' is the percentage/pound discount to #     apply (per item) #   - 'discount_message' is the message to show when a discount #     is applied # ================================================================ BUYVOFW_GETXOFY_FORZ = [   {     buy_product_selector_match_type: :include,     buy_product_selector_type: :tag,     buy_product_selectors: ["your_tag", "another_tag"],     quantity_to_buy: 1,     get_product_selector_match_type: :include,     get_product_selector_type: :tag,     get_product_selectors: ["your_other_tag", "a_different_tag"],     quantity_to_discount: 1,     allow_incomplete_bundle: false,     discount_type: :percent,     discount_amount: 100,     discount_message: 'Buy a Product X, get a Product Y free!',   },   {     buy_product_selector_match_type: :include,     buy_product_selector_type: :id,     buy_product_selectors: [1234567890987, 1234567890986],     quantity_to_buy: 1,     get_product_selector_match_type: :include,     get_product_selector_type: :id,     get_product_selectors: [1234567890985, 1234567890984],     quantity_to_discount: 1,     allow_incomplete_bundle: false,     discount_type: :pound,     discount_amount: 10,     discount_message: 'Buy a Product X, get £10 off a Product Y!',   }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # ProductSelector # # Finds matching products by the entered criteria. # ================================================================ class ProductSelector   def initialize(match_type, selector_type, selectors)     @match_type = match_type     @comparator = match_type == :include ? 'any?' : 'none?'     @selector_type = selector_type     @selectors = selectors   end   def match?(line_item)     if self.respond_to?(@selector_type)       self.send(@selector_type, line_item)     else       raise RuntimeError.new('Invalid product selector type')     end   end   def tag(line_item)     product_tags = line_item.variant.product.tags.map { |tag| tag.downcase.strip }     @selectors = @selectors.map { |selector| selector.downcase.strip }     (@selectors & product_tags).send(@comparator)   end   def type(line_item)     @selectors = @selectors.map { |selector| selector.downcase.strip }     (@match_type == :include) == @selectors.include?(line_item.variant.product.product_type.downcase.strip)   end   def vendor(line_item)     @selectors = @selectors.map { |selector| selector.downcase.strip }     (@match_type == :include) == @selectors.include?(line_item.variant.product.vendor.downcase.strip)   end   def product_id(line_item)     (@match_type == :include) == @selectors.include?(line_item.variant.product.id)   end   def variant_id(line_item)     (@match_type == :include) == @selectors.include?(line_item.variant.id)   end   def all(line_item)     true   end end # ================================================================ # DiscountApplicator # # Applies the entered discount to the supplied line item. # ================================================================ class DiscountApplicator   def initialize(discount_type, discount_amount, discount_message)     @discount_type = discount_type     @discount_message = discount_message     @discount_amount = if discount_type == :percent       1 - (discount_amount * 0.01)     else       Money.new(pennies: 100) * discount_amount     end   end   def apply(line_item)     new_line_price = if @discount_type == :percent       line_item.line_price * @discount_amount     else       [line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].max     end     line_item.change_line_price(new_line_price, message: @discount_message)   end end # ================================================================ # DiscountLoop # # Loops through the supplied line items and discounts the supplied # number of items by the supplied discount. # ================================================================ class DiscountLoop   def initialize(discount_applicator)     @discount_applicator = discount_applicator   end   def loop_items(cart, line_items, num_to_discount)     line_items.each do |line_item|       break if num_to_discount <= 0       if line_item.quantity > num_to_discount         split_line_item = line_item.split(take: num_to_discount)         @discount_applicator.apply(split_line_item)         position = cart.line_items.find_index(line_item)         cart.line_items.insert(position + 1, split_line_item)         break       else         @discount_applicator.apply(line_item)         num_to_discount -= line_item.quantity       end     end   end end # ================================================================ # BuyVofWGetXofYForZCampaign # # Buy a certain number of "matching" items, get a certain number # of a different set of "matching" items with the entered discount # applied. # ================================================================ class BuyVofWGetXofYForZCampaign   def initialize(campaigns)     @campaigns = campaigns   end   def run(cart)     @campaigns.each do |campaign|       buy_product_selector = ProductSelector.new(         campaign[:buy_product_selector_match_type],         campaign[:buy_product_selector_type],         campaign[:buy_product_selectors],       )       get_product_selector = ProductSelector.new(         campaign[:get_product_selector_match_type],         campaign[:get_product_selector_type],         campaign[:get_product_selectors],       )       buy_items = []       get_items = []       cart.line_items.each do |line_item|         buy_items.push(line_item) if buy_product_selector.match?(line_item)         get_items.push(line_item) if get_product_selector.match?(line_item)       end       next if buy_items.empty? || get_items.empty?       get_items = get_items.sort_by { |line_item| line_item.variant.price }       quantity_to_buy = campaign[:quantity_to_buy]       quantity_to_discount = campaign[:quantity_to_discount]       buy_offers = (buy_items.map(&:quantity).reduce(0, :+) / quantity_to_buy).floor       if campaign[:allow_incomplete_bundle]         number_of_bundles = buy_offers       else         get_offers = (get_items.map(&:quantity).reduce(0, :+) / quantity_to_discount).floor         number_of_bundles = [buy_offers, get_offers].min       end       number_of_discountable_items = number_of_bundles * quantity_to_discount       next unless number_of_discountable_items > 0       discount_applicator = DiscountApplicator.new(         campaign[:discount_type],         campaign[:discount_amount],         campaign[:discount_message]       )       discount_loop = DiscountLoop.new(discount_applicator)       discount_loop.loop_items(cart, get_items, number_of_discountable_items)     end   end end CAMPAIGNS = [   BuyVofWGetXofYForZCampaign.new(BUYVOFW_GETXOFY_FORZ), ] CAMPAIGNS.each do |campaign|   campaign.run(Input.cart) end Output.cart = Input.cart

 



#4 Bundle discount 

Category: Line items 

This script provides a discount when the customer adds a specific combination of items – or ‘bundle’ – to their shopping cart. That might mean, for instance, offering 20% off their order when they purchase a T-shirt, hat and a pair of sunglasses at the same time. 

 

# ================================ Customizable Settings ================================ # ================================================================ # Buy Products WXY, get Z Discount # # Buy a specific bundle of products, get that bundle at a # discount. For example: # #   "Buy a t-shirt, a hat, and sunglasses, get 20% off each" # #   - 'bundle_items' is a list of the items that comprise the #     bundle, where: #     - 'product_id' is the ID of the product #     - 'quantity_needed' is the quantity necessary to complete #       the bundle #   - 'discount_type' is the type of discount to provide. Can be #     either: #       - ':percent' #       - ':pound' #   - 'discount_amount' is the percentage/pound discount to #     apply (per item) #   - 'discount_message' is the message to show when a discount #     is applied # ================================================================ BUNDLE_DISCOUNTS = [   {     bundle_items: [       {         product_id: 1234567890987,         quantity_needed: 1       },       {         product_id: 1234567890986,         quantity_needed: 1       },     ],     discount_type: :percent,     discount_amount: 10,     discount_message: "Buy Product X and Product Y, get 10% off!",   }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # BundleSelector # # Finds any items that are part of the entered bundle and saves # them. # ================================================================ class BundleSelector   def initialize(bundle_items)     @bundle_items = bundle_items.reduce({}) do |acc, bundle_item|       acc[bundle_item[:product_id]] = {         cart_items: [],         quantity_needed: bundle_item[:quantity_needed],         total_quantity: 0,       }       acc     end   end   def build(cart)     cart.line_items.each do |line_item|             next if line_item.line_price_changed?       next unless @bundle_items[line_item.variant.product.id]       @bundle_items[line_item.variant.product.id][:cart_items].push(line_item)       @bundle_items[line_item.variant.product.id][:total_quantity] += line_item.quantity     end     @bundle_items   end end # ================================================================ # DiscountApplicator # # Applies the entered discount to the supplied line item. # ================================================================ class DiscountApplicator   def initialize(discount_type, discount_amount, discount_message)     @discount_type = discount_type     @discount_message = discount_message     @discount_amount = if discount_type == :percent       1 - (discount_amount * 0.01)     else       Money.new(pennies: 100) * discount_amount     end   end   def apply(line_item)     new_line_price = if @discount_type == :percent       line_item.line_price * @discount_amount     else       [line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].max     end     line_item.change_line_price(new_line_price, message: @discount_message)   end end # ================================================================ # DiscountLoop # # Loops through the supplied line items and discounts the supplied # number of items by the supplied discount. # ================================================================ class DiscountLoop   def initialize(discount_applicator)     @discount_applicator = discount_applicator   end   def loop_items(cart, line_items, num_to_discount)     line_items.each_with_index do |line_item|       break if num_to_discount <= 0       if line_item.quantity > num_to_discount         split_line_item = line_item.split(take: num_to_discount)         @discount_applicator.apply(split_line_item)         position = cart.line_items.find_index(line_item)         cart.line_items.insert(position + 1, split_line_item)         break       else         @discount_applicator.apply(line_item)         num_to_discount -= line_item.quantity       end     end   end end # ================================================================ # BundleDiscountCampaign # # If the entered bundle is present, the entered discount is # applied to each item in the bundle. # ================================================================ class BundleDiscountCampaign   def initialize(campaigns)     @campaigns = campaigns   end   def run(cart)     @campaigns.each do |campaign|       bundle_selector = BundleSelector.new(campaign[:bundle_items])       bundle_items = bundle_selector.build(cart)       next if bundle_items.any? do |product_id, product_info|         product_info[:total_quantity] < product_info[:quantity_needed]       end       num_bundles = bundle_items.map do |product_id, product_info|         (product_info[:total_quantity] / product_info[:quantity_needed])       end       num_bundles = num_bundles.min.floor       discount_applicator = DiscountApplicator.new(         campaign[:discount_type],         campaign[:discount_amount],         campaign[:discount_message]       )       discount_loop = DiscountLoop.new(discount_applicator)       bundle_items.each do |product_id, product_info|         discount_loop.loop_items(           cart,           product_info[:cart_items],           (product_info[:quantity_needed] * num_bundles),         )       end     end   end end CAMPAIGNS = [   BundleDiscountCampaign.new(BUNDLE_DISCOUNTS), ] CAMPAIGNS.each do |campaign|   campaign.run(Input.cart) end Output.cart = Input.cart

 



#5 Free gift with purchase 

Category: Line items 

This script is a great one for giving a 100% discount on a particular product – in other words, offering it for free – if the cart total exceeds a certain amount. We’ve set up the below example so that the customer would simply need to spend more than £75 to be entitled to their free gift. 

 

# ================================ Customizable Settings ================================ # ================================================================ # Spend £X, get Product Y for Z Discount # # If the cart total is greater than (or equal to) the entered # threshold (less the discounted amount), the entered number of # "matching" items is discounted by the entered amount. # #   - 'product_selector_match_type' determines whether we look for #     products that do or don't match the entered selectors. Can #     be: #       - ':include' to check if the product does match #       - ':exclude' to make sure the product doesn't match #   - 'product_selector_type' determines how eligible products #     will be identified. Can be either: #       - ':tag' to find products by tag #       - ':type' to find products by type #       - ':vendor' to find products by vendor #       - ':product_id' to find products by ID #       - ':variant_id' to find products by variant ID #       - ':all' for all products #   - 'product_selector' is a list of identifiers (from above) #     for qualifying products. Product/Variant ID lists should #     only contain numbers (ie. no quotes). If ':all' is used, #     this can also be 'nil'. #   - 'threshold' is the pound amount needed to spend to qualify #   - 'quantity_to_discount' is the number of items to discount #     if qualified #   - 'discount_type' is the type of discount to provide. Can be #     either: #       - ':percent' #       - ':pound' #   - 'discount_amount' is the percentage/pound discount to #     apply (per item) #   - 'discount_message' is the message to show when a discount #     is applied # ================================================================ SPENDX_GETY_FORZ = [   {     product_selector_match_type: :include,     product_selector_type: :product_id,     product_selectors: [1234567890123],     threshold: 75,     quantity_to_discount: 1,     discount_type: :percent,     discount_amount: 100,     discount_message: 'Spend £75 or more and get a free Product X!',   }, ]   # ================================ Script Code (do not edit) ================================ # ================================================================ # ProductSelector # # Finds matching products by the entered criteria. # ================================================================ class ProductSelector   def initialize(match_type, selector_type, selectors)     @match_type = match_type     @comparator = match_type == :include ? 'any?' : 'none?'     @selector_type = selector_type     @selectors = selectors   end     def match?(line_item)     if self.respond_to?(@selector_type)       self.send(@selector_type, line_item)     else       raise RuntimeError.new('Invalid product selector type')     end   end     def tag(line_item)     product_tags = line_item.variant.product.tags.map { |tag| tag.downcase.strip }     @selectors = @selectors.map { |selector| selector.downcase.strip }     (@selectors & product_tags).send(@comparator)   end     def type(line_item)     @selectors = @selectors.map { |selector| selector.downcase.strip }     (@match_type == :include) == @selectors.include?(line_item.variant.product.product_type.downcase.strip)   end     def vendor(line_item)     @selectors = @selectors.map { |selector| selector.downcase.strip }     (@match_type == :include) == @selectors.include?(line_item.variant.product.vendor.downcase.strip)   end     def product_id(line_item)     (@match_type == :include) == @selectors.include?(line_item.variant.product.id)   end     def variant_id(line_item)     (@match_type == :include) == @selectors.include?(line_item.variant.id)   end     def all(line_item)     true   end end   # ================================================================ # DiscountApplicator # # Applies the entered discount to the supplied line item. # ================================================================ class DiscountApplicator   def initialize(discount_type, discount_amount, discount_message)     @discount_type = discount_type     @discount_message = discount_message       @discount_amount = if discount_type == :percent       1 - (discount_amount * 0.01)     else       Money.new(pennies: 100) * discount_amount     end   end     def apply(line_item)     new_line_price = if @discount_type == :percent       line_item.line_price * @discount_amount     else       [line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].max     end       line_item.change_line_price(new_line_price, message: @discount_message)   end end   # ================================================================ # DiscountLoop # # Loops through the supplied line items and discounts the supplied # number of items by the supplied discount. # ================================================================ class DiscountLoop   def initialize(discount_applicator)     @discount_applicator = discount_applicator   end     def loop_items(cart, line_items, num_to_discount)     line_items.each do |line_item|       break if num_to_discount <= 0         if line_item.quantity > num_to_discount         split_line_item = line_item.split(take: num_to_discount)         @discount_applicator.apply(split_line_item)         position = cart.line_items.find_index(line_item)         cart.line_items.insert(position + 1, split_line_item)         break       else         @discount_applicator.apply(line_item)         num_to_discount -= line_item.quantity       end     end   end end   # ================================================================ # SpendXGetYForZCampaign # # If the cart total is greater than (or equal to) the entered # threshold (less the discounted amount), the entered number of # "matching" items is discounted by the entered amount. # ================================================================ class SpendXGetYForZCampaign   def initialize(campaigns)     @campaigns = campaigns   end     def run(cart)     @campaigns.each do |campaign|       threshold = Money.new(pennies: 100) * campaign[:threshold]         next if cart.subtotal_price < threshold         product_selector = ProductSelector.new(         campaign[:product_selector_match_type],         campaign[:product_selector_type],         campaign[:product_selectors],       )         eligible_items = cart.line_items.select { |line_item| product_selector.match?(line_item) }         next if eligible_items.nil?         eligible_items = eligible_items.sort_by { |line_item| line_item.variant.price }       num_to_discount = campaign[:quantity_to_discount]       cart_total = cart.subtotal_price         eligible_items.each do |line_item|         break if num_to_discount <= 0           if line_item.quantity > num_to_discount           cart_total -= line_item.variant.price * num_to_discount           break         else           cart_total -= line_item.line_price           num_to_discount -= line_item.quantity         end       end         next if cart_total < threshold         discount_applicator = discount_applicator = DiscountApplicator.new(         campaign[:discount_type],         campaign[:discount_amount],         campaign[:discount_message]       )         discount_loop = DiscountLoop.new(discount_applicator)       discount_loop.loop_items(cart, eligible_items, campaign[:quantity_to_discount])     end   end end   CAMPAIGNS = [   SpendXGetYForZCampaign.new(SPENDX_GETY_FORZ), ]   CAMPAIGNS.each do |campaign|   campaign.run(Input.cart) end   Output.cart = Input.cart

 



#6 Tagged customer discount 

Category: Line items 

You can use this script to apply a discount to the customer’s order if they have a specific tag. In the below example, we’ve made ‘VIP’ the tag, and 20% the size of the discount – the idea being that only VIP shoppers get to enjoy this particular money off deal. 

 

# ================================ Customizable Settings ================================ # ================================================================ # Discounts by Customer Tag # # If a customer is tagged (or not, depending on the setting below) # with the entered tag(s), the entered discount will be applied to # each item in the cart. # #   - 'customer_tag_match_type' determines whether we look for the customer #     to be tagged with any of the entered tags or not. Can be: #       - ':include' to check if the customer is tagged #       - ':exclude' to make sure the customer isn't tagged #   - 'customer_tags' is a list of tags to identify qualified #     customers #   - 'discount_type' is the type of discount to provide. Can be #     either: #       - ':percent' #       - ':pound' #   - 'discount_amount' is the percentage/pound discount to #     apply (per item) #   - 'discount_message' is the message to show when a discount #     is applied # ================================================================ DISCOUNTS_FOR_CUSTOMER_TAG = [   {     customer_tag_match_type: :include,     customer_tags: ["VIP"],     discount_type: :percent,     discount_amount: 20,     discount_message: "Discount for VIP customers!",   }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # CustomerTagSelector # # Finds whether the supplied customer has any of the entered tags. # ================================================================ class CustomerTagSelector   def initialize(match_type, tags)     @comparator = match_type == :include ? 'any?' : 'none?'     @tags = tags.map { |tag| tag.downcase.strip }   end   def match?(customer)     customer_tags = customer.tags.map { |tag| tag.downcase.strip }     (@tags & customer_tags).send(@comparator)   end end # ================================================================ # DiscountApplicator # # Applies the entered discount to the supplied line item. # ================================================================ class DiscountApplicator   def initialize(discount_type, discount_amount, discount_message)     @discount_type = discount_type     @discount_message = discount_message     @discount_amount = if discount_type == :percent       1 - (discount_amount * 0.01)     else       Money.new(pennies: 100) * discount_amount     end   end   def apply(line_item)     new_line_price = if @discount_type == :percent       line_item.line_price * @discount_amount     else       [line_item.line_price - (@discount_amount * line_item.quantity), Money.zero].max     end     line_item.change_line_price(new_line_price, message: @discount_message)   end end # ================================================================ # DiscountForCustomerTagCampaign # # If we have a "matching" customer (by tag), the entered discount # is applied. # ================================================================ class DiscountForCustomerTagCampaign   def initialize(discounts)     @discounts = discounts   end   def run(cart)     return unless cart.customer&.tags     @discounts.each do |discount|       customer_tag_selector = CustomerTagSelector.new(discount[:customer_tag_match_type], discount[:customer_tags])       next unless customer_tag_selector.match?(cart.customer)       discount_applicator = DiscountApplicator.new(         discount[:discount_type],         discount[:discount_amount],         discount[:discount_message]       )       cart.line_items.each do |line_item|         discount_applicator.apply(line_item)       end     end   end end CAMPAIGNS = [   DiscountForCustomerTagCampaign.new(DISCOUNTS_FOR_CUSTOMER_TAG), ] CAMPAIGNS.each do |campaign|   campaign.run(Input.cart) end Output.cart = Input.cart

 



#7 Discount shipping rates by customer tag 

Category: Shipping rates 

This script allows you to offer money off delivery costs to customers with a specific tag. That could be, for example, a 10% discount for customers tagged as ‘VIP’. 

 

# ================================ Customizable Settings ================================ # ================================================================ # Discount rates based on customer tag, where: #   - 'tag_match_type' determines whether we look for the customer #     to be tagged with any of the entered tags or not. Can be: #       - ':include' to check if the customer is tagged #       - ':exclude' to make sure the customer isn't tagged #   - 'customer_tags' is a list of customer tags to qualify for #     a discount #   - 'rate_match_type' determines whether the below strings #     should be an exact or partial match. Can be: #       - ':exact' for an exact match #       - ':partial' for a partial match #   - 'rate_names' is a list of strings to identify rates #   - 'discount_type' is the type of discount to provide. Can be #     either: #       - ':percent' #       - ':pound' #   - 'discount_amount' is the percentage/pound discount to #     apply #   - 'discount_message' is the message to show when a discount #     is applied # ================================================================ DISCOUNTS_FOR_CUSTOMER_TAG = [   {     tag_match_type: :include,     customer_tags: ["customer_tag", "another_tag"],     rate_match_type: :exact,     rate_names: ["Shipping Rate", "Other Shipping Rate"],     discount_type: :percent,     discount_amount: 10,     discount_message: "10% off shipping for tagged customers"   }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # CustomerTagSelector # # Finds whether the supplied customer has any of the entered tags # ================================================================ class CustomerTagSelector   def initialize(match_type, tags)     @comparator = match_type == :include ? 'any?' : 'none?'     @tags = tags.map { |tag| tag.downcase.strip }   end   def match?(customer)     customer_tags = customer.tags.map { |tag| tag.downcase.strip }     (@tags & customer_tags).send(@comparator)   end end # ================================================================ # RateNameSelector # # Finds whether the supplied rate name matches any of the entered # names # ================================================================ class RateNameSelector   def initialize(match_type, rate_names)     @comparator = match_type == :exact ? '==' : 'include?'     @rate_names = rate_names.map { |rate_name| rate_name.downcase.strip }   end   def match?(shipping_rate)     @rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }   end end # ================================================================ # DiscountApplicator # # Applies the entered discount to the supplied shipping rate # ================================================================ class DiscountApplicator   def initialize(discount_type, discount_amount, discount_message)     @discount_type = discount_type     @discount_message = discount_message     @discount_amount = if discount_type == :percent       discount_amount * 0.01     else       Money.new(pennies: 100) * discount_amount     end   end   def apply(shipping_rate)     rate_discount = if @discount_type == :percent       shipping_rate.price * @discount_amount     else       @discount_amount     end     shipping_rate.apply_discount(rate_discount, message: @discount_message)   end end # ================================================================ # DiscountRatesForCustomerTagCampaign # # Applies the entered discount to the entered rates if the # customer has any of the entered tags # ================================================================ class DiscountRatesForCustomerTagCampaign   def initialize(campaigns)     @campaigns = campaigns   end   def run(cart, shipping_rates)     return if cart.customer.nil?     @campaigns.each do |campaign|       customer_tag_selector = CustomerTagSelector.new(campaign[:tag_match_type], campaign[:customer_tags])       next unless customer_tag_selector.match?(cart.customer)       rate_name_selector = RateNameSelector.new(campaign[:rate_match_type], campaign[:rate_names])       discount_applicator = DiscountApplicator.new(         campaign[:discount_type],         campaign[:discount_amount],         campaign[:discount_message],       )       shipping_rates.each do |shipping_rate|         next unless rate_name_selector.match?(shipping_rate)         discount_applicator.apply(shipping_rate)       end     end   end end CAMPAIGNS = [   DiscountRatesForCustomerTagCampaign.new(DISCOUNTS_FOR_CUSTOMER_TAG), ] CAMPAIGNS.each do |campaign|   campaign.run(Input.cart, Input.shipping_rates) end Output.shipping_rates = Input.shipping_rates

 



#8 Show shipping rates for a specific zip code, province or country 

Category: Shipping rates 

You might use this script if you wish to show customers from a particular location a specific shipping rate, and hide shipping rates that aren’t applicable to them. 

Customers in France, for example, might be shown one rate, and not the rate that would apply to customers in the UK. 

 

# ================================ Customizable Settings ================================ # ================================================================ # Show Rate(s) for Zip/Province/Country # # If the cart's shipping address country/province/zip match the # entered settings, the entered rate(s) are shown, and all other # rates are hidden. Otherwise, the entered rate(s) are hidden. # #   - 'country_code' is a 2-character abbreviation for the #     applicable country #   - 'province_code' is a list of 2-character abbreviations for #     the applicable provinces #   - 'zip_code_match_type' determines whether the below strings #     should be an exact or partial match. Can be: #       - ':exact' for an exact match #       - ':partial' for a partial match #   - 'zip_codes' is a list of strings to identify zip codes #   - 'rate_match_type' determines whether the below strings #     should be an exact or partial match. Can be: #       - ':exact' for an exact match #       - ':partial' for a partial match #       - ':all' for all rates #   - 'rate_names' is a list of strings to identify rates #     - if using ':all' above, this can be set to 'nil' # ================================================================ SHOW_RATES_FOR_ZIP_PROVINCE_COUNTRY = [   {     country_code: "CA",     province_code: "BC",     zip_code_match_type: :partial,     zip_codes: ["V8T"],     rate_match_type: :exact,     rate_names: ["Apparel Rate"],   }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # ZipCodeSelector # # Finds whether the supplied zip code matches any of the entered # strings. # ================================================================ class ZipCodeSelector   def initialize(match_type, zip_codes)     @comparator = match_type == :exact ? '==' : 'include?'     @zip_codes = zip_codes.map { |zip_code| zip_code.upcase.strip }   end   def match?(zip_code)     @zip_codes.any? { |zip| zip_code.to_s.upcase.strip.send(@comparator, zip) }   end end # ================================================================ # RateNameSelector # # Finds whether the supplied rate name matches any of the entered # names. # ================================================================ class RateNameSelector   def initialize(match_type, rate_names)     @match_type = match_type     @comparator = match_type == :exact ? '==' : 'include?'     @rate_names = rate_names&.map { |rate_name| rate_name.downcase.strip }   end   def match?(shipping_rate)     if @match_type == :all       true     else       @rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }     end   end end # ================================================================ # ShowRatesForZipProvinceCountryCampaign # # If the cart's shipping address zip/province/country match the # entered settings, the entered rate(s) are shown, and all other # rates are hidden. Otherwise, the entered rate(s) are hidden. # ================================================================ class ShowRatesForZipProvinceCountryCampaign   def initialize(campaigns)     @campaigns = campaigns   end   def run(cart, shipping_rates)     address = cart.shipping_address     @campaigns.each do |campaign|       zip_code_selector = ZipCodeSelector.new(campaign[:zip_code_match_type], campaign[:zip_codes])       rate_name_selector = RateNameSelector.new(campaign[:rate_match_type], campaign[:rate_names])       if address.nil?         full_match = false       else         country_match =  address.country_code.upcase.strip == campaign[:country_code].upcase.strip         province_match = address.province_code.upcase.strip == campaign[:province_code].upcase.strip         zip_match = zip_code_selector.match?(address.zip)         full_match = country_match && province_match && zip_match       end       shipping_rates.delete_if do |shipping_rate|         rate_name_selector.match?(shipping_rate) != full_match       end     end   end end CAMPAIGNS = [   ShowRatesForZipProvinceCountryCampaign.new(SHOW_RATES_FOR_ZIP_PROVINCE_COUNTRY), ] CAMPAIGNS.each do |campaign|   campaign.run(Input.cart, Input.shipping_rates) end Output.shipping_rates = Input.shipping_rates

 



#9 Discount shipping rates by discount code

Category: Shipping rates

What if you only wish to present your customer with a discount on the delivery charge if they enter a discount code at the checkout? Well, that’s precisely why you’d use this particular script.  

This means that if, for example, your customer uses a discount code at the checkout stage to take 15% off their order, you can also give them 15% off their shipping. 

 

# ================================ Customizable Settings ================================ # ================================================================ # Discount Rate(s) by Discount Code(s) # # If one of the entered discount codes is used, the entered # rate(s) are discounted by the entered amount # #   - 'discount_code_match_type' determines whether the below #     strings should be an exact or partial match. Can be: #       - ':exact' for an exact match #       - ':partial' for a partial match #   - 'discount_codes' is a list of strings to identify discount #     codes #   - 'rate_match_type' determines whether the below strings #     should be an exact or partial match. Can be: #       - ':exact' for an exact match #       - ':partial' for a partial match #   - 'rate_names' is a list of strings to identify rates #   - 'discount_type' is the type of discount to provide. Can be #     either: #       - ':percent' #       - ':pound' #   - 'discount_amount' is the percentage/pound discount to #     apply #   - 'discount_message' is the message to show when a discount #     is applied # ================================================================ DISCOUNTS_FOR_DISCOUNT_CODES = [   {     discount_code_match_type: :exact,     discount_codes: ["TESTCODE1", "TESTCODE2"],     rate_match_type: :exact,     rate_names: ["Shipping Rate", "Other Shipping Rate"],     discount_type: :percent,     discount_amount: 100,     discount_message: "Free Shipping with discount code"   }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # DiscountCodeSelector # # Finds whether the supplied discount code matches any of the # entered codes. # ================================================================ class DiscountCodeSelector   def initialize(match_type, discount_codes)     @comparator = match_type == :exact ? '==' : 'include?'     @discount_codes = discount_codes.map { |discount_code| discount_code.upcase.strip }   end   def match?(discount_code)     @discount_codes.any? { |code| discount_code.code.upcase.send(@comparator, code) }   end end # ================================================================ # RateNameSelector # # Finds whether the supplied rate name matches any of the entered # names. # ================================================================ class RateNameSelector   def initialize(match_type, rate_names)     @comparator = match_type == :exact ? '==' : 'include?'     @rate_names = rate_names.map { |rate_name| rate_name.downcase.strip }   end   def match?(shipping_rate)     @rate_names.any? { |name| shipping_rate.name.downcase.send(@comparator, name) }   end end # ================================================================ # DiscountApplicator # # Applies the entered discount to the supplied shipping rate. # ================================================================ class DiscountApplicator   def initialize(discount_type, discount_amount, discount_message)     @discount_type = discount_type     @discount_message = discount_message     @discount_amount = if discount_type == :percent       discount_amount * 0.01     else       Money.new(pennies: 100) * discount_amount     end   end   def apply(shipping_rate)     rate_discount = if @discount_type == :percent       shipping_rate.price * @discount_amount     else       @discount_amount     end     shipping_rate.apply_discount(rate_discount, message: @discount_message)   end end # ================================================================ # DiscountRatesForDiscountCodeCampaign # # Applies the entered discount to the entered rates if the # any of the entered discount codes are used. # ================================================================ class DiscountRatesForDiscountCodeCampaign   def initialize(campaigns)     @campaigns = campaigns   end   def run(cart, shipping_rates)     return if cart.discount_code.nil?     @campaigns.each do |campaign|       discount_code_selector = DiscountCodeSelector.new(campaign[:discount_code_match_type], campaign[:discount_codes])       next unless discount_code_selector.match?(cart.discount_code)       rate_name_selector = RateNameSelector.new(campaign[:rate_match_type], campaign[:rate_names])       discount_applicator = DiscountApplicator.new(         campaign[:discount_type],         campaign[:discount_amount],         campaign[:discount_message],       )       shipping_rates.each do |shipping_rate|         next unless rate_name_selector.match?(shipping_rate)         discount_applicator.apply(shipping_rate)       end     end   end end CAMPAIGNS = [   DiscountRatesForDiscountCodeCampaign.new(DISCOUNTS_FOR_DISCOUNT_CODES), ] CAMPAIGNS.each do |campaign|   campaign.run(Input.cart, Input.shipping_rates) end Output.shipping_rates = Input.shipping_rates

 



#10 Reorder payment gateways 

Category: Payment gateways 

This script enables you to edit the default order of the payment gateways that your customers are presented with. 

 

# ================================ Customizable Settings ================================ # ================================================================ # Reorder Gateways # # The order in which you would like your gateways to display # ================================================================ DESIRED_GATEWAY_ORDER = [   "Payment Gateway 1", "Payment Gateway 2", "Payment Gateway 3", ] # ================================ Script Code (do not edit) ================================ # ================================================================ # ReorderGatewaysCampaign # # Reorders gateways into the entered order # ================================================================ class ReorderGatewaysCampaign   def initialize(desired_order)     @desired_order = desired_order.map { |item| item.downcase.strip }   end   def run(cart, payment_gateways)     payment_gateways.sort_by! { |payment_gateway| @desired_order.index(payment_gateway.name.downcase.strip) || Float::INFINITY }   end end CAMPAIGNS = [   ReorderGatewaysCampaign.new(DESIRED_GATEWAY_ORDER), ] CAMPAIGNS.each do |campaign|   campaign.run(Input.cart, Input.payment_gateways) end Output.payment_gateways = Input.payment_gateways  

 



#11 Show payment gateways to specific customers 

Category: Payment gateways 

If you wish to display certain payment gateway options only to specific customers – for example, shoppers with the ‘VIP’ tag – this is the script to use. 

 

# ================================ Customizable Settings ================================ # ================================================================ # Show Gateways For Customer Tag # # If a customer is tagged (or not, depending on the setting below) # with the entered tag(s), the entered gateway(s) will be shown, and # all others will be hidden. Otherwise, the entered gateway(s) will # be hidden. # #   - 'customer_tag_match_type' determines whether we look for the customer #     to be tagged with any of the entered tags or not. Can be: #       - ':include' to check if the customer is tagged #       - ':exclude' to make sure the customer isn't tagged #   - 'customer_tags' is a list of customer tags to trigger the #     campaign #   - 'gateway_match_type' determines whether the below strings #     should be an exact or partial match. Can be: #       - ':exact' for an exact match #       - ':partial' for a partial match #   - 'gateway_names' is a list of strings to identify gateways # ================================================================ SHOW_GATEWAYS_FOR_CUSTOMER_TAG = [   {     customer_tag_match_type: :include,     customer_tags: ["customer_tag", "another_tag"],     gateway_match_type: :exact,     gateway_names: ["Gateway", "Other Gateway"],   }, ] # ================================ Script Code (do not edit) ================================ # ================================================================ # CustomerTagSelector # # Finds whether the supplied customer has any of the entered tags. # ================================================================ class CustomerTagSelector   def initialize(match_type, tags)     @comparator = match_type == :include ? 'any?' : 'none?'     @tags = tags.map { |tag| tag.downcase.strip }   end   def match?(customer)     customer_tags = customer.tags.map { |tag| tag.downcase.strip }     (@tags & customer_tags).send(@comparator)   end end # ================================================================ # GatewayNameSelector # # Finds whether the supplied gateway name matches any of the # entered names. # ================================================================ class GatewayNameSelector   def initialize(match_type, gateway_names)     @comparator = match_type == :exact ? '==' : 'include?'     @gateway_names = gateway_names.map { |name| name.downcase.strip }   end   def match?(payment_gateway)     @gateway_names.any? { |name| payment_gateway.name.downcase.strip.send(@comparator, name) }   end end # ================================================================ # ShowGatewaysForCustomerTagCampaign # # If the customer has any of the entered tags, the entered gateways # are shown/hidden depending on the entered settings # ================================================================ class ShowGatewaysForCustomerTagCampaign   def initialize(campaigns)     @campaigns = campaigns   end   def run(cart, payment_gateways)     @campaigns.each do |campaign|       customer_tag_selector = CustomerTagSelector.new(         campaign[:customer_tag_match_type],         campaign[:customer_tags],       )       customer_match = cart.customer.nil? ? false : customer_tag_selector.match?(cart.customer)       gateway_name_selector = GatewayNameSelector.new(         campaign[:gateway_match_type],         campaign[:gateway_names],       )       payment_gateways.delete_if do |payment_gateway|         gateway_name_selector.match?(payment_gateway) != customer_match       end     end   end end CAMPAIGNS = [   ShowGatewaysForCustomerTagCampaign.new(SHOW_GATEWAYS_FOR_CUSTOMER_TAG), ] CAMPAIGNS.each do |campaign|   campaign.run(Input.cart, Input.payment_gateways) end Output.payment_gateways = Input.payment_gateways  

 


There you have it – just 11 great Shopify script examples to help your brand to realise the potential this ecommerce platform offers. 

 

Need some extra support?

 

Here at Underwaterpistol, we're Shopify Plus partners. That means we know the platform inside-out.

Our team has over 15 years of experience designing and developing custom Shopify stores that drive sales and delight customers. 

Whether you're just starting out or looking to take your existing store to the next level, we can help. Get in touch to find out how.

Blog