Data drives decisions. This chapter covers:
The Etsy API provides access to:
| Data Type | Available Via |
|---|---|
| Sales/Revenue | Receipts endpoint |
| Order details | Transactions endpoint |
| Listing views | Listing stats |
| Favorites | Listing data |
| Shop stats | Shop endpoint |
What’s not available:
See code/analytics.py for the complete implementation.
from datetime import datetime, timedelta
from collections import defaultdict
def calculate_revenue(orders):
"""Calculate total revenue from orders."""
total = 0
for order in orders:
price = order["total_price"]
total += price["amount"] / price["divisor"]
return total
def revenue_by_period(client, shop_id, days=30):
"""Get revenue broken down by day."""
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
orders = get_orders_in_range(client, shop_id, start_date, end_date)
daily = defaultdict(float)
for order in orders:
date = datetime.fromtimestamp(order["create_timestamp"]).date()
price = order["total_price"]
daily[str(date)] += price["amount"] / price["divisor"]
return dict(sorted(daily.items()))
def top_products(client, shop_id, days=30, limit=10):
"""Get top selling products by revenue."""
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
orders = get_orders_in_range(client, shop_id, start_date, end_date)
products = defaultdict(lambda: {"sales": 0, "revenue": 0, "title": ""})
for order in orders:
for transaction in order.get("transactions", []):
listing_id = transaction["listing_id"]
price = transaction["price"]["amount"] / transaction["price"]["divisor"]
products[listing_id]["title"] = transaction["title"]
products[listing_id]["sales"] += transaction["quantity"]
products[listing_id]["revenue"] += price * transaction["quantity"]
# Sort by revenue
sorted_products = sorted(
products.items(),
key=lambda x: x[1]["revenue"],
reverse=True
)
return sorted_products[:limit]
def products_without_sales(client, shop_id, days=30):
"""Find products that haven't sold in N days."""
# Get all active listings
listings = get_all_listings(client, shop_id)
all_listing_ids = {l["listing_id"] for l in listings}
# Get sold listing IDs
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
orders = get_orders_in_range(client, shop_id, start_date, end_date)
sold_ids = set()
for order in orders:
for transaction in order.get("transactions", []):
sold_ids.add(transaction["listing_id"])
# Find unsold
unsold_ids = all_listing_ids - sold_ids
return [l for l in listings if l["listing_id"] in unsold_ids]
def listing_engagement(client, shop_id):
"""Get views and favorites for all listings."""
listings = get_all_listings(client, shop_id)
stats = []
for listing in listings:
stats.append({
"listing_id": listing["listing_id"],
"title": listing["title"][:50],
"views": listing.get("views", 0),
"favorites": listing.get("num_favorers", 0),
"fav_rate": listing.get("num_favorers", 0) / max(listing.get("views", 1), 1)
})
return sorted(stats, key=lambda x: x["favorites"], reverse=True)
def conversion_analysis(client, shop_id, days=30):
"""Analyze view-to-sale conversion."""
# Get listings with views
listings = get_all_listings(client, shop_id)
# Get sales data
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
orders = get_orders_in_range(client, shop_id, start_date, end_date)
# Count sales per listing
sales_count = defaultdict(int)
for order in orders:
for transaction in order.get("transactions", []):
sales_count[transaction["listing_id"]] += transaction["quantity"]
# Calculate conversion rates
analysis = []
for listing in listings:
listing_id = listing["listing_id"]
views = listing.get("views", 0)
sales = sales_count.get(listing_id, 0)
analysis.append({
"listing_id": listing_id,
"title": listing["title"][:40],
"views": views,
"sales": sales,
"conversion": (sales / views * 100) if views > 0 else 0
})
return sorted(analysis, key=lambda x: x["conversion"], reverse=True)
def monthly_comparison(client, shop_id, months=3):
"""Compare performance across recent months."""
results = []
for i in range(months):
# Calculate month boundaries
end_date = datetime.now().replace(day=1) - timedelta(days=i*30)
start_date = end_date - timedelta(days=30)
orders = get_orders_in_range(client, shop_id, start_date, end_date)
revenue = calculate_revenue(orders)
results.append({
"month": start_date.strftime("%Y-%m"),
"orders": len(orders),
"revenue": revenue,
"avg_order": revenue / len(orders) if orders else 0
})
return results
def sales_by_day_of_week(client, shop_id, days=90):
"""Analyze which days perform best."""
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
orders = get_orders_in_range(client, shop_id, start_date, end_date)
by_day = defaultdict(lambda: {"orders": 0, "revenue": 0})
for order in orders:
date = datetime.fromtimestamp(order["create_timestamp"])
day_name = date.strftime("%A")
by_day[day_name]["orders"] += 1
by_day[day_name]["revenue"] += (
order["total_price"]["amount"] / order["total_price"]["divisor"]
)
# Order by day of week
day_order = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
return {day: by_day[day] for day in day_order}
def generate_shop_report(client, shop_id, days=30):
"""Generate a comprehensive shop performance report."""
report = {
"generated": datetime.now().isoformat(),
"period_days": days
}
# Basic stats
shop = client.get(f"/application/shops/{shop_id}")
report["shop"] = {
"name": shop["shop_name"],
"active_listings": shop["listing_active_count"],
"total_favorites": shop["num_favorers"]
}
# Revenue
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
orders = get_orders_in_range(client, shop_id, start_date, end_date)
report["performance"] = {
"total_orders": len(orders),
"total_revenue": calculate_revenue(orders),
"average_order": calculate_revenue(orders) / len(orders) if orders else 0
}
# Top products
report["top_products"] = top_products(client, shop_id, days, limit=5)
return report
import json
def save_report(report, filename="shop_report.json"):
"""Save report to JSON file."""
with open(filename, "w") as f:
json.dump(report, f, indent=2, default=str)
return filename
def print_report(report):
"""Print a human-readable report."""
print(f"\n{'='*50}")
print(f"Shop Report: {report['shop']['name']}")
print(f"Period: Last {report['period_days']} days")
print(f"{'='*50}\n")
print(f"Active Listings: {report['shop']['active_listings']}")
print(f"Shop Favorites: {report['shop']['total_favorites']}")
print(f"\nOrders: {report['performance']['total_orders']}")
print(f"Revenue: ${report['performance']['total_revenue']:.2f}")
print(f"Avg Order: ${report['performance']['average_order']:.2f}")
print(f"\nTop Products:")
for listing_id, data in report['top_products'][:5]:
print(f" - {data['title'][:30]}: ${data['revenue']:.2f} ({data['sales']} sales)")
Automate weekly reports:
import schedule
import time
def weekly_report_job(client, shop_id, email=None):
"""Job to generate and optionally email weekly report."""
report = generate_shop_report(client, shop_id, days=7)
filename = f"weekly_report_{datetime.now().strftime('%Y%m%d')}.json"
save_report(report, filename)
print_report(report)
# Optionally send via email (implement your own)
# send_email(email, report)
# Schedule for every Monday at 9 AM
# schedule.every().monday.at("09:00").do(weekly_report_job, client, shop_id)
While the API returns data, visualization requires additional tools:
# Export data for visualization in other tools
def export_for_visualization(client, shop_id, days=30):
"""Export data in CSV format for tools like Excel or Tableau."""
daily_revenue = revenue_by_period(client, shop_id, days)
with open("daily_revenue.csv", "w") as f:
f.write("date,revenue\n")
for date, amount in daily_revenue.items():
f.write(f"{date},{amount}\n")
For Python visualization, consider matplotlib or plotly (not covered here, but the data structures work directly).
Analytics help you understand your business. The next chapter covers handling errors gracefully—an essential skill for reliable automation.
| ← Previous: Inventory & Variations | Next: Error Handling → |