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.

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:

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:

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:

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:

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

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:

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

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%+):

If your discounts barely increase AOV (5% or less):

If high-percentage coupons have low redemption rates:

If certain coupons drive negative net margin:

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.

Try it on your data

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:

Issue: Redemption Rates Seem Unrealistically High or Low

Problem: Your calculated redemption rates don't match expectations (e.g., 60% or 2%).

Solution:

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:

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:

Issue: Statistical Significance Concerns

Problem: You're unsure if differences between coupon performance are statistically significant or just random variation.

Solution:

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:

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:

4. Test Alternative Promotional Strategies

Discounts aren't the only way to drive sales. Test these alternatives:

5. Monitor and Iterate Monthly

Discount effectiveness changes over time. Commit to monthly reviews:

6. Expand Your Analytics Capabilities

Consider expanding your analysis to include:

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 →