TL;DR
This guide shows you how to send Shopify new orders to Google Sheets with n8n, so every sale lands in a clean, append-only spreadsheet the moment a customer checks out. You wire a Shopify trigger to an Edit Fields node and a Google Sheets append step — three nodes, no code. The result is a live order log your whole team can filter, pivot, and share, without paying monthly for yet another export app.
Prefer to skip the setup? Grab the ready-made template → and be running in under 10 minutes.
What it does
The workflow listens for new Shopify orders and writes one tidy row to a Google Sheet for each one. As soon as a shopper completes checkout, Shopify fires a webhook to n8n. n8n flattens the messy order payload into the columns you actually care about — order number, date, customer, email, total, items — and appends that row to the bottom of your sheet.
You end up with a running ledger of every order that updates itself. No more exporting CSVs at the end of the week, no copy-paste, no stale numbers. If you want the wider picture of what n8n can do for a store, the n8n Shopify automation guide covers the full set of workflows this one belongs to.
┌──────────────────────────────────────────────────────────────┐ │ SHOPIFY NEW ORDERS → GOOGLE SHEETS │ │ │ │ [Shopify Trigger] → [Edit Fields] → [Google Sheets] │ │ orders/create flatten order append one row │ └──────────────────────────────────────────────────────────────┘
Why it beats the default
Shopify already lets you export orders, so why automate it? Because the built-in export is a manual, point-in-time CSV. Someone has to remember to download it, the file is out of date the second a new order arrives, and you cannot share a live view with a fulfillment partner or accountant without re-sending files.
A live Google Sheet fixes all of that. The data is current to the last order, everyone works from the same tab, and you can build pivot tables, filters, and charts on top without touching Shopify. Compared with paid order-export apps that charge a monthly fee per store, this workflow runs on tools you already have and costs nothing extra if you self-host n8n.
Tip: Keep this sheet append-only. If you need a working copy for notes or edits, duplicate the tab — never edit the raw log, so it stays a clean source of truth.
What you need
- An n8n instance — n8n Cloud or self-hosted, version 1.0 or newer.
- A Shopify store with admin access, so you can create a custom app and an Admin API access token.
- A Google account with a Google Sheet ready to receive orders.
- About 30 minutes if you build it from scratch, or under 10 minutes with the template below.
Node-by-node list
Three nodes, wired in a straight line. Here is the whole workflow before we build it:
| # | Node | Type | Job |
|---|---|---|---|
| 1 | Shopify Trigger | shopifyTrigger |
Fires on every new order (topic orders/create) |
| 2 | Edit Fields | set (v3.4) |
Flattens the order JSON into clean spreadsheet columns |
| 3 | Google Sheets | googleSheets (v4) |
Appends one row to your order log |
Step-by-step build
1 Add the Shopify Trigger
Create a new workflow and add a Shopify Trigger node as the starting point. This is the only trigger in the workflow — everything else runs after it.
- In the node, click the credential dropdown and choose Create new. Shopify uses an Access Token credential — see the credentials guide in the template for how to create a custom app and copy the token.
- Set Topic to
orders/create. This is the key choice: it fires once per new order and never on edits, so you get exactly one row per sale. - Save the node. n8n registers the webhook with Shopify automatically.
When an order comes in, the node outputs the full Shopify order object. It looks roughly like this:
{
"order_number": 1042,
"created_at": "2026-06-18T14:32:09-05:00",
"email": "james.carter@gmail.com",
"total_price": "84.00",
"currency": "USD",
"customer": { "first_name": "James", "last_name": "Carter" },
"line_items": [
{ "quantity": 2, "title": "Cedar Camp Mug" },
{ "quantity": 1, "title": "Trail Beanie" }
],
"financial_status": "paid",
"fulfillment_status": null
}
Do not wire the Shopify Trigger anywhere except as the first node. A trigger placed in the middle of a flow is one of the most common reasons an imported workflow refuses to run.
2 Map the order with Edit Fields
Add an Edit Fields node (the node type is Set) right after the trigger. The raw order has dozens of fields and nested objects; this node keeps only what belongs in your log and gives each column a clean name.
- Set the mode to Manual Mapping.
- Add one assignment per column. Give each a name, choose the String type, and paste the expression below as its value.
| Field name | Value expression |
|---|---|
order_number |
={{ $json.order_number }} |
order_date |
={{ $json.created_at }} |
customer_name |
={{ ($json.customer?.first_name || '') + ' ' + ($json.customer?.last_name || '') }} |
email |
={{ $json.email }} |
total |
={{ $json.total_price }} |
currency |
={{ $json.currency }} |
items |
={{ $json.line_items.map(i => i.quantity + 'x ' + i.title).join(', ') }} |
financial_status |
={{ $json.financial_status }} |
fulfillment_status |
={{ $json.fulfillment_status || 'unfulfilled' }} |
After this node the data is flat and ready for the sheet:
{
"order_number": "1042",
"order_date": "2026-06-18T14:32:09-05:00",
"customer_name": "James Carter",
"email": "james.carter@gmail.com",
"total": "84.00",
"currency": "USD",
"items": "2x Cedar Camp Mug, 1x Trail Beanie",
"financial_status": "paid",
"fulfillment_status": "unfulfilled"
}
Tip: The items expression collapses every line item into one readable cell like 2x Cedar Camp Mug, 1x Trail Beanie. If you would rather log one row per product, skip this and split line items instead — but for a sales ledger, one row per order is cleaner.
3 Append the row to Google Sheets
Add a Google Sheets node as the final step.
- Connect your Google credential (OAuth2). Authorize n8n to access your sheets.
- Set Resource to Sheet Within Document and Operation to Append Row.
- Pick your order-log document and the tab name, for example
Orders. - Set the mapping column mode to Map Each Column Manually and match each sheet header to the matching Edit Fields value —
order_numbertoorder_number, and so on. - Save and activate the workflow with the toggle in the top right.
The header row in your sheet must match the field names exactly, including lower-case and underscores. A mismatch is the number-one reason the append silently lands in the wrong column.
The order log schema
Create these headers in row 1 of your sheet before you run the workflow:
| Column | Example | What it stores |
|---|---|---|
order_number |
1042 | Shopify order number for reference |
order_date |
2026-06-18T14:32:09-05:00 | When the order was created |
customer_name |
James Carter | First and last name of the buyer |
email |
james.carter@gmail.com | Customer email for follow-up |
total |
84.00 | Order total before currency |
currency |
USD | Currency code |
items |
2x Cedar Camp Mug, 1x Trail Beanie | Readable line-item summary |
financial_status |
paid | paid, pending, refunded, and so on |
fulfillment_status |
unfulfilled | Fulfillment state at order time |
Common mistakes
- Picking the wrong topic. Using
orders/updatedinstead oforders/createwrites a new row every time an order changes — duplicates everywhere. Stick toorders/create. - Headers that do not match. If your sheet header reads
Order Numberbut the field isorder_number, the value lands in the wrong column or a brand-new one. Match names exactly. - Forgetting the null fulfillment status. New orders have
fulfillment_status: null. The|| 'unfulfilled'fallback keeps that cell readable instead of blank. - Building the Set node the old way. On version 3.4 the node is Edit Fields with named assignments; if you are following an old tutorial that talks about Values to Set, you are on a different version. Use Manual Mapping and add one assignment per column.
- Testing with the workflow inactive. The Shopify Trigger only registers its webhook when the workflow is active. Toggle it on, then place a test order.
Cost at realistic volume
This is about as cheap as automation gets, because none of the three services bill you for it.
| Volume | n8n self-hosted | n8n Cloud Starter |
|---|---|---|
| 200 orders / month | $0 (plus ~$5 VPS) | Well within the plan |
| 1,000 orders / month | $0 (plus ~$5 VPS) | Comfortable |
| 5,000 orders / month | $0 (plus ~$5 VPS) | Consider the Pro tier |
Each order is a single execution. Google Sheets is free up to its generous cell limit (around 10 million cells per spreadsheet — start a fresh sheet each year if you are a high-volume store). The Shopify webhook is included with every plan at no charge. If you self-host n8n, the workflow itself is effectively free; the only real cost is the small server you already run n8n on.
🚀 Get the Shopify Orders to Google Sheets Template
Skip the wiring. The template imports in minutes and ships with a pre-built sheet layout, a setup guide, and a credentials walkthrough so you only have to plug in your own keys. Want it done for you instead? See our automation services.
Instant download · Works on n8n Cloud and self-hosted
FAQ
Will this capture orders placed before I turned it on?
No. The Shopify Trigger only fires on orders created after you activate the workflow. To backfill older orders, run a one-time second workflow with a Shopify node set to Get Many Orders, then feed those into the same Edit Fields and Google Sheets append steps.
Does this slow down my Shopify checkout?
No. Shopify sends the order webhook to n8n after checkout completes, so the shopper never waits on your workflow. Even if n8n is briefly down, Shopify retries the webhook for up to 48 hours, so a short outage will not lose an order.
Can I log each month to a separate tab?
Yes. Set the sheet name in the Google Sheets node to an expression such as the current month and year. n8n appends to that tab if it exists. Create the monthly tabs ahead of time with matching headers so the append never fails midway.
Does it work with POS or draft orders?
The orders/create topic fires for online and Shopify POS orders once they become real orders. Draft orders are separate and do not trigger it until they convert. If you only want online sales, add an IF node that checks the source_name field before the append.
How do I also get a Slack or Telegram alert for big orders?
Add an IF node after Edit Fields that checks whether the total exceeds your threshold, then branch to a Telegram or Slack node. The Google Sheets append still runs for every order, while the alert only fires for the high-value ones you care about.