Shopify Capping Number of Customer Orders You Can Loop Through?

Topic summary

A developer implemented Liquid code on product pages to alert logged-in customers if they’ve previously purchased an item. The feature works for customers with few orders but fails for those with 100+ orders.

Root Cause:

  • Shopify Liquid limits customer.orders to approximately 50 orders by default
  • Nested loops create performance constraints that can cause page rendering timeouts
  • No native pagination exists for customer.orders in Liquid

Proposed Solutions:

  1. Use Shopify APIs (Recommended): Leverage Admin API or Storefront API with JavaScript to query all customer orders programmatically, bypassing Liquid’s limitations

  2. JavaScript-based approach: Fetch order data via AJAX and process client-side for better performance with large datasets

  3. Limit scope: Restrict the loop to recent orders only (e.g., customer.orders | limit: 10) as a practical compromise

Consensus: Liquid has inherent constraints for large datasets. For scalable implementation, API-based solutions with JavaScript or server-side processing are necessary to handle customers with extensive order histories.

Summarized with AI on November 2. AI used: claude-sonnet-4-5-20250929.

I have implemented custom code in my Product page to essentially loop through all of a logged in Customer’s orders and alert them if they’ve already purchased that Product in the past.

It seems to work fine with Customers that have a limited number of Orders in the past but for Customers with 100+ orders, we are seeing the process break down and not show the alert as expected.

Does anyone know if Shopify limits the number of Orders + Line Items + Product Variants you can loop through in a single request? If so, any way around this?

Snippet of my code with nested loops –

{% if customer %}
  {% assign has_purchased = false %}
  {% assign last_purchase_date = '' %}

  
  {% for order in customer.orders %}
    
    {% for line_item in order.line_items %}
      {% if line_item.product_id == product.id %}
        {% assign has_purchased = true %}
        {% assign last_purchase_date = order.created_at %}
        {% break %}
      {% endif %}
    {% endfor %}
    {% if has_purchased %}
      {% break %}
    {% endif %}
  {% endfor %}

  
  {% if has_purchased %}
    
     You purchased this Product on  {{ last_purchase_date | date: "%B %d, %Y" }}
    

  {% endif %}
{% endif %}

Hi there,

This is Jay from Fast Bunde. I hope you are doing well.

The issue you’re encountering is likely due to Shopify’s Liquid limitations. Shopify imposes constraints on both the amount of data you can loop through and the overall complexity of Liquid operations. Here’s a breakdown of the problem and how to work around it.


Why This Happens1. Order Query Limitations:

  • Shopify Liquid limits the number of orders that can be accessed within the customer.orders object. While there isn’t an officially documented hard limit, Shopify typically caps the number of items returned by an object in Liquid to 50 by default. If a customer has more than 50 orders, Liquid won’t load all of them in the loop.
  1. Performance Constraints:
    • Even if you were able to loop through a larger number of orders, nested loops (like in your code) can be resource-intensive. This can cause the page rendering to time out for customers with many orders.

Workarounds#### 1. Use Shopify’s Admin API or Storefront API

Shopify’s Liquid is limited when it comes to handling large datasets. The recommended approach for this use case is to leverage Shopify’s Admin API or Storefront API in conjunction with JavaScript. With the API, you can query all of a customer’s orders and process the data on the client or server side.

Here’s an example of how you could use the Shopify Admin API with JavaScript (assuming you have access to create custom apps):

  • Query the customer’s orders via the API.
  • Loop through all orders programmatically to check if the product has been purchased.
  • Display the alert dynamically.

Here’s a rough outline of the steps:

  • Create a private or custom app in Shopify to get an Admin API key.
  • Use JavaScript on the product page to fetch the orders and check for matches.

2. Paginate Orders in Liquid (if possible)

If you want to stick to Liquid only, you’ll need to account for the 50-order limit by paginating the data. Unfortunately, Shopify Liquid doesn’t allow direct pagination for customer.orders, but you could implement custom logic to retrieve subsets of orders via metafields or other workarounds. This is tricky and may not scale well.

3. Use JavaScript with Shopify’s customer.orders for Incremental Checks

You can use JavaScript to handle the alert dynamically, looping through the available orders Liquid provides and checking incrementally:

<!-- Pass customer order data into JavaScript -->
{% if customer %}
  <script>
    var orders = [];
    {% for order in customer.orders %}
      orders.push({
        id: {{ order.id }},
        created_at: "{{ order.created_at }}",
        line_items: [
          {% for line_item in order.line_items %}
            { product_id: {{ line_item.product_id }} },
          {% endfor %}
        ]
      });
    {% endfor %}
    
    var productId = {{ product.id }};
    
    // Check if the product was previously purchased
    var hasPurchased = false;
    var lastPurchaseDate = '';
    orders.forEach(function(order) {
      order.line_items.forEach(function(item) {
        if (item.product_id === productId) {
          hasPurchased = true;
          lastPurchaseDate = order.created_at;
        }
      });
    });

    if (hasPurchased) {
      document.write('<div class="purchased-before-badge" style="background-color: #ffcc00; color: black; padding: 10px; font-weight: bold; border-radius: 5px; display: inline-block;">' +
        'You purchased this Product on ' + new Date(lastPurchaseDate).toLocaleDateString() +
        '</div>');
    }
  </script>
{% endif %}

This solution offloads the data processing to JavaScript, which can be more performant for large datasets.

4. Limit the Scope of Data in Liquid

If you absolutely must stick to Liquid, consider limiting the scope of your check to the most recent orders (e.g., 10 or 20). For example:

{% for order in customer.orders | limit: 10 %}

This limits the loop to the 10 most recent orders, reducing the risk of hitting Liquid limitations. While not perfect, it’s a practical compromise for most customers.


Final Recommendation

For a scalable solution, use the Shopify Admin API or Storefront API with JavaScript or a server-side script. Liquid has inherent limitations when working with large datasets, and APIs are the best way to bypass these constraints while maintaining performance.