Ecommerce Dashboard Template

A trading layout that builds itself from your own order export. Bring one row per order carrying an order date, a fulfillment status, a destination country, an item count, a subtotal, a shipping charge and a total. Drop the file and revenue over time, average order value, status mix and country breakdown appear. The columns are the template.

Load the template with sample data

The sample is the fastest way to see whether this layout fits before you go and find your own export. A store's worth of orders across a dozen countries, already at the right grain.

Download the sample CSV

The column contract

Nine columns at the order grain. The grain is the part people get wrong, so before you read the table: one row, one order, one total. If the same order number appears on four lines, this is not the file yet.

Column What it holds Role Required What breaks without it
order_id The order reference, like ORD-70000 Identifier Required You cannot verify the grain. Without it there is no way to check whether an order is on one row or four.
customer_id A stable buyer key, like C-104 Identifier Optional Distinct customers and orders per customer disappear, so you cannot tell growth from more buyers apart from growth from repeat buying.
order_date The day the order was placed Date Required Every trend goes. Revenue with no time axis is one number, and nobody needs a dashboard for one number.
status delivered, shipped, pending, refunded, cancelled Category Required Gross and net revenue become indistinguishable, and refunds are silently counted as sales.
country Destination market Category Optional No geographic mix, which is the panel that shows where shipping cost is eating the margin.
items Units in the basket Count Optional Basket size vanishes, and you lose the ability to say whether a good month came from more orders or from fuller ones.
subtotal Goods value before shipping Currency Optional Merchandise revenue cannot be separated from freight, so a shipping surcharge looks like a sales increase.
shipping Freight charged on the order Currency Optional The shipping share panel and the cost-per-market comparison go with it.
total What the customer paid Currency Required There is no headline revenue and no average order value, which is most of the dashboard.

What you get

  • A KPI strip. Orders, distinct customers, total revenue, average order value and average basket size. Five numbers that fit in a message to your co-founder.
  • Revenue over time. Sum of total per day, folded into weeks or months as the span grows. The panel everything else is checked against.
  • Order count over time. Deliberately a separate line from revenue. When the two diverge, average order value moved and that is worth knowing.
  • Revenue by country. Markets ranked by money rather than by order count, with a long tail folded into Other.
  • Status mix. Delivered against shipped against pending against refunded and cancelled, so the refund rate is a visible share instead of a footnote.
  • Order value distribution. A histogram of order totals. Ecommerce baskets are right-skewed almost everywhere, and the shape tells you where your real price points are.
  • Shipping share of revenue. Freight against goods, split by market. This is where you find the country you are subsidizing.
  • Basket size against order value. A scatter of items against total, with the correlation reported. A weak relationship usually means a few expensive single-item orders are carrying the month.

i. Bring these columns

Export orders, not line items, and rename the header row to match the contract. If your store only exports line items, group by order number and take the first value of the order-level fields with a sum of the line amounts. This is the one preparation step that genuinely matters, and it is worth ten minutes.

Keep one currency, keep refunds in the file with their status intact, and drop the address columns you do not need. A dashboard does not require a street address and an export is safer without one.

ii. Drop the file

Open the dashboard view and drop the CSV. Each column is read once and given a role from its values. A column of amounts carrying decimal places and a currency symbol is money, so it formats as $1.4k on an axis rather than as 1400. A column of ISO dates becomes the time axis with a grain chosen from the span. order_id and customer_id are identifiers, so nothing offers to sum them.

Nothing is uploaded and nothing is stored. Close the tab and the data is gone.

iii. Adjust what you need

Switch the order value panel from average to median when a handful of wholesale orders is pulling the mean somewhere no shopper lives. That single change makes more ecommerce dashboards honest than any other control on the page. Change the time grain when a daily line becomes noise. Raise the top-N on the country panel if the folded Other bar has grown larger than your third market.

Then export what you need: PNG for the trading review, SVG when it goes into something printed, and the aggregated CSV so the number in the deck and the number in the appendix cannot drift apart.

Getting your export into this shape

Every store exports orders, and almost none of them export them the way this contract wants on the first try. The reason is that an order is a header and a set of lines, and a CSV is a rectangle. Platforms resolve that by flattening to the lines and repeating the header fields down each one.

Shopify is the clearest example. Its orders export writes one row per line item, and only the first row of each order carries the financial fields; the rest have blank totals and a repeated Name. Drop that in unchanged and revenue is roughly right by accident while the order count is three times too high. WooCommerce plugins vary, but most offer a choice between one row per order and one row per item, and the setting is easy to miss. BigCommerce exports orders and products separately, which is the friendlier design. Amazon's settlement reports are transaction-level and include fees as their own rows, so they need real work before they resemble this contract at all.

The fix is always the same shape. Group by the order key. Sum the line amounts into subtotal. Sum the line quantities into items. Take the first value of the date, status, country and shipping fields, since they repeat identically down the group. Then check that your distinct order count equals your row count, because that is the assertion the rest of the dashboard rests on.

