Skip to content
Discount Codes in Cart - Free Tutorial
Browse other ways to boost conversion rate & profit

Discount Codes in Cart - Free Tutorial

In this tutorial, we add a cart discount code field to let customers apply discounts directly in the cart. This upgrade can boost your conversion rate by reducing friction in the buying journey while giving customers an instant dopamine hit with their savings.

Compatible Themes: This code should work on all free Shopify themes (Dawn, Refresh, Craft, Studio, Publisher, Crave, Origin, Taste, Colorblock, Sense, Ride, Spotlight).

 

Edit settings_schema.json

  {
    "name": "Cart Discount Settings",
    "settings": [
      {
        "type": "header",
        "content": "General"
      },
      {
        "type": "checkbox",
        "id": "enable_cart_discounts",
        "label": "Enable Cart Discounts",
        "default": false
      },
  
      {
        "type": "header",
        "content": "Cart Discount Messaging"
      },
      {
        "type": "text",
        "id": "cart_discount_apply_btn_text",
        "label": "Apply discount button text",
        "default": "Apply"
      },
      {
        "type": "text",
        "id": "cart_discount_input_placeholder",
        "label": "Discount code input placeholder",
        "default": "Enter discount code"
      },
      {
        "type": "checkbox",
        "id": "enable_cart_discount_message",
        "label": "Show cart discount message",
        "default": false
      },
      {
        "type": "text",
        "id": "cart_discount_message",
        "label": "Cart discount message",
        "default": "Shipping discounts can be added at checkout.",
        "info": "Displayed on the cart to inform customers about discounts, if enabled."
      },  
      {
        "type": "header",
        "content": "Input Field Styling"
      },
      {
        "type": "color",
        "id": "cart_discount_input_text_color",
        "label": "Discount input text color",
        "default": "#000000"
      },
      {
        "type": "color",
        "id": "cart_discount_input_placeholder_color",
        "label": "Discount input placeholder color",
        "default": "#888888"
      },
      {
        "type": "color",
        "id": "cart_discount_input_bg_color",
        "label": "Discount input background color",
        "default": "#ffffff"
      },
      {
        "type": "color",
        "id": "cart_discount_input_border_color",
        "label": "Discount input border color",
        "default": "#cccccc"
      },
      {
        "type": "range",
        "id": "cart_discount_input_font_size",
        "label": "Input font size",
        "default": 1.4,
        "min": 1,
        "max": 2,
        "step": 0.1,
        "unit": "rem"
      },
      {
        "type": "range",
        "id": "cart_discount_input_padding_vertical",
        "label": "Input vertical padding",
        "default": 1,
        "min": 0.5,
        "max": 2,
        "step": 0.1,
        "unit": "rem"
      },
  
      {
        "type": "header",
        "content": "Apply Button Styling"
      },
      {
        "type": "color",
        "id": "cart_discount_button_bg_color",
        "label": "Apply button background color",
        "default": "#121212"
      },
      {
        "type": "color",
        "id": "cart_discount_button_text_color",
        "label": "Apply button text color",
        "default": "#ffffff"
      },
      {
        "type": "range",
        "id": "cart_discount_button_font_size",
        "label": "Apply button font size",
        "default": 1.4,
        "min": 1,
        "max": 2,
        "step": 0.1,
        "unit": "rem"
      },
  
      {
        "type": "header",
        "content": "Discount Pill Styling"
      },
      {
        "type": "range",
        "id": "discount_pill_font_size",
        "label": "Discount pill font size",
        "default": 1.3,
        "min": 1,
        "max": 2,
        "step": 0.1,
        "unit": "rem"
      },
      {
        "type": "color",
        "id": "discount_pill_bg_color",
        "label": "Discount pill background color",
        "default": "#f1f1f1"
      },
      {
        "type": "color",
        "id": "discount_pill_text_color",
        "label": "Discount pill text color",
        "default": "#333333"
      },
  
      {
        "type": "header",
        "content": "Discount Note Styling"
      },
      {
        "type": "color",
        "id": "cart_discount_note_text_color",
        "label": "Cart discount note text color",
        "default": "#333333"
      },
      {
        "type": "range",
        "id": "cart_discount_note_font_size",
        "label": "Cart discount note font size",
        "min": 1,
        "max": 2,
        "step": 0.1,
        "default": 1.3,
        "unit": "rem"
      },
      {
        "type": "header",
        "content": "Error Message Appearance"
      },
      {
        "type": "color",
        "id": "cart_discount_error_text_color",
        "label": "Discount error message text color",
        "default": "#b10000"
      },
      {
        "type": "range",
        "id": "cart_discount_error_font_size",
        "label": "Discount error message font size",
        "default": 1.3,
        "min": 1,
        "max": 2,
        "step": 0.1,
        "unit": "rem"
      },
  
      {
        "type": "header",
        "content": "Error Messages (Text)"
      },
      {
        "type": "text",
        "id": "cart_discount_error_no_code",
        "label": "Error: No code entered",
        "default": "Please enter a discount code."
      },
      {
        "type": "text",
        "id": "cart_discount_error_already_applied",
        "label": "Error: Code already applied",
        "default": "That discount code is already applied."
      },
      {
        "type": "text",
        "id": "cart_discount_error_invalid",
        "label": "Error: Invalid or not applicable",
        "default": "Discount code is invalid or not applicable."
      }
    ]
  }

