Etsy Discount Effectiveness: Are Sales Working?
Updated October 2026
Analyze Which Coupons Drive Revenue vs Eating Margins
Introduction to Discount Effectiveness
As an Etsy seller, you've likely asked yourself: "Are my discounts driving sales or just eating into my margins?" This is one of the most critical questions for sustainable e-commerce growth. While promotional codes can attract customers and boost conversion rates, poorly designed discount strategies can severely damage profitability.
Discount effectiveness analysis helps you answer essential questions:
- Which coupon codes generate the most revenue?
- How much extra volume does a given discount need to bring in to pay for itself (a break-even check you run with your own margin)?
- Do discounted orders have higher or lower average order values?
- Which promotions resonate most with your customers?
This tutorial will guide you through a systematic approach to analyzing your Etsy discount performance, enabling you to make data-driven decisions about your promotional strategy. By the end, you'll have a clear picture of how each coupon performed, and a short list of coupons to test changing. The comparisons describe what happened in your orders; they do not by themselves show what the coupons caused. The figures in the examples come from a synthetic order file generated for this tutorial, not from a real shop, so your numbers will differ.
Prerequisites and Data Requirements
What You'll Need
Before starting this analysis, ensure you have:
- Etsy Shop Manager Access: You'll need admin access to your Etsy shop to export order data
- A few months of sales data: The example covers about four months. What matters is how many orders each coupon has and how much order values vary, because those set how precise any average is
- Python with pandas: The steps below are Python code; a spreadsheet pivot table can produce the same totals
- Active coupon codes: You should have run at least 2-3 different promotional campaigns
- CSV export capability: Ability to download your order history from Etsy
Required Data Fields
Your Etsy order export should include these columns. Header names differ between exports, so check the header row of your own file; the code in Step 1 renames the tutorial's headers to the names used afterwards, and you change the left-hand names to match yours:
- Order ID
- Order date
- Order total: what the buyer paid for the items after the coupon, without shipping or tax
- Coupon code used (if any)
- Discount amount
- Number of items in the order
Exporting Your Etsy Data
1. Log into your Etsy Shop Manager
2. Navigate to Settings → Options → Download Data
3. Select "Orders" as the data type
4. Choose your date range (minimum 90 days recommended)
5. Click "Download CSV"
6. Save the file to your local machine
Pro Tip: Export data covering complete months to avoid skewed metrics from partial time periods. For example, if today is March 15th, export from January 1st through February 28th rather than March 15th.
Step 1: Which Coupon Codes Drive the Most Revenue?
The first step in discount effectiveness analysis is identifying which coupon codes generate actual revenue. Not all promotional codes are created equal. Some might have high usage but low revenue impact, while others drive substantial sales despite fewer redemptions.
Setting Up Your Analysis
You'll need to aggregate your order data by coupon code and calculate total revenue for each. Here's how to approach this. Two definitions are used throughout: order_total is what the buyer paid after the coupon, and list_total is that amount plus the discount, the value before the coupon. The discount is counted once: paid revenue is already net of it, so it is not subtracted again.
import pandas as pd
pd.options.display.float_format = '{:,.2f}'.format
pd.set_option('display.width', 200)
pd.set_option('display.max_columns', None)
# Load your Etsy order data. The left-hand names are the headers in this tutorial's file;
# change them to match the headers in yours.
orders = pd.read_csv('etsy_orders.csv').rename(columns={
'Order ID': 'order_id', 'Sale Date': 'order_date', 'Order Total': 'order_total',
'Coupon Code': 'coupon_code', 'Discount Amount': 'discount_amount',
'Number of Items': 'item_quantity',
})
# order_total = what the buyer paid for the items AFTER the coupon (no shipping, no tax).
# If your file's total includes shipping or tax, subtract them first.
orders['discount_amount'] = orders['discount_amount'].fillna(0)
orders['list_total'] = orders['order_total'] + orders['discount_amount'] # before the coupon
orders['discount_rate'] = orders['discount_amount'] / orders['list_total'] * 100
# Filter for orders with coupon codes (after the columns above exist,
# so the filtered frame carries them)
discounted_orders = orders[orders['coupon_code'].notna()]
# Group by coupon code and calculate metrics
coupon_performance = discounted_orders.groupby('coupon_code').agg(
paid_revenue=('order_total', 'sum'),
avg_order_value=('order_total', 'mean'),
redemptions=('order_total', 'count'),
discount_given=('discount_amount', 'sum'),
)
coupon_performance['pre_discount_value'] = coupon_performance['paid_revenue'] + coupon_performance['discount_given']
# Sort by revenue actually paid
coupon_performance_sorted = coupon_performance.sort_values('paid_revenue', ascending=False)
print(coupon_performance_sorted)
Expected Output
paid_revenue avg_order_value redemptions discount_given pre_discount_value
coupon_code
SUMMER20 10,917.56 39.41 277 2,625.51 13,543.07
WELCOME10 8,948.07 41.81 214 971.19 9,919.26
FLASH15 5,195.94 39.36 132 874.01 6,069.95
LOYAL25 3,171.13 52.85 60 1,032.74 4,203.87
Interpreting the Results
Look for these key patterns:
- High paid revenue: SUMMER20 brought in $10,917.56 of paid revenue, the most of any code
- Redemption volume: SUMMER20 also had 277 redemptions, the most of any code
- Discount cost: SUMMER20 gave away $2,625.51 in discounts. Its orders held $13,543.07 before the coupon; $10,917.56 is what was paid
- Order size: LOYAL25 has the highest average order value ($52.85) despite only 60 redemptions
In this example SUMMER20 drives volume while LOYAL25 drives larger orders. This is a description of what happened under each code; it does not show which orders would have happened without a code. For more on judging whether a comparison is more than random variation, see our guide on A/B testing statistical significance.
Step 2: What's the Average Discount Rate?
Understanding your average discount rate is crucial for margin management. A discount that's too deep erodes profitability, while one that's too shallow may not motivate purchases. This step shows where each code sits, and the break-even check at the end of the step shows what a given depth has to earn back.
Calculating Discount Rates
The discount rate is the percentage reduction from the pre-coupon value of the order. It was calculated per order in Step 1, so here you summarize it for each coupon code:
# discount_rate was added to orders in Step 1, before discounted_orders was filtered,
# so discounted_orders already carries it (a column added after the filter would be missing).
avg_discount_by_coupon = discounted_orders.groupby('coupon_code').agg(
avg_rate=('discount_rate', 'mean'),
median_rate=('discount_rate', 'median'),
std_dev=('discount_rate', 'std'),
min_discount=('discount_amount', 'min'),
max_discount=('discount_amount', 'max'),
avg_discount_amount=('discount_amount', 'mean'),
)
print(avg_discount_by_coupon)
Expected Output
avg_rate median_rate std_dev min_discount max_discount avg_discount_amount
coupon_code
FLASH15 14.39 15.00 1.69 1.45 20.56 6.62
LOYAL25 24.61 25.00 1.64 3.20 39.13 17.21
SUMMER20 19.38 20.00 2.07 1.34 24.63 9.48
WELCOME10 9.82 10.00 0.77 0.63 11.77 4.54
The rate columns are percentages and the discount columns are dollars.
What This Tells You
- Rate versus the advertised percentage: The median rate equals each code's advertised percentage (10, 15, 20 and 25). The averages sit a little lower, and the standard deviation is 0.77 to 2.07 points, because in this example some orders held an item the code did not cover. If your own averages sit well below the advertised percentage, look for excluded items or minimum-spend rules
- Discount depth: Your promotions range from 10% to 25% off
- Dollar impact: LOYAL25 gives the highest average discount ($17.21), on the largest orders
- Strategic positioning: If WELCOME10 goes to new customers and LOYAL25 to repeat customers, as assumed here, they serve different jobs and should be judged separately
Whether a depth is too deep depends on your margin, which this file does not contain. A break-even check shows what a discount has to earn back. If a discount takes d% off the list price and your margin before the discount is m% of the list price, the margin per unit falls from m to m minus d, so units sold must rise by d / (m minus d) to leave total margin unchanged. In the code below the 40% margin is a placeholder for the example: use your own (list price minus item cost, Etsy fees and shipping you pay, divided by list price).
def breakeven_volume_increase(margin_pct, discount_pct):
"""Extra units needed, as a % of today's units, to keep total contribution unchanged.
margin_pct: (list price - item cost - fees - shipping you pay) / list price, in percent."""
if discount_pct >= margin_pct:
return float('inf') # the discount takes the whole margin: no volume can pay for it
return discount_pct / (margin_pct - discount_pct) * 100
margin_pct = 40 # a placeholder: replace with your own margin
for discount_pct in (10, 15, 20, 25):
extra = breakeven_volume_increase(margin_pct, discount_pct)
print(f"{discount_pct}% off at a {margin_pct}% margin: units must rise {extra:.1f}% to break even")
10% off at a 40% margin: units must rise 33.3% to break even
15% off at a 40% margin: units must rise 60.0% to break even
20% off at a 40% margin: units must rise 100.0% to break even
25% off at a 40% margin: units must rise 166.7% to break even
At that margin a 20% coupon has to double unit sales to break even, and a 25% coupon has to raise them by about 167%. Compare those requirements with the extra volume your codes actually brought in, using a holdout or a before-and-after comparison, not the raw order counts. Published discount ranges that "typically maintain healthy margins" do not substitute for this, because margins differ by product.
Step 3: Do Discounts Increase or Decrease Order Value?
This is perhaps the most revealing analysis: do customers who use discount codes actually spend more per order, or do they simply pay less for items they would have purchased anyway? The answer fundamentally shapes your promotional strategy. The data here can show how the two groups differ; it cannot by itself show why.
Comparing Discounted vs. Non-Discounted Orders
# Separate discounted and non-discounted orders
orders['has_discount'] = orders['coupon_code'].notna()
# Calculate average order values (order_total is what the buyer paid)
aov_comparison = orders.groupby('has_discount').agg(
avg_order_value=('order_total', 'mean'),
median_order_value=('order_total', 'median'),
order_count=('order_total', 'count'),
avg_items_per_order=('item_quantity', 'mean'),
)
print(aov_comparison)
# Observed difference in what buyers paid
non_discounted_aov = aov_comparison.loc[False, 'avg_order_value']
discounted_aov = aov_comparison.loc[True, 'avg_order_value']
aov_lift = ((discounted_aov - non_discounted_aov) / non_discounted_aov) * 100
print(f"\nPaid AOV, discounted vs non-discounted orders: {aov_lift:+.2f}%")
Expected Output
avg_order_value median_order_value order_count avg_items_per_order
has_discount
False 40.78 35.44 1245 1.82
True 41.34 39.31 683 2.20
Paid AOV, discounted vs non-discounted orders: +1.36%
Analyzing the Impact
In this example, the data shows several things:
- Paid order value is nearly flat: Discounted orders average $41.34 against $40.78 for non-discounted orders, a difference of 1.36%
- More items per order: Orders with a code hold 2.20 items on average against 1.82
- The median is higher: The median paid order is $39.31 against $35.44, so the typical discounted order is larger even though the average is nearly level
- The coupon returns the difference: Before the coupon, discounted orders held $49.39 on average, about 21% above the $40.78 non-discounted average; the coupon gives that back
Read together: buyers with a code bought more items per order, and after the coupon they paid about the same as buyers without one. Whether they would have bought without the code cannot be told from this data. To see what the codes added, compare against orders that did not get the offer, for example by holding a random group back.
The next block lays out the numbers behind that reading, counting the discount once:
# What did discounted orders hold before the coupon, and what was paid after it?
discounted_list_aov = orders.loc[orders['has_discount'], 'list_total'].mean()
print(f"Non-discounted orders, paid: ${non_discounted_aov:.2f}")
print(f"Discounted orders, before the coupon: ${discounted_list_aov:.2f}")
print(f"Discounted orders, paid after coupon: ${discounted_aov:.2f}")
ratio = discounted_aov / non_discounted_aov * 100
print(f"Paid per discounted order as % of paid per non-discounted order: {ratio:.2f}%")
Non-discounted orders, paid: $40.78
Discounted orders, before the coupon: $49.39
Discounted orders, paid after coupon: $41.34
Paid per discounted order as % of paid per non-discounted order: 101.36%
A paid-per-order ratio above 100% means orders with a code brought in slightly more per order after the discount; here it is 101.36%, essentially level. It is an observed difference, not proof that the discounts produced extra revenue: customers who use codes may differ from those who do not (for example, a code sent only to repeat buyers), and order thresholds and campaign timing can also move order values. A randomized holdout, or another design that accounts for who gets a code, is what estimates the extra revenue a discount causes.
Step 4: Which Promotions Have the Highest Redemption?
Redemption rate measures how many customers who receive or see your promotion actually use it. This metric shows which offers were taken up most and, if you record where each code was sent, which distribution channels were used most.
Calculating Redemption Rates
To calculate redemption rate, you need both the number of times a coupon was distributed and how many times it was used. The distribution counts come from wherever you sent the codes, not from the order file; the numbers below are invented for the example:
# If you track coupon distribution (e.g., email sends, social posts)
# Illustrative counts invented for this tutorial; use your own
coupon_distribution = {
'SUMMER20': 2500,
'WELCOME10': 1800,
'FLASH15': 950,
'LOYAL25': 300
}
# Calculate redemption rates
redemption_analysis = coupon_performance.copy()
redemption_analysis['distributed'] = redemption_analysis.index.map(coupon_distribution)
redemption_analysis['redemption_rate'] = (redemption_analysis['redemptions'] / redemption_analysis['distributed']) * 100
# Add paid revenue per distributed coupon
redemption_analysis['revenue_per_distribution'] = redemption_analysis['paid_revenue'] / redemption_analysis['distributed']
print(redemption_analysis[['redemptions', 'distributed', 'redemption_rate', 'revenue_per_distribution']])
Expected Output
redemptions distributed redemption_rate revenue_per_distribution
coupon_code
FLASH15 132 950 13.89 5.47
LOYAL25 60 300 20.00 10.57
SUMMER20 277 2500 11.08 4.37
WELCOME10 214 1800 11.89 4.97
Key Insights
- Highest redemption rate: LOYAL25 at 20.00%. It goes to your best customers, so a high rate is expected and does not show the offer is better
- Flash sale: FLASH15 has a 13.89% redemption rate and $5.47 of paid revenue per distributed coupon
- Similar rates: SUMMER20 and WELCOME10 are at 11.08% and 11.89%, close to each other
- Revenue per distributed coupon: LOYAL25 generates $10.57, about 2.4 times SUMMER20's $4.37, which reflects its larger orders ($52.85) and its higher redemption rate (20.00%) among a smaller, hand-picked audience
Segmenting by Distribution Channel
If you record where each code was sent and add that as a column, you can summarize each coupon and channel combination:
# Example with distribution channel data: an acquisition_channel column that you
# add yourself (the example file has one)
channel_performance = discounted_orders.groupby(['coupon_code', 'acquisition_channel']).agg(
orders=('order_id', 'count'),
paid_revenue=('order_total', 'sum'),
)
# This shows which channel and coupon combinations bring in the most paid revenue
print(channel_performance)
orders paid_revenue
coupon_code acquisition_channel
FLASH15 email 67 2,627.50
social 65 2,568.44
LOYAL25 email 60 3,171.13
SUMMER20 email 139 5,647.74
social 138 5,269.82
WELCOME10 email 126 5,055.09
site popup 88 3,892.98
Seeing which combinations of offers and channels bring in the most paid revenue helps you plan your promotional calendar. Here the channels are close (for SUMMER20, 139 email orders and 138 social orders); a small gap like that can be noise, so test before moving budget.
Interpreting Your Results
Now that you've completed the four-step analysis, it's time to synthesize the insights into actionable strategies. Here's how to interpret your findings holistically:
Creating Your Discount Effectiveness Scorecard
Combine the metrics you computed into one view. Every column below is calculated from the earlier steps; the last two columns compare each code's average paid order with the no-code average, and give its redemption rate:
scorecard = pd.DataFrame({
'paid_revenue': coupon_performance['paid_revenue'],
'redemptions': coupon_performance['redemptions'],
'avg_discount_pct': avg_discount_by_coupon['avg_rate'],
'avg_paid_order': coupon_performance['avg_order_value'],
'vs_no_code_aov_pct': (coupon_performance['avg_order_value'] / non_discounted_aov - 1) * 100,
'redemption_rate_pct': redemption_analysis['redemption_rate'],
}).sort_values('paid_revenue', ascending=False)
print(scorecard)
paid_revenue redemptions avg_discount_pct avg_paid_order vs_no_code_aov_pct redemption_rate_pct
coupon_code
SUMMER20 10,917.56 277 19.38 39.41 -3.35 11.08
WELCOME10 8,948.07 214 9.82 41.81 2.53 11.89
FLASH15 5,195.94 132 14.39 39.36 -3.48 13.89
LOYAL25 3,171.13 60 24.61 52.85 29.60 20.00
In this example only LOYAL25 has a clearly larger average paid order than orders without a code (29.60% higher). If LOYAL25 goes to repeat buyers who tend to buy higher-priced items, as assumed in this example, that gap says nothing about what the coupon did. The scorecard has no margin column: add one with the break-even check from Step 2 and your own costs.
Strategic Recommendations Based on Results
If your discounts increase AOV significantly (15%+):
- Customers may be adding items to qualify for discounts; check this against order thresholds and a comparison group before relying on it
- Consider implementing tiered discounts (e.g., "15% off $50+, 20% off $100+")
- Keep the promotional calendar while you test the next change
If your discounts barely increase AOV (5% or less):
- Customers may be using coupons on items they'd buy anyway
- Reduce discount frequency or depth
- Reserve promotions for new customer acquisition only
- Test free shipping thresholds instead of percentage discounts
If high-percentage coupons have low redemption rates:
- Your distribution channel may be wrong (reaching the wrong audience)
- The offer might be too complex or have unclear terms
- Consider simplifying to round numbers (20% vs. 17%)
If certain coupons drive negative net margin:
- Calculate customer lifetime value (CLV). The discount may be worth it for acquisition
- If targeting existing customers, reduce or eliminate this promotion
- Test lower discount percentages with similar messaging
Run It on Your Own Etsy Export
Export your orders from Etsy as a CSV and upload it at MCP Analytics. The analysis runs a comparison of discounted and non-discounted orders by coupon code on your file and shows the result with the method used. You choose the columns; nothing connects to your Etsy account.
Common Issues and Solutions
Issue: Incomplete Discount Data in Exports
Problem: Your Etsy CSV export doesn't include coupon codes or discount amounts for some orders.
Solution: This typically occurs when:
- Orders were placed using Etsy's sale pricing instead of coupon codes. These should be tracked separately
- The export date range doesn't include the complete order history, re-export with corrected dates
- Some orders had manual price adjustments. You may need to reconcile these manually or exclude them
Issue: Redemption Rates Seem Unrealistically High or Low
Problem: Your calculated redemption rates don't match expectations (e.g., 60% or 2%).
Solution:
- Verify your distribution count is accurate, if you sent 500 emails but 200 bounced, your actual distribution is 300
- Check for coupon code sharing: customers may share codes on deal sites, inflating redemptions beyond your distribution
- Ensure you're not counting single-use codes that expired without being redeemed
- For public codes (posted on social media), redemption rate = redemptions / impressions is more meaningful
Issue: Negative AOV Lift from Discounts
Problem: Your analysis shows discounted orders have lower AOV than non-discounted orders.
Solution: This isn't necessarily bad. It may indicate:
- Discounts are successfully acquiring new customers who start with smaller orders
- You're helping price-sensitive customers make their first purchase
- Track these customers over time. They may increase AOV on subsequent purchases
- If consistent across repeat customers, you're training customers to wait for discounts, reduce frequency
Issue: Unable to Attribute Revenue to Specific Marketing Campaigns
Problem: You know which coupons drove sales but not which marketing campaigns drove the coupon usage.
Solution:
- Use unique coupon codes for each campaign (EMAIL10 vs. SOCIAL10 vs. INFLUENCER10)
- Implement UTM parameters in your marketing links to track source
- Use Etsy's attribution window to see which marketing touchpoints preceded purchases
- Create a tracking spreadsheet mapping coupon codes to campaigns and distribution dates
Issue: Statistical Significance Concerns
Problem: You're unsure if differences between coupon performance are statistically significant or just random variation.
Solution:
- Treat about 30 redemptions per coupon as a rough floor for looking at an average at all; how precise it is depends on how much order values vary, so put a confidence interval around it
- Calculate confidence intervals for your key metrics (AOV, redemption rate)
- Run promotions for at least 2 weeks to capture weekly purchasing patterns
- Consider using A/B testing frameworks for new promotional strategies
For a comprehensive understanding of statistical significance in your testing, refer to our article on A/B testing and statistical significance.
Next Steps with Etsy Discount Strategy
Now that you understand how to analyze discount effectiveness, here are recommended next steps to optimize your promotional strategy:
1. Establish a Promotional Calendar
Based on your findings, create a structured promotional calendar:
- Schedule your highest-performing coupons during peak sales periods
- Rotate promotional codes monthly to test different discount depths
- Reserve deep discounts (20%+) for customer acquisition campaigns only
- Plan flash sales around inventory clearance needs
2. Implement Tiered Discount Strategies
If your analysis showed that discounts increase AOV, leverage this with tiers:
10% off orders $50+
15% off orders $75+
20% off orders $100+
Free shipping on orders $125+
3. Segment Your Customer Base
Create targeted promotional strategies for different segments:
- New customers: 10-15% welcome discount to reduce friction on first purchase
- Repeat customers: Loyalty rewards or early access to sales rather than deep discounts
- Lapsed customers: Win-back campaigns with 20% off to re-engage
- High-value customers: Exclusive perks like free shipping or first access to new products
4. Test Alternative Promotional Strategies
Discounts aren't the only way to drive sales. Test these alternatives:
- Free shipping thresholds (often more profitable than percentage discounts)
- Buy-one-get-one (BOGO) offers to move inventory
- Gift with purchase promotions
- Bundling strategies (3 items for $50)
- Limited-time scarcity messaging without discounts
5. Monitor and Iterate Monthly
Discount effectiveness changes over time. Commit to monthly reviews:
- Run this analysis on the first of each month for the previous month's data
- Track trends in redemption rates and AOV impact
- Adjust your promotional calendar based on performance data
- Document what works and what doesn't for future reference
6. Expand Your Analytics Capabilities
Consider expanding your analysis to include:
- Customer lifetime value (CLV) by acquisition source
- Profit margin analysis by product category and discount depth
- Predictive modeling to forecast promotional ROI
- Cohort retention analysis for discount-acquired customers
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: Etsy Shop Analytics: all tools, tutorials, and guides →
Not sure which plan? Compare plans →