ds@mcpanalytics.aiEmail your data and your question and get an answer about your own data, with the method shown.Email your data and question. Get an answer.

How to Use Item Quantity and Basket Analysis in WooCommerce: Step-by-Step Tutorial

Updated October 2026

Published by MCP Analytics | Category: WooCommerce Analytics

Introduction to Item Quantity and Basket Analysis

Understanding what customers buy together and in what quantities is crucial for optimizing your WooCommerce store's performance. Item quantity and basket analysis reveals purchasing patterns that point to opportunities in product placement, bundling and cross-selling.

In this tutorial, you'll learn how to analyze your WooCommerce order data to answer critical business questions: What's the typical basket size in your store? Which products are frequently purchased together? Are there opportunities for product bundles that customers are already creating organically?

Unlike traditional analytics that focus solely on individual product performance, basket analysis examines the relationships between products and the aggregate behavior of your customers. This approach, similar to techniques used in AI-first data analysis pipelines, provides actionable insights that can transform your store's profitability.

Prerequisites and What You'll Need

Before You Begin

To successfully complete this tutorial, you'll need:

Required Data Fields

Your export should include these essential fields:

Step 1: Understanding Item Quantity and Basket Analysis Fundamentals

Before diving into the data, it's essential to understand what basket analysis can reveal about your store:

Key Metrics You'll Discover

Average Basket Size

This metric tells you how many items, on average, customers purchase per transaction. Track it over time as a baseline for bundling and promotion changes.

Example: An average basket size of 2.3 items is a mean over orders. It does not tell you that most orders hold two or three items: a store can reach 2.3 with many single-item orders and a few large ones. Read the basket size distribution (below) for the share of orders at each size, and use the mean as a baseline to compare against after you try bundling or promotions.

Product Affinity

Product affinity measures how often products appear together in the same order. High affinity between two products suggests a natural bundling opportunity.

Basket Size Distribution

Understanding the distribution of basket sizes (how many customers buy 1 item vs. 2 items vs. 5 items) helps you identify customer segments and tailor marketing strategies accordingly.

Why This Analysis Matters

Step 2: Exporting Your WooCommerce Order Data

The quality of your analysis depends entirely on the quality of your data export. Follow these steps to ensure you capture all necessary information:

Method 1: An Order-Export Plugin

Use an order-export plugin (WP All Export is one example) and follow its own documentation to export WooCommerce orders. Configure the export so that each row is one order line item, with these columns: order ID, product ID, product name, quantity, order date and order total. Filter to completed orders and to the date range you want to analyze. Field names and menu paths differ between plugins, so check the plugin's documentation for the exact placeholders.

Method 2: Direct Database Query

If you have database access, you can export data directly using SQL. The query below reads the classic WordPress storage, where an order is a shop_order row in wp_posts and its line items are rows in wp_woocommerce_order_items, with product ID and quantity in wp_woocommerce_order_itemmeta under the keys _product_id and _qty. WooCommerce 8.2 and later enable High-Performance Order Storage (HPOS) by default for new installations, which keeps orders in dedicated tables (wc_orders and related tables) instead; if your store uses HPOS without posts synchronization, take the order ID, date and total from those tables, or use Method 1.

SELECT
    orders.ID AS order_id,
    pid.meta_value AS product_id,
    order_items.order_item_name AS product_name,
    qty.meta_value AS quantity,
    DATE(orders.post_date) AS order_date,
    order_total.meta_value AS order_total
FROM wp_posts AS orders
INNER JOIN wp_woocommerce_order_items AS order_items
    ON orders.ID = order_items.order_id
    AND order_items.order_item_type = 'line_item'
INNER JOIN wp_woocommerce_order_itemmeta AS pid
    ON order_items.order_item_id = pid.order_item_id
    AND pid.meta_key = '_product_id'
INNER JOIN wp_woocommerce_order_itemmeta AS qty
    ON order_items.order_item_id = qty.order_item_id
    AND qty.meta_key = '_qty'
LEFT JOIN wp_postmeta AS order_total
    ON orders.ID = order_total.post_id
    AND order_total.meta_key = '_order_total'
WHERE orders.post_type = 'shop_order'
    AND orders.post_status = 'wc-completed'
ORDER BY orders.post_date DESC, orders.ID, order_items.order_item_id;

Replace wp_ with your database prefix if it differs. Shipping lines are excluded by the order_item_type = 'line_item' filter. The query was run against a small mock of this table layout to confirm it returns one row per line item.

Data Validation Checklist

Before proceeding, verify your export:

Expected Output

Your CSV file should look like this. The rows here, and all figures in Step 4, come from a synthetic data set of 1,000 orders generated for this tutorial, not from a real store:

order_id,product_id,product_name,quantity,order_date,order_total
1924,421,Mug Set,2,2024-12-28,44.00
1952,234,Organic Coffee Beans,1,2024-12-28,50.00
1952,567,French Press,1,2024-12-28,50.00
1980,310,Yoga Mat,1,2024-12-28,55.00
1980,311,Yoga Blocks,1,2024-12-28,55.00