Edit main-cart-items.liquid and cart-drawer.liquid

Conditionally add styling variables and scripts if feature is enabled.

  {% if settings.enable_cart_discounts %}
    <style>
      :root {
        --discount-pill-bg: {{ settings.discount_pill_bg_color }};
        --discount-pill-text: {{ settings.discount_pill_text_color }};
        --discount-pill-font-size: {{ settings.discount_pill_font_size }}rem;
    
        --discount-input-padding-vertical: {{ settings.cart_discount_input_padding_vertical }}rem;
        --discount-input-font-size: {{ settings.cart_discount_input_font_size }}rem;
        --discount-input-text-color: {{ settings.cart_discount_input_text_color }};
        --discount-input-placeholder-color: {{ settings.cart_discount_input_placeholder_color }};
        --discount-input-bg-color: {{ settings.cart_discount_input_bg_color }};
        --discount-input-border-color: {{ settings.cart_discount_input_border_color }};
    
        --discount-button-font-size: {{ settings.cart_discount_button_font_size }}rem;
        --discount-button-bg-color: {{ settings.cart_discount_button_bg_color }};
        --discount-button-text-color: {{ settings.cart_discount_button_text_color }};
        
        --cart-discount-note-text-color: {{ settings.cart_discount_note_text_color }};
        --cart-discount-note-font-size: {{ settings.cart_discount_note_font_size }}rem;

        --cart-discount-error-text-color: {{ settings.cart_discount_error_text_color }};
        --cart-discount-error-font-size: {{ settings.cart_discount_error_font_size }}rem;

      }
    </style>
    <script>
      window.cartDiscountStrings = {
        errorNoCode: "{{ settings.cart_discount_error_no_code | escape }}",
        errorAlreadyApplied: "{{ settings.cart_discount_error_already_applied | escape }}",
        errorInvalid: "{{ settings.cart_discount_error_invalid | escape }}"
      };
    </script>
    <script src="{{ 'cart-discount-codes-custom.js' | asset_url }}" defer="defer"></script>
  {% endif %}

Edit cart-drawer.liquid

Render the discount code input code

{% render 'cart-discount-codes-custom' %}

Edit main-cart-footer.liquid

Render the discount code input code

{%- unless settings.cart_type == 'drawer' -%}
  {% render 'cart-discount-codes-custom' %}
{%- endunless -%}

Create new file cart-discount-codes-custom.liquid

