HomeShopify & E-commerceShopify sales tax report automation with…

Shopify sales tax report automation with n8n

Shopify sales tax report automation with n8n










This shopify sales tax report automation n8n build runs on the first of every month, pulls the previous month’s orders from the Shopify Admin API, sums the tax you collected by state and jurisdiction, writes a clean summary row to Google Sheets, and emails you the totals. No paid tax app, no CSV exports, no manual pivot tables. You keep a permanent audit trail and hand your accountant a tidy sheet instead of a raw order dump.

Prefer to skip the setup? Grab the ready-made template and be running in under 10 minutes.

What it does

Every Shopify store collects sales tax, and every store owner eventually has to answer a boring but unavoidable question: how much tax did I actually collect last month, and where? Shopify shows you a total in the admin, but the moment you need it broken down by state, county, or tax name for a filing, you are back to exporting orders and building a spreadsheet by hand.

This workflow removes that chore. On a monthly schedule it reads your orders through the n8n Shopify automation pattern, then does three things:

  • Adds up total collected tax, subtotal, and gross sales for the month.
  • Breaks that tax down by jurisdiction using each order’s tax_lines, so “California State Tax” and “Los Angeles County” appear as separate lines.
  • Saves the summary to a Google Sheet and emails it to you, so the number is filed before you even open your inbox.

The output is the sheet a bookkeeper actually wants: one row per month, tax grouped by name, sales grouped by currency, and a running history you can hand over at quarter end.

Why it beats the default

Shopify’s built-in reports give you a single tax figure and a finance summary, but three things push store owners toward automation.

First, the native breakdown is shallow. You can see total tax, but pulling collected tax per jurisdiction across a full month still means an export and a pivot table. If you sell into several states with economic nexus, that manual step happens every single month.

Second, the manual export has no memory. Once you close the spreadsheet, nothing is archived in a consistent place. Six months later, when you reconcile or an accountant asks for March, you rebuild it from scratch.

Third, paid tax-reporting apps solve this but add a recurring bill and yet another dashboard to log into. For a store that just needs a monthly collected-tax summary for filing prep, that is more tool than the job requires.

The n8n version sits in the middle: it reads the same authoritative order data Shopify already stores, runs on your schedule, and drops a permanent record into a sheet you own. No per-order fee, no vendor lock-in.

📌

This is a reporting and reconciliation tool for tax you already collected. It is not a tax engine and does not decide what you owe. Always have a professional review filings.

What you need

  • A running n8n instance, either n8n Cloud or self-hosted.
  • A Shopify custom app access token created through the 2026 Shopify Dev Dashboard, with read_orders scope. If you have not connected Shopify to n8n yet, follow how to connect Shopify to n8n in 2026 first.
  • A Google account for Google Sheets and Gmail (both free tiers are plenty).
  • One blank Google Sheet with a header row to receive the monthly summaries.

Build time is roughly 30 to 40 minutes from scratch, or under 10 minutes if you import the template and paste in your credentials.

Node-by-node list

The workflow is a straight line, no branches. Six nodes, one authoritative data source.

┌────────────────────────────────────────────────────────────────┐
│  SHOPIFY MONTHLY SALES TAX REPORT                              │
│                                                                │
│  [Schedule Trigger]                                            │
│        ↓                                                        │
│  [Build Date Range] (Code)                                     │
│        ↓                                                        │
│  [Get Orders] (HTTP Request, paginated)                        │
│        ↓                                                        │
│  [Aggregate Tax] (Code)                                        │
│        ↓                                                        │
│  [Append to Sheet] (Google Sheets)   →   [Email Report] (Gmail)│
└────────────────────────────────────────────────────────────────┘
# Node Type Job
1 Schedule Trigger scheduleTrigger Fire on the 1st of each month at 06:00
2 Build Date Range code Compute previous month’s start and end in ISO
3 Get Orders httpRequest Pull last month’s orders with tax_lines, paginated
4 Aggregate Tax code Sum tax by jurisdiction, sales by currency
5 Append to Sheet googleSheets Write one summary row per month
6 Email Report gmail Send the totals to you

Step-by-step build

1 Schedule Trigger

Add a Schedule Trigger node. Set the rule to a Months interval, trigger at day of month 1, hour 6. That runs the report early on the first day of each month, covering the full month that just ended.

💡

Set your instance timezone in n8n settings before you rely on scheduled dates. A store on US Central time reporting against a UTC instance can pull the wrong day at month boundaries.

2 Build Date Range (Code)

Add a Code node to compute last month’s window. This keeps the workflow self-adjusting so you never hardcode dates.

const now = new Date();
const firstThisMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
const firstLastMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 1, 1));

return [{
  json: {
    created_at_min: firstLastMonth.toISOString(),
    created_at_max: firstThisMonth.toISOString(),
    label: firstLastMonth.toISOString().slice(0, 7) // e.g. "2026-06"
  }
}];

3 Get Orders (HTTP Request)

Add an HTTP Request node. Use GET against the Admin API orders endpoint and attach your Shopify token as a Header Auth credential named X-Shopify-Access-Token.

  • URL: https://YOUR_STORE.myshopify.com/admin/api/2026-04/orders.json
  • Query parameters: status=any, created_at_min={{ $json.created_at_min }}, created_at_max={{ $json.created_at_max }}, limit=250, and fields=id,created_at,currency,subtotal_price,total_price,total_tax,tax_lines.
  • Turn Pagination on. Set the mode to follow the response’s Link header so n8n walks every page until Shopify stops returning a next link.
