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 Product Performance in Amazon: Step-by-Step Tutorial

Updated October 2026

Discover which Amazon products sell best and optimize your inventory strategy with data-driven insights

Introduction to Amazon Product Performance Analysis

As an Amazon seller, one of the most useful questions is: "Which products should I focus on?" Product performance analysis answers it by putting units, revenue, margin and returns side by side for each product, so you can see which ones earn their place and which ones do not.

This tutorial computes those numbers with pandas from three files you can export: your order lines, a cost sheet, and a returns report. Sales alone cannot give margin or return rate, so the tutorial shows exactly where costs and returns are joined in. The figures in every output block come from a synthetic data set generated for this tutorial (16 invented products, about 3,900 order lines), not from a real seller, so your numbers will differ.

Fulfillment method also affects product economics; see Amazon FBA vs FBM performance for that comparison.

What You'll Accomplish

By following this step-by-step tutorial, you will:

Prerequisites and Data Requirements

What You Need

Which Amazon reports provide each file, and how far back they go, depends on your account and marketplace and changes over time. Check Seller Central's current help pages for the report names and limits; this tutorial does not rely on any specific one.

Step 1: Understand Product Performance Metrics

Metrics This Tutorial Computes

1. Units Sold

Total units on shipped order lines for each product. Cancelled and pending lines are left out.

2. Revenue

Item price times quantity on shipped lines, before Amazon fees, returns and costs.

3. Profit Margin

(Revenue minus units times unit cost minus fees) divided by revenue. It needs your cost sheet and a fee rate. It leaves out advertising, storage and shipping unless you add them to the calculation.

4. Return Rate

Returned units divided by units sold. It needs the returns report. Recent orders look better than they are because some returns have not arrived yet.

Metrics That Need Other Data

Pick the metrics that match your goal: cash flow points to turnover, brand building to margin and returns.

Step 2: Check Your Data Sources

  1. Orders: confirm you can export order lines with SKU, product name, quantity, item price, order status and order date
  2. Costs: confirm every SKU you sell has a unit cost in your cost sheet
  3. Returns: confirm you can export returns with the order, SKU and quantity
  4. Product keys: make sure the SKU is spelled the same in all three files, since the join depends on it

If any SKU is missing a cost, the code in Step 4 stops with an error rather than reporting a margin that is wrong.

Step 3: Export Your Amazon Files

Export your order report for the period, with every order status included, and your returns report, both as CSV or tab-separated text. Report names and menus change, so follow Seller Central's current help for the exact steps. Save them as orders.csv and returns.csv, and keep your cost sheet as costs.csv.

The code expects these columns, so rename the ones in your report to match:

Check the order statuses in your file. The code treats "Shipped" as a sale; if your report uses different words, change that one line.

Step 4: Compute Product Performance with pandas

Units and Revenue per Product

This code keeps shipped lines, totals units and revenue per SKU, and shows how concentrated revenue is.

import pandas as pd

orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
print(orders["order_status"].value_counts().to_string())

# Only shipped orders count as sales; cancelled and pending lines are left out
sold = orders[orders["order_status"] == "Shipped"].copy()
sold["revenue"] = sold["item_price"] * sold["quantity"]

by_sku = (sold.groupby(["sku", "product_name"])
              .agg(units=("quantity", "sum"), revenue=("revenue", "sum"))
              .reset_index().sort_values("revenue", ascending=False).reset_index(drop=True))
by_sku["share_pct"] = by_sku["revenue"] / by_sku["revenue"].sum() * 100
by_sku["cum_share_pct"] = by_sku["share_pct"].cumsum()
print(by_sku.head(6).round(1).to_string())
top = max(1, round(len(by_sku) * 0.2))
print(f"Top {top} of {len(by_sku)} products ({top / len(by_sku):.0%}) earn {by_sku['cum_share_pct'].iloc[top - 1]:.1f}% of shipped revenue")

Expected Output

order_status
Shipped      3508
Cancelled     236
Pending       158
      sku        product_name  units  revenue  share_pct  cum_share_pct
0  SKU-03  Blue Light Glasses   1130  62037.0       30.9           30.9
1  SKU-15      Screen Cleaner   1103  44660.5       22.2           53.2
2  SKU-08          Travel Mug    592  41209.1       20.5           73.7
3  SKU-11        Notebook Set    209  10048.7        5.0           78.7
4  SKU-13           Mouse Pad    207   9488.9        4.7           83.4
5  SKU-02        Laptop Stand    134   7922.1        3.9           87.4
Top 3 of 16 products (19%) earn 73.7% of shipped revenue

Add Margin and Return Rate

Margin and return rate need the cost sheet and the returns file. This code joins both on SKU. Groups are defined against the median of your own products, so about half the products fall on each side by construction; they rank products against each other and say nothing about whether a margin is good in absolute terms.