{% if settings.enable_cart_discounts %}
  {% assign discount_codes = '' %}

  {% for discount_application in cart.cart_level_discount_applications %}
    {% unless discount_codes == '' %}
      {% assign discount_codes = discount_codes | append: ',' %}
    {% endunless %}
    {% assign discount_codes = discount_codes | append: discount_application.title %}
  {% endfor %}

  {% for item in cart.items %}
    {% for allocation in item.line_level_discount_allocations %}
      {% unless discount_codes contains allocation.discount_application.title %}
        {% unless discount_codes == '' %}
          {% assign discount_codes = discount_codes | append: ',' %}
        {% endunless %}
        {% assign discount_codes = discount_codes | append: allocation.discount_application.title %}
      {% endunless %}
    {% endfor %}
  {% endfor %}

  <div id="discount-code-container">
    {% if settings.enable_cart_discount_message and settings.cart_discount_message != blank %}
      <div class="cart-discount-note">
        {{ settings.cart_discount_message }}
      </div>
    {% endif %}

    <div id="discount-error-message"></div>

    <form id="discount-form" onsubmit="return false;">
      <input
        type="text"
        id="discount-input"
        placeholder="{{ settings.cart_discount_input_placeholder | escape }}"
        aria-label="Discount code"
      >
      <button type="button" id="apply-discount-btn">
        {{ settings.cart_discount_apply_btn_text | escape }}
      </button>
    </form>

    <div id="applied-discounts">
      {% if discount_codes != '' %}
        {% assign codes_array = discount_codes | split: ',' %}
        {% for code in codes_array %}
          <span class="discount-pill" data-code="{{ code | escape }}">
            <span class="svg-wrapper discount-icon">
              {{ 'icon-price-tag.svg' | inline_asset_content }}
            </span>
            {{ code }}
            <button
              type="button"
              class="remove-discount"
              aria-label="Remove discount code {{ code }}"
            >
              <span class="svg-wrapper">
                {{ 'icon-close.svg' | inline_asset_content }}
              </span>
            </button>
          </span>
        {% endfor %}
      {% endif %}
    </div>
  </div>

  <style>
    #discount-code-container {
      margin: 1rem 0;
    }

    #discount-form {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      margin-bottom: 0.75rem;
    }
    #discount-input {
      color: var(--discount-input-text-color);
      background-color: var(--discount-input-bg-color);
      flex: 1;
      min-width: 150px;
      padding: var(--discount-input-padding-vertical) 1rem;
      border: 1px solid var(--discount-input-border-color);
      border-radius: 4px;
      font-size: var(--discount-input-font-size);
    }
    #discount-input::placeholder {
      color: var(--discount-input-placeholder-color);
    }

    #apply-discount-btn {
      padding: var(--discount-input-padding-vertical) 2rem;
      background-color: var(--discount-button-bg-color);
      color: var(--discount-button-text-color);
      cursor: pointer;
      border: none;
      border-radius: 4px;
      font-size: var(--discount-button-font-size);
    }
    #apply-discount-btn:hover {
      filter: brightness(0.9);
    }

    #applied-discounts {
      display: flex;
      flex-wrap: wrap;
      gap: 0.5rem;
    }

    .discount-pill {
      display: inline-flex;
      align-items: center;
      background-color: var(--discount-pill-bg);
      color: var(--discount-pill-text);
      font-size: var(--discount-pill-font-size);
      padding: 0.4rem 1rem;
      border-radius: 4px;
      white-space: nowrap;
    }
    .discount-pill svg {
      width: var(--discount-pill-font-size);
      height: var(--discount-pill-font-size);
      color: var(--discount-pill-text);
      fill: var(--discount-pill-text);
    }
    .discount-pill .discount-icon {
      margin-right: 0.5rem;
    }
    .discount-pill .remove-discount {
      background: transparent;
      border: none;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      margin-left: 1rem;
      outline: none;
      padding: 0;
    }
    .discount-pill .remove-discount:hover {
      opacity: 0.7;
    }
    .discount-pill .remove-discount .svg-wrapper svg {
      width: 12px;
      height: 12px;
    }

    .cart-discount-note {
      color: var(--cart-discount-note-text-color);
      font-size: var(--cart-discount-note-font-size);
    }

    #discount-error-message {
      color: var(--cart-discount-error-text-color);
      font-size: var(--cart-discount-error-font-size);
      margin: 0.5rem 0;
      display: none;
    }
  </style>
{% endif %}

Create new file cart-discount-codes-custom.js

