Back to Blog
Advanced8 min readJanuary 2024

Building Custom Checkout Components: The Complete Shopify Liquid Guide

Transform your checkout from a conversion killer into a conversion machine. Learn how to build trust badges, upsells, progress indicators, and social proof that increase completion rates by up to 35%.

TL;DR

  • • Trust badges increase checkout completion by 23%
  • • Progress indicators reduce abandonment by 18%
  • • Smart upsells can boost AOV by 15-25%
  • • Social proof elements build confidence
  • • Mobile-first design is critical for conversions

💳 Want these components built instantly? Generate checkout components with AI

The Checkout Conversion Crisis

Average Cart Abandonment Rates

69.8%
Overall Average
85.2%
Mobile Checkout
$4.6T
Lost Revenue (Annually)

1. Trust Badges That Actually Convert

Trust badges are your first line of defense against checkout anxiety. Here's how to implement them strategically:

<!-- Trust badges section with conditional display -->
{% assign trust_badges = section.settings.trust_badges %}
{% if trust_badges.size > 0 %}
  <div class="checkout-trust-badges" role="banner" aria-label="Security and trust indicators">
    <h3 class="trust-badges__title">Your order is protected by:</h3>
    
    <div class="trust-badges__grid">
      {% for badge in trust_badges %}
        <div class="trust-badge" data-badge="{{ badge.type }}">
          {% if badge.icon %}
            <img src="{{ badge.icon | img_url: '48x48' }}" 
                 alt="{{ badge.title | escape }}"
                 width="24" height="24" loading="lazy">
          {% endif %}
          
          <div class="trust-badge__content">
            <span class="trust-badge__title">{{ badge.title | escape }}</span>
            {% if badge.description %}
              <span class="trust-badge__desc">{{ badge.description | escape }}</span>
            {% endif %}
          </div>
        </div>
      {% endfor %}
    </div>
  </div>
{% endif %}

2. Smart Progress Indicators

Show customers exactly where they are in the checkout process. This reduces anxiety and abandonment:

<!-- Dynamic progress indicator -->
{% assign checkout_steps = 'Cart,Shipping,Payment,Complete' | split: ',' %}
{% assign current_step = template.name %}

<div class="checkout-progress" role="navigation" aria-label="Checkout progress">
  <ol class="progress-steps">
    {% for step in checkout_steps %}
      {% assign step_slug = step | downcase | replace: ' ', '-' %}
      {% assign step_number = forloop.index %}
      
      {% comment %} Determine step status {% endcomment %}
      {% liquid
        assign step_status = 'pending'
        case current_step
          when 'cart'
            if step_slug == 'cart'
              assign step_status = 'current'
            endif
          when 'checkout'
            if step_slug == 'cart'
              assign step_status = 'completed'
            elsif step_slug == 'shipping'
              assign step_status = 'current'
            endif
          when 'checkout-payment'
            if step_slug == 'cart' or step_slug == 'shipping'
              assign step_status = 'completed'
            elsif step_slug == 'payment'
              assign step_status = 'current'
            endif
        endcase
      %}
      
      <li class="progress-step progress-step--{{ step_status }}" 
          aria-current="{% if step_status == 'current' %}step{% else %}false{% endif %}">
        <div class="progress-step__indicator">
          {% if step_status == 'completed' %}
            <svg class="progress-check" viewBox="0 0 20 20" fill="currentColor">
              <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
            </svg>
          {% else %}
            <span class="progress-number">{{ step_number }}</span>
          {% endif %}
        </div>
        <span class="progress-step__label">{{ step }}</span>
      </li>
    {% endfor %}
  </ol>
</div>

3. Strategic Upsell Components

The checkout page is your last chance to increase order value. Here's how to do it without being pushy:

<!-- Smart upsell based on cart contents -->
{% liquid
  assign cart_total = cart.total_price
  assign upsell_threshold = settings.upsell_threshold | default: 7500
  assign remaining_for_free_shipping = settings.free_shipping_threshold | minus: cart_total
%}