costs = pd.read_csv("costs.csv")        # sku, unit_cost, fee_rate: your own cost sheet and Amazon fee rate per SKU
returns = pd.read_csv("returns.csv")    # order_id, sku, returned_qty: from your returns report

ret = returns.groupby("sku")["returned_qty"].sum().rename("returned_units")
perf = (by_sku.merge(costs, on="sku", how="left")
              .merge(ret, left_on="sku", right_index=True, how="left"))
perf["returned_units"] = perf["returned_units"].fillna(0)
assert perf["unit_cost"].notna().all(), "every SKU needs a cost"

perf["profit"] = perf["revenue"] - perf["units"] * perf["unit_cost"] - perf["revenue"] * perf["fee_rate"]
perf["margin_pct"] = perf["profit"] / perf["revenue"] * 100
perf["return_rate_pct"] = perf["returned_units"] / perf["units"] * 100

med_rev, med_margin = perf["revenue"].median(), perf["margin_pct"].median()
perf["group"] = (perf["revenue"] >= med_rev).map({True: "high revenue", False: "low revenue"}) + " / " + \
                (perf["margin_pct"] >= med_margin).map({True: "high margin", False: "low margin"})
cols = ["product_name", "units", "revenue", "margin_pct", "return_rate_pct", "group"]
print(perf[cols].head(8).round(1).to_string())
print(perf["group"].value_counts().to_string())
print(f"Total shipped revenue ${perf['revenue'].sum():,.2f}, profit ${perf['profit'].sum():,.2f} "
      f"({perf['profit'].sum() / perf['revenue'].sum() * 100:.1f}%)")

Expected Output

         product_name  units  revenue  margin_pct  return_rate_pct                       group
0  Blue Light Glasses   1130  62037.0        33.8              5.6  high revenue / high margin
1      Screen Cleaner   1103  44660.5        25.7              5.7   high revenue / low margin
2          Travel Mug    592  41209.1        36.4              8.4  high revenue / high margin
3        Notebook Set    209  10048.7        35.3             12.4  high revenue / high margin
4           Mouse Pad    207   9488.9        31.2              7.2   high revenue / low margin
5        Laptop Stand    134   7922.1        11.0              0.0   high revenue / low margin
6            Pen Pack    169   5970.8        30.8              2.4   high revenue / low margin
7           Desk Lamp    302   4795.8        28.1             21.5   high revenue / low margin
group
high revenue / low margin     5
low revenue / high margin     5
high revenue / high margin    3
low revenue / low margin      3
Total shipped revenue $200,723.87, profit $63,345.51 (31.6%)

Step 5: Interpret Your Results

Questions to Ask Your Data

When you compare two products or two periods, remember that differences can be chance; testing for statistical significance is the way to check.

Step 6: Take Action Based on Insights

These are tests to run, not guaranteed improvements. Change one thing at a time and compare against your own numbers.

Inventory

A common reorder estimate is average daily sales times lead time times a safety factor. The factor is a judgment about how much demand varies and how costly a stockout is, not a fixed rule:

daily_units, lead_time_days, safety_factor = 25, 45, 1.5
units_needed = daily_units * lead_time_days * safety_factor
print(f"{daily_units} units/day x {lead_time_days} days x {safety_factor} = {units_needed:,.1f}, order {int(-(-units_needed // 1)):,} units (rounded up)")

Expected Output

25 units/day x 45 days x 1.5 = 1,687.5, order 1,688 units (rounded up)

For slow sellers, work out what the stock costs you in storage and tied-up cash before deciding to clear it.

Pricing and Advertising

Product Decisions

Before dropping a product, check whether it sells alongside others and whether its low margin is a cost problem you can fix.

Run It on Your Own Amazon Export

Export your Amazon orders as a CSV and upload it at MCP Analytics. The analysis runs a per-product breakdown of units and revenue on your file and shows the result with the method used. You choose the columns; nothing connects to your Amazon account.

Try it on your data

Next Steps with Amazon Analytics

Troubleshooting Common Issues

Issue: The Code Stops With "every SKU needs a cost"

A SKU in your orders is missing from the cost sheet, or is spelled differently. List the missing ones with set(by_sku["sku"]) - set(costs["sku"]) and add them.

Issue: Garbled Characters

Save the file as UTF-8, or pass encoding="utf-8" or the file's actual encoding to pd.read_csv.

Issue: Top Products by Revenue Are Not Profitable

Revenue is not profit. Sort by profit instead of revenue, and add advertising and storage costs to the calculation if you want them included.

Issue: Return Rates Look Too Low

Returns arrive after the order. Recent orders will show lower return rates than they will end up with, so compare periods that are old enough for most returns to have been recorded.

Issue: Few Rows After Filtering

Check the order status values in your file. If your report does not call a completed sale "Shipped", the filter keeps nothing.

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: Amazon Seller Analytics: all tools, tutorials, and guides →