By MCP Analytics Team | Published , updated
Knowing how much sales tax and VAT appear in your Etsy export, and where your orders go, helps you keep your records straight. This tutorial lists orders to review. It does not decide tax due, registration or filing. Ask a tax adviser. This is not tax advice.
This comprehensive tutorial will walk you through using Tax & VAT Analysis to answer critical questions: How much sales tax and VAT are in my export? and Which orders have an effective rate that differs from a reference rate I enter? By the end of this guide, you will have tax totals by type, sales by destination, and a list of orders to review with your accountant.
Steps: 1 Export your Etsy order data | 2 Group the tax once per order | 3 Read the totals | 4 Review VAT by destination country | 5 Export a summary for your accountant | 6 Cross-check with Etsy
Question: How do sales value and tax in a small export vary by destination?
Inputs: Simulated item rows for US, UK and German orders, made with Python's random module and seed 41. The order tax is repeated on each item row, as it can be in an item-level file. The reference rates (8.25, 8.875, 6.25, 20 and 19 percent) are example rates typed for this script, not current rates for any place. "Domestic" means US and assumes a US shop; "VAT" is the script's label for every non-US order.
Method: Group item values by order. Count order tax once per order. Group sales by destination, then compare each order's effective rate, tax divided by item value, with its reference rate. This comparison flags an order for review; it does not decide tax due.
Complete Python script (standard library only):
import random
from collections import defaultdict
SEED = 41
rng = random.Random(SEED)
# Simulated item-level export. Tax repeats on each item row in an order.
# The rates are example rates typed for this script, not current rates
# for any place.
orders = [
("A101", "US", "CA", 0.0825, 2),
("A102", "US", "NY", 0.08875, 1),
("A103", "US", "TX", 0.0625, 2),
("A104", "US", "CA", 0.0825, 1),
("A105", "GB", "", 0.20, 2),
("A106", "DE", "", 0.19, 1),
]
rows = []
for order_id, country, region, rate, item_count in orders:
subtotal = rng.randint(40, 120)
parts = [subtotal // item_count] * item_count
parts[-1] += subtotal - sum(parts)
tax_rate = rate
if order_id == "A104":
tax_rate = 0.05 # Deliberate simulated mismatch to review.
order_tax = round(subtotal * tax_rate, 2)
for item_no, item_value in enumerate(parts, start=1):
rows.append({
"order_id": order_id,
"item_no": item_no,
"country": country,
"region": region,
"item_value": item_value,
"order_tax_repeated": order_tax,
"reference_rate": rate,
})
# Sum item values, but keep the repeated order tax once per order.
by_order = {}
for row in rows:
order = by_order.setdefault(row["order_id"], {
"country": row["country"],
"region": row["region"],
"value": 0,
"tax": row["order_tax_repeated"],
"rate": row["reference_rate"],
})
order["value"] += row["item_value"]
sales_by_market = defaultdict(int)
tax_by_type = defaultdict(float)
issues = []
for order_id, order in by_order.items():
market = "domestic" if order["country"] == "US" else "international"
sales_by_market[market] += order["value"]
tax_type = "sales tax" if market == "domestic" else "VAT"
tax_by_type[tax_type] += order["tax"]
effective_rate = order["tax"] / order["value"]
if abs(effective_rate - order["rate"]) > 0.005:
issues.append((
order_id, effective_rate, order["rate"],
order["tax"], order["value"]
))
total_sales = sum(sales_by_market.values())
print(f"Simulated data, seed {SEED}")
print(f"Item rows: {len(rows)}; unique orders: {len(by_order)}")
print(f"Sales tax: ${tax_by_type['sales tax']:.2f}; "
f"VAT: ${tax_by_type['VAT']:.2f}")
print(f"Tax in file: ${sum(tax_by_type.values()):.2f}")
print(
f"Domestic sales: ${sales_by_market['domestic']:.2f} "
f"({sales_by_market['domestic'] / total_sales:.1%})"
)
print(
f"International sales: ${sales_by_market['international']:.2f} "
f"({sales_by_market['international'] / total_sales:.1%})"
)
print(f"Orders flagged for review: {len(issues)}")
for order_id, observed, expected, tax, value in issues:
print(
f"Investigate {order_id}: item value ${value:.2f}, "
f"tax ${tax:.2f}, effective rate {observed:.2%}; "
f"simulated reference rate {expected:.2%}"
)
print(
"Limit: rates and orders are simulated; an effective rate alone "
"cannot establish tax owed or prove an error."
)
print("Built in: order A104 was given a 5% tax rate on purpose, so "
"the screen finds the one mismatch that was planted.")
print("All amounts are treated as one currency; a real export with "
"several currencies needs each order converted first.")
Printed output:
Simulated data, seed 41
Item rows: 9; unique orders: 6
Sales tax: $21.90; VAT: $39.27
Tax in file: $61.17
Domestic sales: $300.00 (59.8%)
International sales: $202.00 (40.2%)
Orders flagged for review: 1
Investigate A104: item value $61.00, tax $3.05, effective rate 5.00%; simulated reference rate 8.25%
Limit: rates and orders are simulated; an effective rate alone cannot establish tax owed or prove an error.
Built in: order A104 was given a 5% tax rate on purpose, so the screen finds the one mismatch that was planted.
All amounts are treated as one currency; a real export with several currencies needs each order converted first.
Result: The run made 9 item rows for 6 orders. Sales tax in the file was $21.90 and VAT was $39.27, for $61.17 in tax. Domestic sales were $300.00 (59.8%) and international sales were $202.00 (40.2%). One order was flagged: A104, $61.00 item value, $3.05 tax, an effective rate of 5.00% against a reference rate of 8.25%. The script plants that mismatch, so the screen finds what was set up. All amounts are treated as one currency, which a real export may not be.
Limit: All orders and rates are simulated. An effective rate alone cannot show tax owed or prove an error.
Before you begin this tutorial, ensure you have:
By following this tutorial, you will:
Etsy publishes its own help for downloading your data and sold transactions; see the two Etsy Help pages in Sources above. Etsy changes Shop Manager, so check the steps against Etsy's current help.
When configuring your data export:
Once downloaded, open the CSV file and look for tax columns. These names are this tutorial's own labels; your file's names will differ:
Sale Date, Order ID, Item Name, Quantity, Price, Item Total,
Sales Tax, VAT, Ship Country, Ship State
Assumption for the sketch in Step 2.2: rename the columns in your export to match these ten names (a tax or VAT column your file lacks can be added as zeros). Tax is often repeated on every item row of an order, so the sketch counts it once per order. Item Total is the one column Etsy may not give you directly: the sketch assumes it is the line amount for that item row, Price times Quantity, less any Discount Amount for that row, with Shipping excluded. If your export has a different layout, compute Item Total yourself that way before running the sketch; the rate it shows depends on that choice.
You can run the sketch below yourself, or upload your CSV at MCP Analytics.
If you prefer to check the numbers yourself first, this pandas sketch groups tax by quarter and by shipping place and compares each order's tax to its item total. It assumes the column names listed in Step 1.3; rename the columns in your export to match. Tax can repeat on every item row of an order, so the sketch first collapses the file to one row per order, summing item values and taking the order-level tax once with max. Summing the tax column over item rows would count it once per item. Treat any rate it shows as a prompt to look at the order, not as a verdict.
import pandas as pd
# Rename your export's columns to the names listed in Step 1.3.
df = pd.read_csv('etsy_tax.csv', parse_dates=['Sale Date'])
df[['Sales Tax', 'VAT']] = df[['Sales Tax', 'VAT']].fillna(0)
# Tax repeats on each item row: take it once per order.
orders = df.groupby('Order ID').agg(
sale_date=('Sale Date', 'first'),
country=('Ship Country', 'first'),
state=('Ship State', 'first'),
item_total=('Item Total', 'sum'),
sales_tax=('Sales Tax', 'max'),
vat=('VAT', 'max'))
orders['total_tax'] = orders['sales_tax'] + orders['vat']
q = orders['sale_date'].dt.to_period('Q')
by_quarter = orders.groupby(q)[['sales_tax', 'vat']].sum()
by_place = (orders.groupby(['country', 'state'], dropna=False)
['total_tax'].sum().sort_values(ascending=False))
orders['rate'] = orders['total_tax'] / orders['item_total']
rates = (orders[orders['total_tax'] > 0].groupby('state')['rate']
.agg(['min', 'mean', 'max']))
print(by_quarter.round(2))
print(by_place.head().round(2))
print(rates.round(4))
After upload you will see a summary of your file. The worked example near the top of this page is the one script whose output is shown here. Every other figure in the examples below is a made-up illustration, not from a real shop. Your counts will differ:
The analysis shows the total sales tax in your file. Whether any of it is yours to remit depends on what Etsy collected and remitted for you.
| Metric | Value | Notes |
|---|---|---|
| Total Sales Tax Collected | $8,342.67 | All US state and local taxes |
| Total VAT Collected | $2,156.44 | All EU and UK VAT |
| Combined tax collected | $10,499.11 | Sales tax plus VAT shown in the file; not necessarily what you owe |
| Average Tax per Order | $9.81 | $10,499.11 across the 1,070 transactions with tax or VAT (892 + 178) |
Before you treat any of this as your liability: part of the tax in an Etsy export may have been collected and remitted by Etsy on your behalf. See Etsy's own pages on who handles tax for your shop (second page), subtract what Etsy remits, and only then work out what you must report. This is not tax advice.
Understanding which states or regions contribute the most to your tax collection helps you see where your sales and tax are concentrated and understand your customer geography.
The analysis will show the tax rates applied to transactions in each jurisdiction. Compare these against the rate for each order's delivery address and sale date (rates differ by county and city) before concluding anything about configuration:
This page gives no jurisdiction rates, because no dated tax-authority source is cited here. Look up the rate for each delivery address and sale date at the relevant tax authority, and compare it with the effective rate in your export.
For sellers with international customers, it helps to see how much VAT appears in the file for each country. The analysis breaks down VAT collection by country:
| Country | VAT Collected | Example Rate | Transactions |
|---|---|---|---|
| United Kingdom | $1,234.56 | 20% | 87 |
| Germany | $456.78 | 19% | 34 |
| France | $287.45 | 20% | 21 |
| Other EU Countries | $177.65 | Varies | 36 |
This tutorial lists orders to review. It does not decide tax due, registration or filing. Ask a tax adviser. A tax column in an Etsy export cannot answer those questions by itself.
Compare the VAT rate in each order with a reference rate you enter. The analysis lists orders whose rate differs, for review:
# VAT rate check (synthetic example):
UK Transactions: 87 orders
- 20% VAT Applied: 82 orders ✓
- 0% VAT Applied: 5 orders ⚠️
- Possible reasons: reverse charge, an exempt buyer, or a missing tax field. Look at each order.
Germany Transactions: 34 orders
- 19% VAT Applied: 34 orders ✓
- Average Effective Rate: 19.02%
- Check: applied rate matches the 19% example reference rate
Export your file from Etsy 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 Etsy account. For your accountant, a useful summary contains:
Navigate to your Etsy Payment Account to compare the tax amounts in your analysis with what Etsy's reports show. Etsy's own pages on who handles tax for your shop are linked in Step 3:
If you use accounting software like QuickBooks or Xero, cross-reference your tax analysis results with the tax revenue recorded in your books. This verification step is crucial for maintaining accurate financial records and can be enhanced using techniques from statistical analysis for data-driven decisions.
# Reconciliation checklist (the $50 line is only an example; set your own):
□ Total sales tax collected matches payment account
□ VAT amounts match international transaction records
□ Tax-exempt transactions properly documented
□ Refunded tax amounts excluded from totals
□ Timing differences explained and documented
□ Discrepancies over $50 investigated and resolved
Export your orders from Etsy 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 Etsy account.
Your tax analysis reveals important patterns about your business:
Your analysis may list orders worth a closer look:
When analyzing multiple periods, look for trends:
# Quarterly sales tax:
Sales tax only, synthetic example, same data as the $8,342.67 total above:
Q1 2024: $1,501.68 (18% of annual)
Q2 2024: $1,334.83 (16% of annual)
Q3 2024: $1,668.53 (20% of annual)
Q4 2024: $3,837.63 (46% of annual)
In this example Q4 holds 46% of the year's sales tax.
Symptoms: Your CSV file doesn't include tax-related columns, or many transactions show blank tax fields.
Solutions:
Symptoms: The total tax in your analysis differs significantly from what shows in your Etsy Payment Account.
Solutions:
Symptoms: Many transactions in taxable jurisdictions show $0 tax collected.
Solutions:
Symptoms: VAT percentages don't match standard country rates, or vary unexpectedly.
Solutions:
Symptoms: The tool rejects your CSV file or shows data format errors.
Solutions:
This tutorial lists orders to review. It does not decide tax due, registration or filing. Ask a tax adviser. This is not tax advice.
Regular tax and VAT review helps you understand your business at a deeper level. The geographic distribution of your sales, the patterns in your tax collection, and the growth of international revenue all provide valuable insights for strategic planning.
By following this tutorial quarterly or even monthly, you'll:
Start with one quarter of your own export and the sketch above.
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
Tell us what went wrong, in your own words. We capture the page you're on automatically, so no need to describe where you are.
Not sure which plan? Compare plans →