Analytics and Reporting

Overview

Data drives decisions. This chapter covers:

What Data Is Available?

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:

Building an Analytics Module

See code/analytics.py for the complete implementation.

Basic Revenue Tracking

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()))

Product Performance Analytics

Top Selling Products

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]

Products with No Sales

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]

Listing Statistics

Views and Favorites

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)

Conversion Analysis

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)

Time-Based Analytics

Monthly Comparison

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

Day of Week Analysis

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}

Creating Reports

Comprehensive Shop Report

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

Export to JSON

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

Simple Text Report

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)")

Scheduled Reporting

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)

Visualization Ideas

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).

What’s Next

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 →

← Back to Table of Contents