Skip to content
NetSuite reporting

NetSuite top customers by revenue: building a report that holds up

Build a top customers by revenue report in NetSuite, and see why revenue, invoiced and collected give three different rankings of the same customers.

ERPray teamUpdated 6 min read
Short answer

A top customers by revenue report in NetSuite is either the Sales by Customer summary report or a transaction saved search grouped by customer with amount summed, ranked descending over a date range. The ranking changes depending on whether you sum invoiced totals, posted income accounts or cash collected — decide which one you mean before publishing it.

Key takeaways

  • Invoiced, recognised and collected revenue give three different top-10 lists. Name the one you mean in the report title, not in a footnote.
  • Sales orders don't post. If a sales-side report includes them alongside invoices, every order you've billed is counted twice.
  • Cash sales are revenue. A report filtered to Type = Invoice quietly deletes your entire retail or web channel from the ranking.
  • Summing income-account accounting lines is the only definition that agrees with the income statement, because it ignores tax, freight and non-posting documents by construction.
  • Rank by margin as well as revenue. The customer at the top of the revenue list is often third or fourth once you strip the cost of serving them.

"Who are our top ten customers?" sounds like a two-minute request. It becomes a forty-minute request the moment two people produce two different lists, which is the normal outcome, because NetSuite can answer the question in at least three defensible ways. Here is the same customer for the first half of 2026, measured three ways:

$2,410,880
Invoiced — sum of invoice totals
$2,246,300
Revenue — posted to income accounts
$1,902,450
Collected — cash applied in the period

None of those is wrong. The $164,580 gap between invoiced and revenue is sales tax, freight recharges and a credit memo; the gap between revenue and collected is just terms. But if the sales director's deck uses invoiced and the CFO's uses posted revenue, the ranking will differ and you will spend the meeting on arithmetic instead of customers.

Revenue, invoiced or collected: pick one and label it

DefinitionHow it's built in NetSuiteUse it forWatch out for
InvoicedSum of transaction totals on invoices and cash sales, less credit memosSales performance and commissionIncludes tax and freight, so it will never tie to the income statement
Recognised revenueSum of accounting lines posted to income accountsAnything a finance leader will seeDeferred revenue and rev-rec schedules shift it into other periods
CollectedCustomer payments applied in the periodCash forecasting and collections priorityPayments applied to prior-period invoices distort the current ranking
Gross marginIncome lines less the COGS lines on the same transactionsDeciding who deserves attentionOnly as good as your item costing; landed cost is often missing
Four rankings of the same customer base. Put the definition in the report name — "Top customers by posted revenue, FY26 H1" — and the argument disappears.

The native report, and what it assumes

NetSuite's Sales report category includes a Sales by Customer pair — summary and detail — which is the fastest route to a ranked list. Set the date range, sort descending on amount, and you have something usable in under a minute. Before you send it, check three things.

  • What the amount column contains. Sales reports are built around transaction amounts, which can include shipping and tax depending on how your items and reports are configured. Your income statement contains only what posted to income accounts. If the two totals differ by a suspiciously round percentage, that's usually tax.
  • Whether the date range means transaction dates or posting periods. There is an accounting preference that controls whether reports are driven by posting period or by transaction date, and it can apply to financial reports only. When it does, your sales report uses transaction dates while your income statement uses periods — which is precisely how one invoice dated 31 March and posted in April makes two reports disagree.
  • Which subsidiaries are in scope. In OneWorld, the subsidiary context you're in and the consolidation you display both change the answer. A consolidated ranking translates child-subsidiary amounts at a rate, so a customer trading in two currencies can move several places purely on FX.

The saved search version

When you need customer fields the report doesn't carry — segment, region, account manager, credit terms — build it as a transaction saved search. The recipe is short:

  1. 1.Criteria: Posting is true. Type is any of Invoice, Cash Sale, Credit Memo, Cash Refund. Date is within your range. Main Line is true if you are summing the transaction total, and false if you are summing line amounts — mixing the two double-counts everything.
  2. 2.Results: Customer (group), Amount (sum), and Amount grouped by period if you want the trend beside the total.
  3. 3.Sort: descending on the summed amount. Saved searches don't take a TOP 10 — you sort and read the first ten rows, or add a criterion on summed amount if you genuinely need to cut the list short.
  4. 4.Then add the fields the report couldn't give you: customer category, sales rep, terms, or a custom field on the customer record. This is the entire reason to be in a saved search rather than a report.
Free calculator
Gross margin calculator

Take the revenue and COGS for your top account and see what the margin actually is before you decide it's your best customer.

The SuiteQL version

For the definition that ties to the income statement, go through the accounting lines rather than the transaction totals. This is the query worth keeping, because it can't accidentally include tax, freight or a non-posting order:

SELECT * FROM (
  SELECT
    c.entityid                                   AS customer,
    ROUND(SUM(tal.credit) - SUM(tal.debit), 2)   AS net_revenue
  FROM transactionaccountingline tal
  JOIN transaction t ON t.id = tal.transaction
  JOIN account a     ON a.id = tal.account
  JOIN customer c    ON c.id = t.entity
  WHERE a.accttype  = 'Income'
    AND tal.posting = 'T'
    AND t.trandate BETWEEN TO_DATE('2026-01-01', 'YYYY-MM-DD')
                       AND TO_DATE('2026-06-30', 'YYYY-MM-DD')
  GROUP BY c.entityid
  ORDER BY net_revenue DESC
) WHERE ROWNUM <= 10
Top 10 customers by posted revenue. The subquery does the ordering because ROWNUM is applied before ORDER BY.

Three notes on that query. Income is a credit balance in the ledger, so revenue is credits minus debits — get the sign backwards and your worst-returning customer tops the list. If you run multiple accounting books, add a filter on the accounting book column or you will sum every book together. And swapping the trandate range for a posting-period filter is what makes this agree with the balance-sheet-driven reports; the accountingperiod table holds quarter and year rollup rows as well as months, so filter to base periods when you build that list. If your saved queries have degenerated into single-line strings, the SuiteQL formatter will make them readable again.

Parent and child customers

This is the trap that produces a genuinely wrong answer rather than a differently-defined one. If your account uses customer hierarchies — one parent with a subsidiary or store per child record — transactions post against the child. Group by the transaction's entity and a $4.2M group appears as eleven separate $380,000 customers, none of which makes the top ten. Roll up through the customer record's parent field:

SELECT
  COALESCE(BUILTIN.DF(c.parent), c.entityid)    AS customer_group,
  ROUND(SUM(tal.credit) - SUM(tal.debit), 2)    AS net_revenue
FROM transactionaccountingline tal
JOIN transaction t ON t.id = tal.transaction
JOIN account a     ON a.id = tal.account
JOIN customer c    ON c.id = t.entity
WHERE a.accttype = 'Income'
  AND tal.posting = 'T'
GROUP BY COALESCE(BUILTIN.DF(c.parent), c.entityid)
ORDER BY net_revenue DESC
One level of rollup. Deeper hierarchies need the full parent chain, which is where a saved search's built-in customer hierarchy handling is genuinely easier.

Reading the ranking

A ranked list on its own is trivia. Three things make it a decision.

  • Concentration. Add a cumulative percentage column. If your top 5 customers are more than half of revenue, that number belongs in the board pack and in your bank covenant conversations. The same Pareto arithmetic applied to items instead of customers is what the ABC analysis calculator does.
  • Movement, not level. Rank this period against the same period last year, in the same query. The interesting rows are the ones that moved four places, in either direction. A customer sliding from 3rd to 9th is a churn conversation you would otherwise have next quarter.
  • Why revenue moved. "Revenue up 6%, margin down 2 points" is almost always mix. Decomposing it into price, volume and mix effects takes ten minutes with the price volume mix calculator, and price volume mix analysis walks through a worked example.
  • Margin per customer, not revenue per customer. Once you have income and COGS lines from the same transactions, the ranking changes shape. The mechanics of getting cost onto those lines properly are in the NetSuite item profitability report.

Or skip the build

The report is not hard. Agreeing on the definition, remembering the credit memos, rolling up the hierarchy and re-running it for a different period next week is what actually costs time. Ask "top 10 customers by posted revenue for H1, rolled up to parent, with margin" and you get the number computed live from your own NetSuite account with the SuiteQL shown underneath — so the definition is on screen instead of in someone's head.

Frequently asked questions

How do I get a top 10 customers report in NetSuite?

Run the Sales by Customer summary report for your date range and sort descending on amount, or build a transaction saved search grouped by customer with amount summed and sorted descending. Saved searches have no TOP N clause — you sort and read the first ten rows. In SuiteQL, wrap an ordered subquery and filter on ROWNUM.

Why does my NetSuite revenue by customer report not match the income statement?

Most often because the customer report sums transaction totals, which include sales tax and freight, while the income statement sums only what posted to income accounts. The second cause is date basis: sales reports may run on transaction date while financials run on posting period, so documents dated at a month boundary land in different periods.

Should cash sales be included in a top customers by revenue report?

Yes, if they represent real revenue for you. A cash sale posts income just as an invoice does; it simply skips accounts receivable. Filtering to Type = Invoice removes your entire retail, POS or web channel from the ranking, which is a common and silent error in NetSuite sales searches.

How do I roll subsidiary customers up to the parent in NetSuite reporting?

Transactions post against the child customer record, so group on the parent instead. In a saved search, use the customer's parent field as the summary field; in SuiteQL, join the customer table and group on COALESCE of the parent's name and the customer's own name. Without this, one large group appears as several mid-sized customers.

What is the difference between invoiced and recognised revenue in NetSuite?

Invoiced is the total you billed, including tax and freight, on the date you billed it. Recognised revenue is what posted to income accounts, which for anything with a revenue recognition schedule is spread across future periods. If you sell subscriptions or multi-element contracts, the two numbers can differ substantially for the same customer.

Your ERP already knows. Start asking.

ERPray computes answers like these live from your own ERP account and shows the exact query behind every number. Early access is open for NetSuite teams — free plan at launch.