ProfitRoot

Help

ProfitRoot reconciles your commerce data into a source-backed margin ladder. This page is task-oriented: find the thing you are trying to do. For why we verify rather than estimate, see the methodology.

Getting started

ProfitRoot starts by reconciling Net Sales to your Shopify orders — it ties our computed total back to the source before anything else is built on top of it.

Install ProfitRoot free from the Shopify App Store. Your orders sync nightly, and Net Sales is checked against Shopify's own total to the cent. Earlier history can be added on Connections with an orders export (Orders > Export in your Shopify admin).

The export must include these columns for the reconciliation to run: Name, Financial Status, Subtotal, Lineitem quantity, Lineitem price. Upload it on Connections; once it reconciles, Net Sales is marked Matches Shopify.

Net Sales = Shopify's Subtotal (already after discounts) minus refunds; it excludes tax and shipping. Subtotal is pre-tax and pre-shipping. A synced store's refunds are read pre-tax from Shopify's refund line items; an uploaded export carries only Shopify's Refunded Amount, which is tax-inclusive.

Uploading files

These are the sources ProfitRoot accepts today. Each one unlocks a further margin layer.

Shopify Orders
Your Shopify orders export. This is the anchor — it reconciles Net Sales and is required before any other layer can be built.
Where:Orders > Export in your Shopify admin.
Unlocks:Net Sales that matches Shopify.
Product Cost
A table mapping each SKU to its unit cost. The easy path is a small two-column CSV you build (recommended); you can also upload your Shopify Products export directly — it carries Variant SKU and Cost per item, and quoted comma-bearing fields are handled. Use one of these SKU columns: SKU, Variant SKU, and one of these cost columns: Unit Cost, Cost per item. Unit costs carry no effective dates — one cost applies to every period, so a multi-period margin assumes your current costs.
Where:You maintain it yourself, from your product records or supplier costs.
Unlocks:Gross Margin (Net Sales minus COGS).

ProfitRoot uses your unit cost exactly as given — it does not prescribe a costing basis (product cost, landed cost, or fully-loaded COGS). State the basis you used; the margin is only as consistent as the basis behind it, and ProfitRoot cannot check which one you chose.

Cost coverage is capped by SKU maintenance in Shopify: a unit cost can only attach to an order line that carries a SKU, so any line exported without one cannot be costed no matter how complete your cost file is.

Gross Margin is Calculated, not Matches Shopify: a cost table has no in-file total to tie back to the way your Shopify orders do, so the figure is computed from your inputs with no external control. It becomes Checked to bill only when checked against an external control such as a GL revenue or COGS total.

Costs must be in the same currency as your Shopify orders. ProfitRoot cannot detect a cost-table currency, so you confirm it with a checkbox on Connections — until you do, a caveat names the assumed currency. This does not block Gross Margin.

Shopify Payments (payouts)
The Shopify Payments PAYOUTS / balance-transactions export, which carries a per-transaction Fee column. This is NOT the order-transactions export (see 'wrong file shape' below).
Where:Finance > Payouts > View transactions > Export in your Shopify admin.
Unlocks:Payment processor fees in the Contribution Margin ladder.
Carrier / 3PL
A shipping-cost file from your carrier or 3PL (cost per order or per shipment). This is not a Shopify export — it comes from your logistics provider. Add a period invoice total and we check the lane against it.
Where:From your carrier or 3PL's billing/export, as a CSV.
Unlocks:Logistics cost-to-serve in the Contribution Margin ladder.

Not accepted yet