{% comment %} Show different upsells based on cart value {% endcomment %}
<div class="checkout-upsells">
  {% if remaining_for_free_shipping > 0 and remaining_for_free_shipping <= 2500 %}
    <!-- Free shipping upsell -->
    <div class="upsell-banner upsell-banner--shipping">
      <div class="upsell-banner__icon">🚚</div>
      <div class="upsell-banner__content">
        <strong>Add {{ remaining_for_free_shipping | money }} more for FREE shipping!</strong>
        <p>You're almost there. Add one of these popular items:</p>
      </div>
    </div>
  {% endif %}
  
  {% comment %} Show complementary products {% endcomment %}
  {% assign upsell_products = collections.upsells.products | where: 'available', true %}
  {% if upsell_products.size > 0 %}
    <div class="upsell-products">
      <h3 class="upsell-products__title">Complete your order</h3>
      
      <div class="upsell-products__grid">
        {% for product in upsell_products limit: 3 %}
          <div class="mini-product-card" data-product-id="{{ product.id }}">
            <img src="{{ product.featured_image | img_url: '120x120' }}" 
                 alt="{{ product.title | escape }}"
                 class="mini-product-card__image" loading="lazy">
            
            <div class="mini-product-card__content">
              <h4 class="mini-product-card__title">{{ product.title | truncate: 30 | escape }}</h4>
              <div class="mini-product-card__price">
                {% if product.compare_at_price > product.price %}
                  <span class="price-compare">{{ product.compare_at_price | money }}</span>
                {% endif %}
                <span class="price-current">{{ product.price | money }}</span>
              </div>
              
              <button type="button" 
                      class="btn btn--small btn--add-upsell"
                      data-variant-id="{{ product.selected_or_first_available_variant.id }}"
                      aria-label="Add {{ product.title | escape }} to cart">
                Add to Order
              </button>
            </div>
          </div>
        {% endfor %}
      </div>
    </div>
  {% endif %}
</div>

4. Social Proof Elements

Build confidence with social proof that shows other customers making purchases:

<!-- Social proof notifications -->
<div class="social-proof-ticker" role="status" aria-label="Recent customer activity">
  {% comment %} Mock data - replace with real customer data {% endcomment %}
  {% assign recent_purchases = 'John from New York,Sarah from London,Mike from Toronto,Lisa from Sydney' | split: ',' %}
  {% assign product_names = 'Pro Bundle,Starter Kit,Premium Package,Essential Set' | split: ',' %}
  
  <div class="social-proof-ticker__container">
    {% for customer in recent_purchases %}
      {% assign random_product = product_names | sample %}
      {% assign minutes_ago = forloop.index | times: 7 | plus: 3 %}
      
      <div class="social-proof-item" data-delay="{{ forloop.index | times: 8000 }}">
        <div class="social-proof-item__avatar">
          <div class="avatar-placeholder">{{ customer | split: ' ' | first | slice: 0, 1 }}</div>
        </div>
        
        <div class="social-proof-item__content">
          <strong>{{ customer }}</strong> purchased 
          <span class="product-name">{{ random_product }}</span>
          <time class="time-ago">{{ minutes_ago }} minutes ago</time>
        </div>
        
        <div class="social-proof-item__icon">
          <svg class="icon-check" viewBox="0 0 20 20" fill="currentColor">
            <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
          </svg>
        </div>
      </div>
    {% endfor %}
  </div>
</div>

<!-- Customer count display -->
<div class="customer-count-badge">
  <span class="customer-count-number">2,847</span> happy customers this month
</div>

5. Mobile-First Payment Security

85% of cart abandonment happens on mobile. Here's how to build mobile-optimized security displays:

<!-- Mobile-optimized security section -->
<div class="checkout-security" role="complementary" aria-label="Payment security information">
  <div class="security-header">
    <Shield class="security-icon" />
    <h3>Secure Checkout</h3>
  </div>
  
  <div class="security-features">
    <!-- SSL Badge -->
    <div class="security-feature">
      <div class="security-feature__icon">🔒</div>
      <div class="security-feature__content">
        <strong>SSL Encrypted</strong>
        <small>Your data is protected</small>
      </div>
    </div>
    
    <!-- Payment methods -->
    <div class="security-feature">
      <div class="security-feature__icon">💳</div>
      <div class="security-feature__content">
        <strong>Secure Payments</strong>
        <div class="payment-methods">
          {% for payment_type in shop.enabled_payment_types %}
            <img src="{{ payment_type | payment_type_img_url }}" 
                 alt="{{ payment_type | capitalize }}"
                 class="payment-method-icon" loading="lazy">
          {% endfor %}
        </div>
      </div>
    </div>
    
    <!-- Guarantee -->
    <div class="security-feature">
      <div class="security-feature__icon">✅</div>
      <div class="security-feature__content">
        <strong>30-Day Guarantee</strong>
        <small>Risk-free purchase</small>
      </div>
    </div>
  </div>
</div>

Measuring Success: Key Metrics

Checkout Optimization Impact

+23%
Completion Rate
With trust badges
+18%
Reduced Abandonment
Progress indicators
+25%
Average Order Value
Smart upsells
+15%
Mobile Conversions
Optimized design

Build Conversion-Optimized Checkouts

Stop losing customers at the final step. Generate checkout components that build trust, reduce friction, and increase conversions automatically.

checkoutliquidconversionsadvanced