Add Automatic % OFF Sale Badges To Shopify Product Pages

Tanz - Tanz

Why Add Dynamic Sale Badges?

Discounts convert — but only if they’re accurate and visible. A variant-level sale badge tells customers exactly how much they’ll save, even if each size or color has different pricing. It reduces confusion, improves trust, and gives your sale pricing the urgency it deserves.

⚠️ Before You Start

  • Duplicate your theme as a backup
  • Basic comfort editing Shopify Liquid files is required
  • No apps needed — this snippet is 100% theme-code based

Step 1: Enable Sale Badge Settings

From your Shopify admin:

  • Go to Online Store → Themes → Edit code
  • Open config/settings_schema.json
  • Scroll to the end of the array and paste this schema before the last ]:
Copy

,
{
  "name": "Automatic Sale Badge",
  "settings": [
    {
      "type": "checkbox",
      "id": "sale_badge_enable",
      "label": "Enable sale badge",
      "default": true
    },
    {
      "type": "text",
      "id": "sale_badge_prefix_text",
      "label": "Prefix text",
      "default": "Save"
    },
    {
      "type": "color",
      "id": "sale_badge_bg_color",
      "label": "Background color",
      "default": "#C9584C"
    },
    {
      "type": "color",
      "id": "sale_badge_text_color",
      "label": "Text color",
      "default": "#FFFFFF"
    },
    {
      "type": "color",
      "id": "sale_badge_border_color",
      "label": "Border color",
      "default": "#F6EDDD"
    },
    {
      "type": "range",
      "id": "sale_badge_font_size",
      "min": 10,
      "max": 20,
      "step": 1,
      "unit": "px",
      "label": "Font size",
      "default": 13
    }
  ]
}

Save the file. You’ll now see a new “Automatic Sale Badge” settings panel in the Theme Editor.

Step 2: Add The Automatic Sale Badge Snippet

Still in the code editor:

  • Under the Snippets folder, create a New file
  • Name it: an-automatic-sale-badge.liquid
  • Paste this code:
Copy

{%- if settings.sale_badge_enable -%}
  {%- assign initial_variant = product.selected_or_first_available_variant -%}
  {%- if initial_variant.compare_at_price > initial_variant.price -%}
    <span 
      id="dynamic-sale-badge-{{ product.id }}-{{ initial_variant.id }}" 
      class="xlr_badge"
      style="
        background-color: {{ settings.sale_badge_bg_color }};
        color: {{ settings.sale_badge_text_color }};
        border: 1px solid {{ settings.sale_badge_border_color }};
        font-size: {{ settings.sale_badge_font_size }}px;
        margin-left: 5px;
        padding: 4px 12px;
        border-radius: 9999px;
        line-height: 1.1;
        vertical-align: middle;
        display: inline-block;
      "
    >
      {{ settings.sale_badge_prefix_text }} 
      {{ initial_variant.compare_at_price | minus: initial_variant.price | times: 100 | divided_by: initial_variant.compare_at_price | round }}%
    </span>
  {%- endif -%}

  <script>
  document.addEventListener("DOMContentLoaded", () => {
    const productId = "{{ product.id }}";
    const initialVariantId = "{{ initial_variant.id }}";
    const badge = document.getElementById(`dynamic-sale-badge-${productId}-${initialVariantId}`);
    if (!badge) return;

    const variants = {{ product.variants | json }};

    function updateSaleBadge(variantId) {
      const v = variants.find(v => v.id == variantId);
      if (v && v.compare_at_price > v.price) {
        const discount = ((v.compare_at_price - v.price) / v.compare_at_price) * 100;
        badge.textContent = `{{ settings.sale_badge_prefix_text }} ${Math.round(discount)}%`;
        badge.style.display = "inline-block";
      } else {
        badge.style.display = "none";
      }
    }

    const form = badge.closest('[id^="product-form"], form[action*="/cart/add"]');
    if (form) {
      const hiddenInput = form.querySelector('input[name="id"]');
      if (hiddenInput) updateSaleBadge(hiddenInput.value);
      hiddenInput?.addEventListener("change", () => updateSaleBadge(hiddenInput.value));
    }

    ["variant:changed", "variantChange", "variantUpdate"].forEach(evt => {
      document.addEventListener(evt, e => {
        if (e.detail?.variant && e.detail.variant.product_id == productId) {
          updateSaleBadge(e.detail.variant.id);
        }
      });
    });
  });
  </script>
{%- endif -%}
  • Save the snippet

Step 3: Insert The Snippet In Product Price

Now attach the badge to your product price. In the theme edit code editor Open:

  • Global search by pressing Ctrl+Shift+F
  • Type compare_at_price in the search box
  • Identify the .liquid file(s) where the badge appears
  • It will be snippets/price.liquid (or main-product.liquid depending on theme)
  • Find the line with: {{ compare_at_price }} or {{ money_price }} object
  • Paste this right after that line, inside the same block or class:
Copy

{% render 'an-automatic-sale-badge' %}
  • Save the file

Step 5: Customize In Theme Editor

In your theme:

  • Go to Online Store → Themes → Customize
  • In the theme editor, click the Theme settings icon
  • Select Automatic Sale Badge
  • Toggle badge on/off
  • Change prefix text (e.g., “Save” → “Discount”)
  • Pick colors, border, and font size

Click Save to apply your changes.

Real-World Insight

Shoppers instantly see how much they’re saving per variant. This builds trust and urgency while keeping product pages clean. Dynamic sale badges are especially powerful for stores with size/color-specific markdowns.

Final Thoughts

Discounting isn’t new — but presenting discounts in real-time is what sets high-performing stores apart. With this lightweight snippet, your Shopify product pages will display accurate, customizable sale badges that adapt instantly as variants change. It’s app-free, fast, and conversion-focused.

Back to blog