ProfitRoot does not ingest these today. The readiness summary on Connections lists them so you can see what each would unlock, but there is no upload path for them yet — do not prepare these files expecting to import them: Accounting / GL (QuickBooks / Xero), and Inventory (an installed store's stock is read from Shopify nightly, so there is no file to upload). Ad Spend is different: it is accepted by upload, a Meta Ads Manager export or a Google Ads campaign report, one file per platform, checked against the bill you type in. A live connection to either is not available yet. The two file shapes are documented, not yet observed on a live export, so a file whose columns differ is refused naming the columns expected and found.

When something does not reconcile

The file did not tie (HARD-HALT)

If your Orders total does not tie to what we map from the file, the upload HARD-HALTs and is marked Does not match Shopify, showing the residual. No bridge or margin figure is rendered from an untied file — we will not build numbers on a source we could not verify. Fix the source file and re-upload.

Partial cost coverage

If some order lines have a matching cost and some do not, Gross Margin is computed on the covered portion only and the gap is named — a partial Gross Margin is never presented as a complete one. Add the missing costs to complete it. Order lines that carry no SKU at all cannot be costed (a cost table is keyed by SKU); assign SKUs to those products in Shopify and re-sync — adding costs alone will not cover them.

Costs that are not applying (unmatched SKUs)

Cost rows whose SKU matches no order line are applied to nothing, and ProfitRoot lists them. The SKU join is exact and case-sensitive, so this is usually a spelling or case mismatch between your cost table and your orders (for example ABC vs abc)— it is the most common reason costs are not applying. Check the SKUs shown as unmatched.

Wrong file shape

If a file is the wrong shape for the slot you dropped it in, ProfitRoot rejects it with a named diagnosis and computes nothing from it — nothing is silently zeroed. Two cases you may hit:

Payments. Shopify has two payments-side exports. If you upload the order-transactions export (it has Kind, Gateway and Status but no Fee column) to the payments slot, it is rejected: the payment-fee lane needs the payouts / balance-transactions export, which carries aper-transaction Fee, from Finance > Payouts > View transactions > Export.

Product Cost. A cost table needs a SKU column and one of the accepted cost columns (Unit Cost, Cost per item). If you upload an Orders export into the cost slot, ProfitRoot recognizes the Orders columns, names the mismatch, and computes nothing from it.

Why a margin layer is locked

Margin is a ladder: each layer unlocks when its source is present. When a layer is locked we name the missing source rather than estimate the number — ProfitRoot refuses fake precision (see the methodology).

1
Net Sales check — Net Sales that matches Shopify. Needs: Shopify Orders.
2
Gross profit — Net Sales minus product costs. Needs: Product Cost.
3
Profit before ads — adds logistics + payment fees. Needs: Carrier / 3PL and Shopify Payments.
4
Left after known costs — subtracts ad spend, checked against the platform's billed total. Needs: Ad Spend (a Meta Ads Manager export or a Google Ads campaign report, one file per platform, plus the month's billed total typed from Billing).
5
Inventory / Cash — your assumption. This never matches Shopify or a bill; it depends on assumptions.

Excluded orders

Not every order counts toward the Net Sales we match to Shopify. When an order is excluded, ProfitRoot names the reason, its dollar value, and its kind — the kind tells you whether it is correct, whether it will change later, or whether it needs your attention. There are four kinds:

Expected
Test orders, voided orders, and gift-card orders (deferred revenue). These are correctly and finally excluded. No action needed.
Timing — unsettled
A pending order. It is not final: it is excluded for now, but your Net Sales may change when it settles. Treat a pending order's figure as provisional, not as a final number — this is the one exclusion whose value is not yet fixed.
Problem — an unrecognized status, or totals that do not add up
An order whose Shopify financial status we do not recognize. This one needs investigating — it is not a benign exclusion.
Other
A reason ProfitRoot could not classify. It is never treated as safe — review it.

Your data

Two paths, handled differently. CSV files you upload are parsed in your browser and are not sent to us unless you save a workspace. Orders synced from a connected Shopify store are transmitted to and stored on our servers so they can be recomputed on later visits.

Full detail is on the privacy page.

Connect your own AI assistant to read your store’s figures (read-only, free on every plan). Ask Root, a question box inside ProfitRoot, is coming.

Reference: status vocabulary

Every figure and lane in ProfitRoot carries a status. The six evidence statuses describe a figure's relationship to your source data. The four operational statuses describe the process— whether a lane could be produced, or failed — and are never an evidence claim about a number.

Evidence — what a figure's relationship to source is
Matches Shopifyties back to a source total.
Calculatedcomputed from your inputs, with no external control to check against.
Checked to billchecked against an external control.
Coverage knownpresent and mapped, may still need a control.
Needs sourcethe required source is missing or incomplete.
What-ifdepends on assumptions; not reconciled actuals.
Operational — the process, not an evidence claim
Needs fixa break, not a gap: something did not tie or could not be validated, and needs fixing.
Readythe layer can be computed and produced. This does not claim a figure ties back to a source — that is Matches Shopify — only that it is now computable.
Not supportednot offered, or not applicable here. Unlike Needs source, it is not an unlockable gap you can fill by adding a source.
Partialsome of the set is covered and some is not. Unlike Coverage known, where every item is checked and any gap is named, coverage here is incomplete.

ProfitRoot · © 2026