(() => {
  function initDiscountScript() {
    const appliedDiscountsContainer = document.getElementById('applied-discounts');
    const applyBtn = document.getElementById('apply-discount-btn');
    const discountInput = document.getElementById('discount-input');

    if (!appliedDiscountsContainer || !applyBtn || !discountInput) return;

    const strings = window.cartDiscountStrings || {};
    const MSG_NO_CODE = strings.errorNoCode || "Please enter a discount code.";
    const MSG_ALREADY_APPLIED = strings.errorAlreadyApplied || "That discount code is already applied.";
    const MSG_INVALID = strings.errorInvalid || "Discount code is invalid or not applicable.";

    function clearMessages() {
      const errDiv = document.getElementById('discount-error-message');
      if (errDiv) {
        errDiv.style.display = 'none';
        errDiv.textContent = '';
      }
    }

    function showError(msg) {
      const errDiv = document.getElementById('discount-error-message');
      if (errDiv) {
        errDiv.style.display = 'block';
        errDiv.textContent = msg;
      }
    }

    function getCurrentDiscounts() {
      const pills = document.querySelectorAll('#applied-discounts .discount-pill');
      return Array.from(pills).map((pill) => pill.getAttribute('data-code').toUpperCase());
    }

    function triggerCartUpdate() {
      const cartDrawerItems = document.querySelector('cart-drawer-items');
      if (cartDrawerItems && typeof cartDrawerItems.updateQuantity === 'function') {
        const qtyInput =
          document.getElementById('Drawer-quantity-1') ||
          document.getElementById('Quantity-1');
        if (qtyInput) {
          const currentQty = parseInt(qtyInput.value, 10) || 1;
          cartDrawerItems.updateQuantity(1, currentQty);
          return;
        } else {
          cartDrawerItems.onCartUpdate();
          return;
        }
      }

      const cartItems = document.querySelector('cart-items');
      if (cartItems && typeof cartItems.updateQuantity === 'function') {
        const qtyInput =
          document.getElementById('Quantity-1') ||
          document.getElementById('Drawer-quantity-1');
        if (qtyInput) {
          const currentQty = parseInt(qtyInput.value, 10) || 1;
          cartItems.updateQuantity(1, currentQty);
          return;
        } else {
          cartItems.onCartUpdate();
          return;
        }
      }
    }

    async function applyDiscounts(discountCodes = []) {
      let isRemoving = false;
      if (discountCodes.length === 0) {
        discountCodes = ['REMOVE_SHOPIFY_CODE'];
        isRemoving = true;
      }
      const discountString = discountCodes.join(',');
      const checkoutUrl = `/checkout?discount=${encodeURIComponent(discountString)}`;

      try {
        await fetch(checkoutUrl, { method: 'GET' });
      } catch (err) {}

      const cartRes = await fetch('/cart.js');
      const cartData = await cartRes.json();

      const validSet = new Set();
      (cartData.cart_level_discount_applications || []).forEach(d => validSet.add(d.title.toUpperCase()));
      cartData.items.forEach(item => {
        (item.line_level_discount_allocations || []).forEach(a => {
          validSet.add(a.discount_application.title.toUpperCase());
        });
      });

      const invalidCodes = discountCodes.filter(c => !validSet.has(c.toUpperCase()));
      const newlyAddedCode = discountCodes[discountCodes.length - 1];
      const codeIsInvalid = invalidCodes.includes(newlyAddedCode);

      if (newlyAddedCode === 'REMOVE_SHOPIFY_CODE' || !codeIsInvalid) {
        triggerCartUpdate();
      }
      return {
        success: !codeIsInvalid || isRemoving,
        invalidCodes
      };
    }

    applyBtn.addEventListener('click', async () => {
      clearMessages();
      const existingCodes = getCurrentDiscounts();
      let newCode = discountInput.value.trim().toUpperCase();
      if (!newCode) {
        showError(MSG_NO_CODE);
        return;
      }
      if (existingCodes.includes(newCode)) {
        showError(MSG_ALREADY_APPLIED);
        return;
      }
      const combinedCodes = [...existingCodes, newCode];
      const result = await applyDiscounts(combinedCodes);
      if (result.invalidCodes.map(c => c.toUpperCase()).includes(newCode)) {
        showError(MSG_INVALID);
      }
    });

    appliedDiscountsContainer.addEventListener('click', async (event) => {
      if (!event.target.closest('.remove-discount')) return;
      clearMessages();
      const pill = event.target.closest('.discount-pill');
      if (!pill) return;
      const codeToRemove = pill.getAttribute('data-code');
      if (!codeToRemove) return;
      const existingCodes = getCurrentDiscounts();
      const newDiscountList = existingCodes.filter(c => c !== codeToRemove.toUpperCase());
      await applyDiscounts(newDiscountList);
    });
  }

  document.addEventListener('DOMContentLoaded', () => {
    initDiscountScript();
  });

  if (typeof subscribe === 'function' && typeof PUB_SUB_EVENTS !== 'undefined') {
    subscribe(PUB_SUB_EVENTS.cartUpdate, () => {
      initDiscountScript();
    });
  }
})();

Browse other ways to boost conversion rate & profit