How to Use Sales Performance in Amazon: Step-by-Step Tutorial
By MCP Analytics Team | Published , updated
Introduction to Sales Performance Analysis
Analyzing your Amazon sales shows whether sales are growing, how FBA (Fulfilled by Amazon) orders compare with merchant-fulfilled (FBM) orders, and what a typical order is worth. This tutorial answers those three questions with pandas on an order export, and shows the definition behind every number.
The figures in every output block come from a synthetic data set generated for this tutorial (about 2,300 orders over nine months), not from a real seller, so your numbers will differ. That larger file is not included here, so the next part gives you a small one you can run yourself.
Try It First on 12 Made-Up Order Lines
This is a synthetic file, not real seller data. Save it as orders.csv. It has 12 lines from 10 orders. Order A003 is cancelled, and orders A001 and A006 have two lines each.
order_id,order_date,order_status,item_price,quantity,fulfillment,sku
A001,2025-01-05,Shipped,20.00,2,FBA,SKU-A
A001,2025-01-05,Shipped,15.00,1,FBA,SKU-B
A002,2025-01-12,Shipped,30.00,1,FBM,SKU-C
A003,2025-01-20,Cancelled,25.00,1,FBA,SKU-A
A004,2025-02-03,Shipped,20.00,3,FBA,SKU-A
A005,2025-02-10,Shipped,18.00,1,FBM,SKU-B
A006,2025-02-18,Shipped,40.00,1,FBA,SKU-D
A006,2025-02-18,Shipped,12.00,2,FBA,SKU-E
A007,2025-03-02,Shipped,22.00,2,FBM,SKU-C
A008,2025-03-09,Shipped,35.00,1,FBA,SKU-D
A009,2025-03-15,Shipped,20.00,1,FBA,SKU-A
A010,2025-03-27,Shipped,28.00,2,FBM,SKU-B
Run the Step 1, Step 2 and Step 3 code blocks below on this file, in that order. Then run one more line to get the average line: print(f"Average line revenue: ${sold['revenue'].mean():.2f}"). The outputs print in this order (blank lines are added here between the blocks):
revenue orders units aov growth_pct
order_date
2025-01 85.0 2 4 42.5 NaN
2025-02 142.0 3 7 47.3 67.1
2025-03 155.0 4 6 38.8 9.2
Average daily revenue: $42.44
orders revenue units order_share_pct revenue_share_pct aov
fulfillment
FBA 5 234.0 11 55.56 61.26 46.8
FBM 4 148.0 6 44.44 38.74 37.0
FBA AOV minus FBM AOV: $9.80 (95% bootstrap interval $-10.50 to $29.10)
Orders: 9 AOV (mean): $42.44 median: $44.00 75th percentile: $56.00
revenue
under $25 22.2
$25-$50 33.3
$50-$100 44.4
over $100 0.0
Average line revenue: $34.73
Three things to notice. The cancelled order is left out, so January has 2 orders, not 3. The average order is $42.44 but the average line is $34.73, because two orders have two lines. That is why AOV divides by orders. With 9 orders the bootstrap interval in Step 2 runs from $-10.50 to $29.10, so it cannot tell whether the $9.80 gap is real. A file this small cannot support that conclusion. The +67.1% growth in February is large only because January is small.
Prerequisites and Data Requirements
What You'll Need Before Starting
- An order export from your Amazon account as a CSV with one row per order line. Report names and menus change, so follow Seller Central's current help for exporting orders
- Several months of history, so that seasonal swings do not look like trends. Compare the same months across years if you have them
- Python with pandas and NumPy, or a spreadsheet if you rebuild the same steps there
Data Fields You Should Have
The code expects these column names, so rename the ones in your report to match:
order_id,order_date,order_statusitem_priceandquantity(price is per unit)fulfillmentwith the values FBA and FBM (your report's column and values will be named differently; map them)sku
The code counts "Shipped" lines as sales and leaves out cancelled ones. If your report uses other status words, change that one line.
What You'll Accomplish
By following this tutorial, you will:
- Total revenue and orders by month and compute month-over-month growth
- Compare FBA and merchant-fulfilled orders, with an interval for the AOV gap
- Calculate average order value correctly, per order and not per line, and read its distribution
- Know which conclusions the data supports and which need more evidence
Step 1: What is My Amazon Revenue Trend?
1Analyzing Revenue Over Time
Your revenue trend shows whether sales are growing, flat or falling. This code keeps shipped lines, adds up revenue, distinct orders and units by month, and computes growth from one month to the next. AOV here is revenue divided by the number of distinct orders: an order with several lines counts once.
import numpy as np
import pandas as pd
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
sold = orders[orders["order_status"] == "Shipped"].copy() # cancelled lines are not sales
sold["revenue"] = sold["item_price"] * sold["quantity"]
monthly = sold.groupby(sold["order_date"].dt.to_period("M")).agg(
revenue=("revenue", "sum"), orders=("order_id", "nunique"), units=("quantity", "sum"))
monthly["aov"] = monthly["revenue"] / monthly["orders"] # revenue per ORDER, not per line
monthly["growth_pct"] = monthly["revenue"].pct_change() * 100
print(monthly.round(1).to_string())
print(f"Average daily revenue: ${sold['revenue'].sum() / sold['order_date'].nunique():,.2f}")
revenue orders units aov growth_pct
order_date
2025-01 9041.5 209 350 43.3 NaN
2025-02 9464.0 200 357 47.3 4.7
2025-03 10456.6 232 412 45.1 10.5
2025-04 11458.8 259 431 44.2 9.6
2025-05 11673.9 260 435 44.9 1.9
2025-06 10398.2 246 394 42.3 -10.9
2025-07 11220.4 243 415 46.2 7.9
2025-08 10226.5 247 401 41.4 -8.9
2025-09 10844.3 260 409 41.7 6.0
Average daily revenue: $352.36
Revenue rises from January to May, dips in June, and is mixed after that. Growth from month to month moves between -10.9% and +10.5%, so a single month says little about the trend. If the last month in your export is partial, its growth is not comparable with full months.
- Growth rate: month-over-month is noisy; compare with the same month a year earlier when you have the history
- Seasonality: recurring patterns such as a holiday peak need at least a full year to see
- Revenue per order and per unit: track them next to revenue to see whether growth comes from more orders, higher prices or larger orders
Step 2: How Does FBA Compare to Merchant Fulfilled?
2Comparing Fulfillment Method Performance
This code groups shipped orders by fulfillment method and compares orders, revenue and AOV. It then resamples orders 2,000 times to get a bootstrap interval for the AOV difference, a rough range for the gap if the orders had come out differently. For more on the comparison, see Amazon FBA vs FBM performance.
by_ch = sold.groupby("fulfillment").agg(orders=("order_id", "nunique"), revenue=("revenue", "sum"), units=("quantity", "sum"))
by_ch["order_share_pct"] = by_ch["orders"] / by_ch["orders"].sum() * 100
by_ch["revenue_share_pct"] = by_ch["revenue"] / by_ch["revenue"].sum() * 100
by_ch["aov"] = by_ch["revenue"] / by_ch["orders"]
print(by_ch.round(2).to_string())
order_totals = sold.groupby(["order_id", "fulfillment"])["revenue"].sum().reset_index()
fba = order_totals.loc[order_totals["fulfillment"] == "FBA", "revenue"].to_numpy()
fbm = order_totals.loc[order_totals["fulfillment"] == "FBM", "revenue"].to_numpy()
rng = np.random.default_rng(5)
diff = [rng.choice(fba, len(fba)).mean() - rng.choice(fbm, len(fbm)).mean() for _ in range(2000)]
lo, hi = np.percentile(diff, [2.5, 97.5])
print(f"FBA AOV minus FBM AOV: ${fba.mean() - fbm.mean():.2f} (95% bootstrap interval ${lo:.2f} to ${hi:.2f})")
orders revenue units order_share_pct revenue_share_pct aov
fulfillment
FBA 1572 72907.79 2639 72.91 76.92 46.38
FBM 584 21876.47 965 27.09 23.08 37.46
FBA AOV minus FBM AOV: $8.92 (95% bootstrap interval $6.35 to $11.48)
FBA has 72.91% of orders and 76.92% of revenue; its AOV is $46.38 against $37.46 for FBM, a gap of $8.92 whose interval ($6.35 to $11.48) stays above zero. In this synthetic data the gap exists; it does not say why. A gap like this can come from which products are fulfilled each way, their prices, and how much of the catalog sits in each group, as well as from the fulfillment method itself.
What Else to Check Before Concluding Anything
- Assortment and price: compare like products, not the whole catalog, before attributing a gap to fulfillment
- Traffic and Buy Box: order exports do not contain sessions or Buy Box data, so conversion rate and Buy Box share need other reports
- Costs: higher revenue is not higher profit; fees, storage and fulfillment costs differ between methods
- Returns: return rate by method needs a returns report
Step 3: What is My Average Order Value?
3Calculating Average Order Value
Average order value (AOV) is total revenue divided by the number of orders. The correct denominator is distinct orders: averaging line revenue instead (the mean of item price times quantity over rows) gives the average line, which is lower whenever orders have several lines. The code adds line revenue up per order first.
totals = sold.groupby("order_id")["revenue"].sum()
print(f"Orders: {len(totals):,} AOV (mean): ${totals.mean():.2f} median: ${totals.median():.2f} 75th percentile: ${totals.quantile(.75):.2f}")
bands = pd.cut(totals, [0, 25, 50, 100, np.inf], labels=["under $25", "$25-$50", "$50-$100", "over $100"])
print((bands.value_counts(normalize=True).sort_index() * 100).round(1).to_string())
Orders: 2,156 AOV (mean): $43.96 median: $34.91 75th percentile: $57.16
revenue
under $25 32.8
$25-$50 34.7
$50-$100 26.2
over $100 6.2
The mean ($43.96) is above the median ($34.91) because a minority of larger orders pulls it up. Report both, and the distribution: a mean alone hides that about a third of orders here are under $25. The bands in the code are examples; choose cutoffs that make sense for your prices.
Ways to Test a Higher AOV
These are ideas to test, not proven fixes. Measure each against revenue and margin, not AOV alone, because a higher AOV can come with fewer orders.
- Bundling: combine complementary products
- Quantity pricing: offer a discount for buying more units
- Upselling and cross-selling: suggest an upgrade or a related product
- Free-shipping threshold: where your channel allows it
Interpreting Your Results
Read the metrics together rather than one at a time. Each scenario below is a hypothesis to investigate, not a conclusion.
Scenario 1: Growing Revenue With Declining AOV
- What it shows: more orders at lower average values
- Possible causes: price cuts, a shift to cheaper products, or a promotion that brought in small orders
- Next step: compare AOV by product mix before changing prices
Scenario 2: FBA Ahead of FBM
- What it shows: FBA orders are larger or more numerous
- Hypothesis: Prime eligibility helps, but assortment, inventory, prices and exposure can also explain the gap
- Next step: compare like products, with availability, price and traffic, before moving inventory
Scenario 3: Flat Revenue With Increasing AOV
- What it shows: fewer orders at higher values
- Possible causes: a premium product focus or lower traffic
- Next step: look at traffic sources, which an order export does not show
Setting Targets
Start from your own baseline: the monthly revenue, AOV and order count the code printed. Choose a target for one change at a time, test it, and compare with the baseline. Targets copied from another seller's numbers do not describe your catalog.
Run It on Your Own Amazon Export
Export your Amazon orders as a CSV and upload it at MCP Analytics, then ask the question in plain language; the report names the method. Nothing connects to your Amazon account.
Common Issues and Solutions
Issue 1: Inconsistent Date Formats in Export Data
Problem: Dates appear in different formats (month first or day first), so some parse wrongly.
Solution: Tell pandas the format explicitly, and check the earliest and latest dates afterwards. Dates like 03/04/2025 are ambiguous; the format that fits your marketplace's report is the one to use.
orders["order_date"] = pd.to_datetime(orders["order_date"], format="%m/%d/%Y")
print(orders["order_date"].min(), orders["order_date"].max())
Issue 2: Missing Fulfillment Method
Problem: Some orders have no fulfillment label, which skews the FBA versus FBM comparison.
Solution: Label them "Unknown", leave them out of the comparison, and report how many orders were unclassified.
Issue 3: Revenue Does Not Match Seller Central
Problem: Your total differs from what Amazon's own reports show.
Common causes:
- Refunds and returns counted differently
- Promotional discounts, shipping and tax included in one and not the other
- Currency conversion on international sales
- Time zone differences in order timestamps
- Cancelled and pending lines included in one and not the other
Solution: Write down which of these your calculation includes (this tutorial counts shipped lines, item price times quantity, no discounts, shipping or tax) and compare with the matching Amazon report.
Issue 4: A Few Huge Orders Distort the AOV
Problem: A handful of very large or very small orders move the mean.
Solution: Report the median next to the mean, as Step 3 does. Trimming the top and bottom 1% is another option, but say that you did it.
Issue 5: Seasonality Hides the Trend
Problem: A holiday peak makes month-over-month growth hard to read.
Solution: Compare each month with the same month a year earlier, which needs at least thirteen months of history.
Next Steps with Amazon Analytics
Advanced Analysis Techniques
- Product-level performance: drill into individual SKUs to find the products driving each trend
- Customer segmentation: first-time against repeat buyers
- Marketplace comparison: if you sell in several, compare them in one currency
- Promotion impact: compare promoted days with matched unpromoted days, and treat the result as association, not effect
Related Resources
A Monthly Routine
Re-export once a month and re-run the same code, so that each month is measured the same way. Record the baseline numbers each time and compare.
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 →
Not sure which plan? Compare plans →