Run It on Your Own WooCommerce Export

Export your WooCommerce orders as a CSV and upload it at MCP Analytics. The analysis runs association-rule mining (support, confidence and lift for product pairs) plus a basket size and quantity breakdown on your file and shows the result with the method used. You choose the columns; nothing connects to your WooCommerce account.

Try it on your data

Step 4: Interpreting Your Results

Here's how to interpret each of the three views the code below produces:

The code below reads the CSV from Step 2 (saved as export.csv) and computes the three views this step interprets. The data is the synthetic 1,000-order set described above.

Basket Size Distribution

Basket size here is the number of distinct products (order lines) in an order. This view shows what share of orders falls at each size:

import itertools
import pandas as pd

df = pd.read_csv("export.csv")
n_orders = df["order_id"].nunique()

# Basket size = number of distinct products (order lines) in an order
basket = df.groupby("order_id").size()
share = basket.value_counts(normalize=True).sort_index() * 100
print("Basket Size | Percentage of Orders | Cumulative %")
for size, pct in share.items():
    print(f"{size} item{'s' if size > 1 else ' '}".ljust(11) + f" | {pct:>5.1f}%".ljust(23) + f"| {share.loc[:size].sum():.1f}%")
print(f"Average basket size: {basket.mean():.2f} items")
print(f"Median basket size: {basket.median():.0f} item")
print(f"Orders with 2 or 3 items: {basket.isin([2, 3]).mean() * 100:.1f}%")

Example Output:

Basket Size | Percentage of Orders | Cumulative %
1 item      |  60.6%              | 60.6%
2 items     |  28.2%              | 88.8%
3 items     |   9.5%              | 98.3%
4 items     |   1.7%              | 100.0%
Average basket size: 1.52 items
Median basket size: 1 item
Orders with 2 or 3 items: 37.7%

Key Insights:

Product Affinity

This section shows which products are purchased together. The table lists five pairs from the same data (1,000 orders):

products = df.groupby("order_id")["product_name"].apply(set)
support = {p: sum(p in s for s in products) / n_orders for p in df["product_name"].unique()}
pairs = [("Organic Coffee Beans", "French Press"), ("Organic Coffee Beans", "Coffee Grinder"),
         ("Organic Coffee Beans", "Coffee Filters (50pk)"), ("Coffee Filters (50pk)", "Organic Coffee Beans"),
         ("Yoga Mat", "Yoga Blocks")]
print("Product A | Product B | Orders with both | Confidence | Lift | Orders with A")
for a, b in pairs:
    both = sum(a in s and b in s for s in products)
    conf = both / (support[a] * n_orders)
    lift = conf / support[b]
    print(f"{a} | {b} | {both / n_orders * 100:.1f}% ({both}) | {conf * 100:.1f}% | {lift:.1f} | {round(support[a] * n_orders)}")

Example Output:

Product A | Product B | Orders with both | Confidence | Lift | Orders with A
Organic Coffee Beans | French Press | 20.1% (201) | 50.4% | 2.0 | 399
Organic Coffee Beans | Coffee Grinder | 13.8% (138) | 34.6% | 2.0 | 399
Organic Coffee Beans | Coffee Filters (50pk) | 8.9% (89) | 22.3% | 1.5 | 399
Coffee Filters (50pk) | Organic Coffee Beans | 8.9% (89) | 60.1% | 1.5 | 148
Yoga Mat | Yoga Blocks | 4.7% (47) | 40.2% | 8.5 | 117

Understanding the Metrics:

Actionable Insights:

In this data set, 50.4% of orders containing "Organic Coffee Beans" also contain a "French Press" (201 of 399 orders), and French Press appears in 25.0% of all orders, so the lift is 2.0. That makes the pair a candidate for:

The Yoga Mat and Yoga Blocks row shows why counts matter: its lift of 8.5 rests on only 47 orders, so a few orders more or fewer would move it a lot. Check the counts before acting on a high lift.

Quantity Patterns

Understanding how many units of each product customers buy helps with inventory and pricing. These figures count only orders that contain the product:

qty = df.groupby("product_name")["quantity"].agg(
    orders="size", avg="mean", common=lambda s: s.mode()[0], multi=lambda s: (s > 1).mean() * 100)
print("Product Name | Orders | Avg Qty/Order | Most Common Qty | % With Qty > 1")
for name in ["Organic Coffee Beans", "French Press", "Coffee Filters (50pk)", "Coffee Grinder"]:
    r = qty.loc[name]
    print(f"{name} | {r.orders:.0f} | {r.avg:.2f} | {r.common:.0f} | {r.multi:.1f}%")

Example Output:

