Profit Margin Calculator

Read-only: calculates true net profit per order and per product by factoring in COGS, shipping costs, transaction fees, discounts, refunds, and taxes.

shopify-admin-profit-margin-calculator


Purpose

Calculates true net profit and margin at both order-level and product-level granularity. Unlike basic revenue reports, this skill deducts all cost components — COGS (from inventoryItem.unitCost), shipping costs, transaction/payment processing fees, applied discounts, refund amounts, and duties/taxes — to surface actual margin percentages. Read-only — no mutations.


Prerequisites

  • Authenticated Shopify CLI session: shopify store auth --store --scopes read_orders,read_products,read_inventory
  • API scopes: read_orders, read_products, read_inventory
  • For accurate results, products should have inventoryItem.unitCost populated

  • Parameters


    ParameterTypeRequiredDefaultDescription
    storestringyesStore domain (e.g., mystore.myshopify.com)
    days_backintegerno30Lookback window for orders
    group_bystringnoorderGrouping: order, product, or variant
    min_ordersintegerno1Minimum orders for a product to appear (product/variant mode)
    include_refundedbooleannotrueInclude fully refunded orders in calculation
    formatstringnohumanOutput format: human or json

    Safety


    > ℹ️ Read-only skill — no mutations are executed. Safe to run at any time.


    Workflow Steps


  • OPERATION: orders — query
  • Inputs: query: "created_at:>=''", first: 250, select id, name, createdAt, totalPriceSet, subtotalPriceSet, totalShippingPriceSet, totalTaxSet, totalDiscountsSet, currentTotalPriceSet, displayFinancialStatus, refunds { totalRefundedSet }, lineItems { variant { id, inventoryItem { id, unitCost { amount, currencyCode } } }, quantity, originalTotalSet, discountedTotalSet }, pagination cursor

    Expected output: All orders in window with full cost breakdown


  • OPERATION: inventoryItems — query
  • Inputs: Batch of inventoryItemIds from line item variants for any missing unitCost data

    Expected output: Unit cost for each inventory item


  • For each order, calculate:
  • Revenue = currentTotalPriceSet.shopMoney.amount
  • COGS = Σ(lineItem.quantity × variant.inventoryItem.unitCost)
  • Shipping Cost = totalShippingPriceSet.shopMoney.amount (merchant-paid portion estimate)
  • Discounts = totalDiscountsSet.shopMoney.amount
  • Transaction Fee = estimated at 2.9% + $0.30 of total (configurable)
  • Refunds = Σ(refunds.totalRefundedSet.shopMoney.amount)
  • Net Profit = Revenue - COGS - Shipping - Transaction Fee - Refunds
  • Margin % = (Net Profit / Revenue) × 100

  • If group_by: product or variant, aggregate profits by product/variant across all orders

  • OPERATION: productVariants — query (enrichment)
  • Inputs: Variant IDs from profitable/unprofitable items for product title context

    Expected output: Product titles, SKUs for display


    GraphQL Operations


    # orders:query — validated against api_version 2025-01
    query OrdersWithCosts($query: String!, $after: String) {
      orders(first: 250, after: $after, query: $query) {
        edges {
          node {
            id
            name
            createdAt
            displayFinancialStatus
            totalPriceSet { shopMoney { amount currencyCode } }
            subtotalPriceSet { shopMoney { amount currencyCode } }
            totalShippingPriceSet { shopMoney { amount currencyCode } }
            totalTaxSet { shopMoney { amount currencyCode } }
            totalDiscountsSet { shopMoney { amount currencyCode } }
            currentTotalPriceSet { shopMoney { amount currencyCode } }
            refunds {
              totalRefundedSet { shopMoney { amount currencyCode } }
            }
            lineItems(first: 50) {
              edges {
                node {
                  quantity
                  originalTotalSet { shopMoney { amount currencyCode } }
                  discountedTotalSet { shopMoney { amount currencyCode } }
                  variant {
                    id
                    sku
                    inventoryItem {
                      id
                      unitCost { amount currencyCode }
                    }
                    product {
                      id
                      title
                    }
                  }
                }
              }
            }
          }
        }
        pageInfo { hasNextPage endCursor }
      }
    }
    

    # inventoryItems:query — validated against api_version 2025-01
    query InventoryItemCosts($ids: [ID!]!) {
      nodes(ids: $ids) {
        ... on InventoryItem {
          id
          unitCost { amount currencyCode }
        }
      }
    }
    

    # productVariants:query — validated against api_version 2025-01
    query VariantDetails($ids: [ID!]!) {
      nodes(ids: $ids) {
        ... on ProductVariant {
          id
          sku
          title
          product { id title vendor }
        }
      }
    }
    

    Session Tracking


    Claude MUST emit the following output at each stage. This is mandatory.


    On start, emit:

    ╔══════════════════════════════════════════════╗
    ║  SKILL: Profit & Margin Calculator           ║
    ║  Store: <store domain>                       ║
    ║  Started: <YYYY-MM-DD HH:MM UTC>             ║
    ╚══════════════════════════════════════════════╝
    

    After each step, emit:

    [N/TOTAL] <QUERY|MUTATION>  <OperationName>
              → Params: <brief summary of key inputs>
              → Result: <count or outcome>
    

    On completion, emit:


    For format: human (default):

    ══════════════════════════════════════════════
    PROFIT & MARGIN REPORT  (<days_back> days)
      Orders analyzed:     <n>
      Total Revenue:       $<amount>
      Total COGS:          $<amount>
      Total Shipping:      $<amount>
      Total Tx Fees:       $<amount>
      Total Refunds:       $<amount>
      ─────────────────────────────
      Net Profit:          $<amount>
      Overall Margin:      <pct>%
    
      Top profitable products:
        "<product>"  Margin: <pct>%  Profit: $<n>
      Bottom margin products:
        "<product>"  Margin: <pct>%  Profit: $<n>
      Output: profit_report_<date>.csv
    ══════════════════════════════════════════════
    

    For format: json, emit:

    {
      "skill": "profit-margin-calculator",
      "store": "<domain>",
      "period_days": 30,
      "orders_analyzed": 0,
      "total_revenue": 0,
      "total_cogs": 0,
      "total_shipping": 0,
      "total_tx_fees": 0,
      "total_refunds": 0,
      "net_profit": 0,
      "overall_margin_pct": 0,
      "currency": "USD",
      "output_file": "profit_report_<date>.csv"
    }
    

    Output Format

    CSV file profit_report_.csv with columns:

    order_id, order_name, date, revenue, cogs, shipping, discounts, tx_fees, refunds, net_profit, margin_pct


    For product grouping: product_id, product_title, vendor, units_sold, revenue, cogs, net_profit, margin_pct


    Error Handling

    ErrorCauseRecovery
    THROTTLEDAPI rate limit exceededWait 2 seconds, retry up to 3 times
    Missing unitCostProduct COGS not setFlag as "unknown COGS" — include in report but exclude from margin calc
    Refunded ordersFully refundedInclude with $0 net revenue if include_refunded: true

    Best Practices

  • Populate inventoryItem.unitCost on all products for accurate COGS. Without it, margins cannot be calculated.
  • Adjust transaction fee estimate based on your payment processor (default 2.9% + $0.30 matches Shopify Payments US).
  • Use group_by: product to identify which products are margin-positive vs. margin-negative.
  • Cross-reference with stock-velocity-report to find fast-selling but low-margin items that may need repricing.
  • Use results with bulk-price-adjustment to increase prices on margin-negative products.