Two more traps. The first is dates with times: 2024-01-05 14:22:31 +0530 is a valid timestamp and it will produce a time axis with a point per second if the grain is left on auto and the span is short. Truncate to a day. The second is currency. A store selling in four currencies exports four currencies into one column with no rate anywhere, and summing them gives you a number that is not money in any country. Convert first, or split the file by currency and build one dashboard per market.

On status, resist the urge to tidy. It is tempting to filter the export down to delivered orders so the revenue headline looks clean. Keep the refunds and cancellations. A refund rate creeping from two to five percent over a quarter is exactly the kind of thing that only shows up when the rows are still in the file, and it is worth far more than a flattering total.

Finally, decide what total means and write it down. With tax or without, with discounts applied or before them. It does not matter enormously which one you choose. It matters a lot that the same definition is used next month, because a dashboard whose baseline silently changed is worse than no dashboard.

What this template will not do

  • No product-level analysis. The order grain has no SKU on it. Best sellers, category mix and product margin need a line-level file, which is a different contract.
  • No cohort retention. Distinct customers and orders per customer are here. Following the March cohort across six months needs a first-order date per row and a cohort grid.
  • No acquisition attribution. There is no channel, campaign or referrer in this contract. Revenue by source belongs to the web analytics layout, and joining the two needs a key neither export carries by default.
  • No profit. Cost of goods is not in an order export, so every revenue panel here is top line. Margin lives in the inventory contract.
  • One currency only. Totals are summed as plain numbers with no conversion anywhere.
  • It is a snapshot, not a feed. The dashboard shows the file you dropped. There is no store connection and nothing refreshes on its own.

Frequently Asked Questions

Is this a spreadsheet I download and fill in?

No. A template on this site is a column contract. The dashboard already knows what to build; what it needs is rows that carry order_date, status, country, items, subtotal, shipping and total. Bring those and the layout appears around them. That is a better deal than a workbook, because your store already exports this data and pasting it into somebody else's grid is the part that never survives contact with a real catalog.

Order-level or line-level rows?

Order-level. One row per order, with a single total on it. Most store exports are line-level, meaning one row per product in each order, and the same order total is repeated on every line. Drop a line-level file in and your revenue is multiplied by the average basket size, which usually lands somewhere between two and four times reality. Group by order_id, sum the line amounts, and take one row per order before you come back.

How do I tell which kind of export I have?

Count the distinct order IDs and compare that to the number of rows. If they match, it is order-level and you are ready. If there are fewer distinct IDs than rows, it is line-level. The other quick check is to look for a product or SKU column: order-level exports do not have one, because an order can contain many products and a single row cannot hold them. Shopify's orders export is line-level and this catches almost everyone once.

Why is items a count rather than a list of products?

Because a list would break the one-row-per-order grain, and because basket size is the useful number at this level. items holding 5 means five units in that order, which gives you an average basket size, a distribution of order sizes, and a way to see whether revenue growth came from more orders or from bigger ones. If you need product-level analysis, that is a different file and a different layout; keep this one at the order grain.

Does total have to equal subtotal plus shipping?

It should, and the dashboard does not check. Keeping the three consistent is what makes the shipping panels honest. If your export also carries tax or a discount, either fold them into total and accept that total no longer decomposes, or add them as their own columns so the arithmetic still closes. What causes real confusion is a total that includes tax while subtotal does not, because the shipping share then looks smaller than it is.

What should I do about refunded and cancelled orders?

Keep them, and let the status column carry the truth. The status panel exists so refunds and cancellations are visible rather than quietly removed, and the refund rate over time is often the most interesting line on the page. If you need net revenue, filter to delivered and shipped in the app before opening the dashboard. Deleting them from the export instead hides a trend you would want to know about.

Can I see repeat customers?

Partly. customer_id gives you a distinct customer count and an orders-per-customer figure, which is enough to see whether the base is widening or deepening. Proper cohort retention, where you follow the January signups for six months, needs a first-order date on every row and a cohort layout. Add a first_order_date column if you want to go that far, or build the cohort grid in the app after the dashboard has loaded.

My totals come out as text. Why?

Almost always a thousands separator in a locale the parser reads as a decimal point, or a currency code appended as a word. 1.234,56 written for a European locale and 1,234.56 written for an American one are different numbers with the same characters. Currency symbols, thousands separators, trailing percent signs and accounting parentheses are all read as numbers, but a value like 603.65 EUR is a category. Strip the code and keep the digits.

Does any of this reach a server?

No. The parsing, the aggregation and the drawing all happen in your browser tab, and there is no upload endpoint behind this page. Order exports carry customer identifiers and sometimes addresses, so this is not a small detail. Once the page has loaded you can disconnect the network entirely and the dashboard still builds.

See it on sample orders first

Already at the order grain, already in one currency. Judge the layout before you go and wrangle your own export.

Load the template with sample data