Product Name | Orders | Avg Qty/Order | Most Common Qty | % With Qty > 1
Organic Coffee Beans | 399 | 1.88 | 2 | 67.2%
French Press | 250 | 1.04 | 1 | 3.6%
Coffee Filters (50pk) | 148 | 1.73 | 2 | 60.8%
Coffee Grinder | 172 | 1.15 | 1 | 14.5%

Strategic Applications:

Temporal Patterns

You can repeat the same calculations on separate date ranges (for example, quarter against quarter) to see how basket behavior changes over time.

Step 5: Applying Insights to Optimize Your Store

Analysis is only valuable when you take action. Here's how to implement your findings:

1. Create Product Bundles

Based on high-lift product pairs with enough orders behind them, create curated bundles (the prices below are illustrative):

// Example: WooCommerce product bundle setup
1. Install "WooCommerce Product Bundles" plugin
2. Create new product: "Coffee Enthusiast Starter Kit"
3. Add components:
   - Organic Coffee Beans (Qty: 2)
   - French Press (Qty: 1)
   - Coffee Grinder (Qty: 1)
4. Set bundle price: $81 (vs $95 individual at the synthetic data set's prices, about 15% off)
5. Configure bundle discount: "Save $14 when purchased together"

2. Optimize Product Recommendations

Update your "Related Products" and "You May Also Like" sections based on actual affinity data rather than categories alone:

// Example: Custom recommendation logic
Product Page: Organic Coffee Beans
Recommended Products (by affinity score):
1. French Press (Lift: 2.0) - "50% of orders with these beans also included this"
2. Coffee Grinder (Lift: 2.0) - "Perfect companion for fresh beans"
3. Coffee Filters (Lift: 1.5) - "Complete your coffee setup"

3. Implement Dynamic Discounting

Encourage basket growth with smart discount rules:

4. Refine Email Marketing

Use affinity data to create targeted email campaigns:

Scenario: Customer purchased Organic Coffee Beans but not French Press

Email Template:
"We noticed you recently purchased our Organic Coffee Beans. Did you know that half of the orders with our Organic Coffee Beans also include our French Press? Here's an exclusive 20% discount to complete your coffee experience..."

5. Inventory Optimization

Keep orders and units separate. Confidence is a share of orders, not of units:

In the synthetic data set (1,000 orders):
- Organic Coffee Beans appear in 399 orders; French Press in 250 orders
- 201 orders contain both, so 49 of the 250 French Press orders have no beans
- Plan French Press stock from its own total demand (250 orders, 1.04 units
  per order), not as a fixed fraction of bean orders

Measuring Success

After implementing changes, track these metrics:

Re-run your analysis monthly to track improvements and identify new opportunities. Consider using A/B testing methodologies to test the impact of specific changes.

Ready to Look at Your Own Store's Patterns?

You've learned the fundamentals of item quantity and basket analysis; the figures above come from a synthetic data set, so the patterns in your own orders will differ. Let the data guide your decisions rather than guessing what your customers want.

Try it on your data

Next Steps and Advanced Techniques

Expand Your Analysis

Once you've mastered basic basket analysis, consider these advanced approaches:

1. Customer Segmentation

Analyze basket patterns by customer segment (new vs. returning, high-value vs. low-value) to create personalized experiences.

2. Temporal Analysis

Examine how basket composition changes by day of week, season, or in response to marketing campaigns.

3. Sequential Pattern Mining

Go beyond single-order analysis to understand the sequence of purchases across multiple orders (what do customers buy on their second order after buying Product X first?)

4. Price Sensitivity Analysis

Combine basket analysis with pricing data to understand how discounts affect product combinations and basket size.

Related Resources

Troubleshooting Common Issues

Problem: No product pairs with a lift above 1

Cause: Dataset too small or highly fragmented product catalog

Solutions:

Problem: "Export file too large to upload"

Cause: The file is larger than the upload limit of the tool you are using

Solutions:

Problem: "Inconsistent or missing product names"

Cause: Product variations or database encoding issues

Solutions:

// Clean data before upload using spreadsheet formulas
1. Remove special characters: =SUBSTITUTE(A2,CHAR(160)," ")
2. Standardize case: =PROPER(A2)
3. Remove leading/trailing spaces: =TRIM(A2)
4. Consolidate variations: Find/Replace "Coffee - Organic" → "Organic Coffee"

Problem: "Lift scores seem incorrect or counterintuitive"

Cause: Misunderstanding of lift calculation or insufficient sample size

Understanding:

Problem: "Analysis results change dramatically between runs"

Cause: Small sample size or highly volatile purchasing patterns

Solutions:

Problem: "Can't connect export plugin to database"

Cause: Database permissions or hosting restrictions

Solutions:

Your turn

Bring your own data and the question you actually need answered.

MCP AnalyticsData science by email Send us your data and your question, and we will reply. ds@mcpanalytics.ai

Explore more: WooCommerce Analytics: all tools, tutorials, and guides →