💡

Requesting only the fields you need keeps each order payload small. On a busy store that is the difference between one fast call and a slow, memory-heavy pull of full order objects.

4 Aggregate Tax (Code)

This is the heart of the workflow. Add a Code node in “Run once for all items” mode. It walks every order, sums the money, and groups collected tax by the jurisdiction name Shopify records in tax_lines.

const orders = $input.all().map(i => i.json);
const byJurisdiction = {};
const byCurrency = {};
let totalTax = 0, orderCount = 0;

for (const o of orders) {
  orderCount++;
  const cur = o.currency || 'USD';
  byCurrency[cur] = byCurrency[cur] || { subtotal: 0, gross: 0, tax: 0 };
  byCurrency[cur].subtotal += parseFloat(o.subtotal_price || 0);
  byCurrency[cur].gross    += parseFloat(o.total_price || 0);
  byCurrency[cur].tax      += parseFloat(o.total_tax || 0);
  totalTax += parseFloat(o.total_tax || 0);

  for (const t of (o.tax_lines || [])) {
    const key = t.title || 'Unnamed tax';
    byJurisdiction[key] = (byJurisdiction[key] || 0) + parseFloat(t.price || 0);
  }
}

const label = $('Build Date Range').first().json.label;

return [{
  json: {
    month: label,
    order_count: orderCount,
    total_tax_collected: Number(totalTax.toFixed(2)),
    tax_by_jurisdiction: byJurisdiction,
    sales_by_currency: byCurrency,
    jurisdiction_summary: Object.entries(byJurisdiction)
      .map(([k, v]) => `${k}: ${v.toFixed(2)}`).join(' | ')
  }
}];

After this node one clean item looks like:

{
  "month": "2026-06",
  "order_count": 214,
  "total_tax_collected": 1873.44,
  "jurisdiction_summary": "California State Tax: 902.10 | Los Angeles County: 311.20 | Texas State Tax: 660.14"
}

5 Append to Sheet (Google Sheets)

Add a Google Sheets node set to the Append operation. Pick your spreadsheet and sheet, then map the columns: Month, Orders, Total Tax, and Jurisdiction Breakdown. Each monthly run adds exactly one row, so the sheet becomes a year-at-a-glance tax ledger.

6 Email Report (Gmail)

Add a Gmail node with the Send operation. Address it to yourself or your bookkeeper, subject Sales tax report {{ $json.month }}, and drop the total plus the jurisdiction summary into the body. Now the number reaches you without opening n8n or Shopify.

Common mistakes

  • Summing total_tax and also summing tax_lines into the same total. They describe the same money at different granularity. Use the order-level total_tax for the grand total and tax_lines only for the per-jurisdiction breakdown.
  • Leaving pagination off. Without it you only get the first 250 orders and every busy month silently under-reports. Always confirm the Link-header pagination is active.
  • Using status=open instead of status=any. Archived and cancelled orders still carry collected tax that belongs in a reconciliation, so any is the safe default.
  • Running the schedule against the wrong timezone, which shifts the month boundary and double-counts or drops a day’s orders.
  • Treating the output as owed tax. It is collected tax. Owed tax depends on nexus rules your accountant applies on top of this data.

Cost at realistic volume

The whole build runs on free infrastructure. Here is the monthly math for a store doing a few hundred orders.

Component Usage per run Cost
Shopify Admin API 1 to 4 paginated calls, once a month Free on every plan
n8n 1 execution/month, 6 nodes Free self-hosted, or well inside Cloud starter
Google Sheets 1 row appended Free
Gmail 1 email sent Free

Even a store pushing several thousand orders a month stays free: pagination just adds a handful of API calls, and you are still writing a single summary row. Compare that to a paid tax-reporting app billing monthly, and the automation pays for itself immediately.

🚀 Get the Shopify sales tax report template

The guide above is free to follow. If you would rather skip the build, download the ready-to-import workflow, then just add your credentials. Prefer it installed and tuned for you? See our done-for-you services.

Download the template ($14) →

Instant download · Works on n8n Cloud and self-hosted

Frequently asked questions

Does this workflow calculate the tax I owe?

No. It reports the tax you already collected from customers, grouped by jurisdiction, straight from Shopify order data. It is a reconciliation and filing-prep tool, not a tax engine. Your accountant or filing software decides what is actually remitted and where.

Which Shopify orders are included in the report?

Every order created in the previous calendar month with status=any, so paid, partially refunded, and cancelled orders all appear. You can filter to paid orders only inside the aggregation Code node if your accountant prefers a stricter cash-basis view of collected tax.

Do I need Shopify Plus or a paid tax app?

No. The workflow only reads the standard Admin API orders endpoint, which every Shopify plan exposes. There is no dependency on Shopify Tax, Avalara, or any paid reporting add-on. Your only real cost is running n8n, which can be entirely free when self-hosted.

How far back can the report go?

The default range is last month, but you can set any created_at_min and created_at_max window in the date node to pull a quarter or a full year. Shopify retains order history for the life of the store, so historical backfills work without extra tooling.

What if a customer paid in a different currency?

Shopify stores each order’s currency. The template groups totals by currency code, so multi-currency stores get one subtotal and tax figure per currency. If you only sell in one currency, that grouping collapses to a single line and you can ignore it.

Related guides

n8n
Shopify
Google Sheets
Gmail
automation