Automate Shopify with n8n: Orders, Inventory & Customer Workflows
Automate Shopify with n8n: Orders, Inventory & Customer Workflows
Shopify is a powerful e‑commerce platform, but many routine tasks – such as confirming new orders, notifying staff when stock runs low, rescuing abandoned carts, and tagging customers for marketing – can be time‑consuming when done manually. By integrating Shopify with n8n, you can build fully automated workflows that react to events in real time, keep your data synchronized, and free up your team to focus on growth.
In this tutorial we will walk through four practical automations:
- Order processing – create a record in a Google Sheet (or any destination) whenever a new order arrives.
- Inventory alerts – send a Slack message (or email) when a product’s inventory falls below a threshold.
- Abandoned cart follow‑up – trigger a personalized email or SMS after a cart has been idle for a configurable period.
- Customer tagging – automatically add or remove Shopify customer tags based on order value, frequency, or custom criteria.
Each step includes exact node names, field configurations, and expressions you can copy‑paste into your n8n instance. The tutorial assumes you are using n8nautomation.cloud as your managed n8n host, but the same steps work on any self‑hosted or cloud‑n8n deployment.
Prerequisites
- n8n instance – accessible via HTTPS. If you prefer a hassle‑free setup, sign up for
n8nautomation.cloud (managed hosting, automatic updates, SSL, and backups). - Shopify store – you need admin access to create a private app and generate API credentials.
- Destination services (optional but used in the examples):
- Google Sheets (for order logging) – a Google account with access to Google Drive.
- Slack (for inventory alerts) – a Slack workspace where you can create an Incoming Webhook.
- Email (SendGrid, SMTP, or Gmail) – for abandoned‑cart follow‑ups.
- Shopify API – for customer tagging (no extra service needed).
- Basic n8n familiarity – know how to create a workflow, add nodes, and connect them.
- Environment variables (recommended) – store secrets like API keys outside the workflow for security.
Step 1 – Create Shopify API Credentials
Before n8n can talk to Shopify, you must generate API credentials from your Shopify admin.
- Log in to your Shopify admin panel.
- Navigate to Apps & sales channels → Develop apps → Create an app.
- Give the app a name (e.g., “n8n Automation”) and click Create app.
- In the app dashboard, go to API credentials.
- Under Admin API access token, click Generate token.
- Select the following Access scopes (minimum required for the workflows):
read_orderswrite_ordersread_productswrite_productsread_customerswrite_customersread_draft_orderswrite_draft_orders
- Click Save, then copy the generated Admin API access token.
- Also note your Shop name (the part before
.myshopify.com) – you’ll need it for the API URL.
Store these two values securely. In n8nautomation.cloud you can add them as Environment Variables:
SHOPIFY_SHOP– e.g.,myawesomestoreSHOPIFY_TOKEN– the long token you just generated
Step 2 – Set Up the n8n Workflow Foundation
We’ll start with a single workflow that contains multiple sub‑workflows (or “branches”) triggered by different Shopify events. This keeps the logic modular and easier to maintain.
- In n8n, click Workflows → New Workflow.
- Give it a descriptive name, e.g.,
Shopify Automation Suite. - Click the + button to add the first node.
- Search for Shopify Trigger and add it.
Shopify Trigger Node Configuration
- Resource:
Order - Operation:
Created - Shopify Store:
{{ $env["SHOPIFY_SHOP"] }}.myshopify.com - Access Token:
{{ $env["SHOPIFY_TOKEN"] }} - Trigger On:
All Orders(you can later filter by financial status if needed)
This node will fire every time a new order is placed in your store.
Branch 1 – Order Processing (Google Sheets Logging)
We’ll now add a branch that takes the order data and appends a row to a Google Sheet.
- Click the + button on the Shopify Trigger node to create a new branch.
- Search for Google Sheets and add the node.
- In the Google Sheets node, set:
- Operation:
Append - Spreadsheet ID: paste the ID from your Google Sheet URL (e.g.,
1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms) - Sheet Name:
Orders(create this sheet if it doesn’t exist) - Columns: Map the fields you want to log. Use the Expression mode to pull data from the previous node.
Field Mapping (Expression Mode)
| Column Header | Expression (value from previous node) |
|---|---|
| Order ID | {{ $json["id"] }} |
| Order Name | {{ $json["name"] }} |
| Customer Email | {{ $json["customer"]["email"] }} |
| Total Price | {{ $json["total_price"] }} |
| Financial Status | {{ $json["financial_status"] }} |
| Fulfilled? | {{ $json["fulfillment_status"] }} |
| Created At | {{ $json["created_at"] }} |
| Line Items Count | {{ $json["line_items"].length }} |
Make sure to toggle Options → Include All Fields off and manually add each column as shown above.
Branch 2 – Inventory Alert (Slack Notification)
Instead of triggering on order creation, we’ll create a separate workflow that runs on a schedule (e.g., every 15 minutes) and checks low‑stock products.
- Create a new workflow named
Shopify Inventory Monitor. - Add a Cron node as the trigger.
- Configure Cron:
- Every X:
15minutes - At Minute:
0(or any minute you prefer)
Next, add a Shopify node to fetch product inventory levels.
- After the Cron node, click + → Shopify.
- Set:
- Resource:
Product - Operation:
Get All - Shopify Store:
{{ $env["SHOPIFY_SHOP"] }}.myshopify.com - Access Token:
{{ $env["SHOPIFY_TOKEN"] }} - Return All:
true(to paginate through all products)
Now we need to filter products where inventory is below a threshold (e.g., 5). Add an IF node.
- Connect the Shopify node to an IF node.
- Set the condition to evaluate each product’s variants.
- Because a product can have multiple variants, we’ll use a Function node first to flatten variant inventory.
Function Node – Flatten Variants
// Input: array of products from Shopify node
const output = [];
for (const product of items[0].json) {
for (const variant of product.variants) {
// Assume inventory quantity is stored in variant.inventory_quantity
const qty = variant.inventory_quantity ?? 0;
output.push({
productId: product.id,
productTitle: product.title,
variantId: variant.id,
variantTitle: variant.title,
inventoryQuantity: qty,
sku: variant.sku ?? ''
});
}
}
return output;
Set the Function node to Execute Once Per Item (default) and connect its output to the IF node.
IF Node Condition
- Value 1: {{ $json["inventoryQuantity"] }}
- Operation:
<(less than) - Value 2:
5(adjust threshold as needed)
Connect the True output of the IF node to a Slack node.
- Add a Slack node, choose Operation:
Send Message. - Authentication: Create a Slack credential of type Incoming Webhook (or use OAuth if you prefer).
- Set:
- Channel:
#inventory-alerts(or your preferred channel) - Text (use Expression mode):
{{
`:warning: Low stock alert!\n*Product:* {{$json["productTitle"]}}\n*Variant:* {{$json["variantTitle"]}}\n*SKU:* {{$json["sku"] || "N/A"}}\n*Current Qty:* {{$json["inventoryQuantity"]}}\n*Threshold:* 5
`}}
Optionally, add an Email node after the Slack node to send a duplicate alert to a distribution list.
Branch 3 – Abandoned Cart Follow‑Up
Shopify does not expose a native “abandoned cart” webhook, but we can poll for carts that have been updated more than X minutes ago and have no associated order.
- Create a new workflow named
Shopify Abandoned Cart. - Add a Cron trigger (run every 20 minutes).
- Add a Shopify node to fetch checkouts (carts).
- Resource:
Checkout - Operation:
Get All - Shopify Store:
{{ $env["SHOPIFY_SHOP"] }}.myshopify.com - Access Token:
{{ $env["SHOPIFY_TOKEN"] }} - Return All:
true
Next, filter checkouts that have not been completed and were last updated more than, say, 30 minutes ago.
- Add a Function node to compute the age of each checkout.
// Input: array of checkouts
const now = new Date();
const output = [];
for (const c of items[0].json) {
// Skip if checkout already has an order (completed)
if (c.order_id) continue;
const updatedAt = new Date(c.updated_at);
const diffMs = now - updatedAt;
const diffMinutes = diffMs / (1000 * 60);
if (diffMinutes > 30) { // threshold
output.push({
checkoutId: c.id,
email: c.email,
cartToken: c.cart_token,
updatedAt: c.updated_at,
minutesAgo: Math.round(diffMinutes),
lineItems: c.line_items
});
}
}
return output;
Connect the Function node to an IF node that simply checks if the array length > 0 (you can also skip the IF and go straight to the email node; the email node will handle an empty array gracefully).
Add an Email node (or SendGrid, SMTP, etc.) to send a follow‑up message.
- Configure the Email node:
- From: your verified sender address (e.g.,
orders@yourstore.com) - To: {{ $json["email"] }}
- Subject:
We noticed you left something behind! - Text (HTML mode recommended):
<p>Hi {{ $json["email"].split("@")[0] }},</p>
<p>It looks like you forgot to complete your purchase. Here’s what you left in your cart:</p>
<ul>
{{#each $json["lineItems"]}}
<li>{{this.quantity}} × {{this.title}} ({{this.variant_title}}) – ${{this.price}}</li>
{{/each}}
</ul>
<p>Complete your order now and enjoy free shipping:</p>
<p><a href="https://{{$env["SHOPIFY_SHOP"]}}.myshopify.com/cart/{{$json["cartToken"]}}?checkout_url=%2Fcheckout%2F{{$json["cartToken"]}}">Return to Cart</a></p>
<p>Best,</p>
<p>The {{ $env["SHOPIFY_SHOP"] }} Team</p>
Tip: If you want a series of reminders (e.g., 1 hour, 4 hours, 24 hours), duplicate the workflow and adjust the Cron schedule and the time threshold in the Function node.
Branch 4 – Customer Tagging Based on Order Value
Finally, we’ll automatically tag customers when they place a high‑value order (e.g., > $200) or when they reach a lifetime spend threshold.
- Create a workflow named
Shopify Customer Tagger. - Use the same Shopify Trigger node as in Step 2 (Order → Created).
- Add a Function node to calculate whether the order qualifies for a tag.
// Input: order object from Shopify Trigger
const order = items[0].json;
const total = parseFloat(order.total_price) || 0;
const customerId = order.customer?.id;
// Define your tagging rules
let tagsToAdd = [];
if (total > 200) {
tagsToAdd.push("high-value");
}
// Example: fetch lifetime spend from a custom meta field or external DB.
// For simplicity, we’ll just tag based on this order only.
// In a real scenario you could query the customer resource and sum past orders.
return {
customerId,
tagsToAdd,
orderId: order.id
};
Connect the Function node to a Shopify node (resource: Customer, operation: Update).
- Set the Shopify node:
- Resource:
Customer - Operation:
Update - Customer ID: {{ $json["customerId"] }}
- Fields to Update:
tags(we’ll append)
To append tags without overwriting existing ones, we need to fetch the current tags first, merge, then update.
- Insert another Shopify node before the Update node:
- Resource:
Customer - Operation:
Get - Customer ID: {{ $json["customerId"] }}
Add a Function node to merge tags:
// Input 0: current customer (from Get node)
// Input 1: tagsToAdd + identifiers (from previous Function node)
const customer = items[0].json;
const newTags = items[1].json.tagsToAdd || [];
const currentTags = (customer.tags || "").split(",").map(t => t.trim()).filter(t => t);
const merged = [...new Set([...currentTags, ...newTags])]; // deduplicateconst tagsString = merged.join(", ");
return {
customerId: items[1].json.customerId,
tags: tagsString,
orderId: items[1].json.orderId};
Finally, connect this Function node to the Shopify Update node, mapping the tags field to {{ $json["tags"] }}.
Testing the Workflows
Before activating any workflow, run a test execution to ensure data flows correctly.
- In each workflow, click the Execute Workflow button (top‑right).
- For trigger‑based workflows (Order Created, Abandoned Cart), you can manually fire a test event:
- Place a test order in Shopify (use a discount code to make it $0 if you don’t want to charge).
- Create a test checkout and leave it idle for >30 minutes to trigger the abandoned cart branch.
- Adjust a product’s inventory to below the threshold to see the Slack alert.
- Check the output of each node:
- Google Sheets node should have added a new row with the expected values.
- Slack node should have posted a message in the designated channel.
- Email node should have delivered the abandoned‑cart reminder (check spam folder).
- Shopify Update node should have added the appropriate tag to the customer profile (view the customer in Shopify admin).
- If any node fails, examine the error message in the node’s output panel; n8n shows the exact HTTP response from Shopify, which often includes helpful details (e.g., missing permissions).
Once satisfied, toggle the workflow’s Active switch to enable automatic execution.
Common Issues & Troubleshooting
1. “Invalid Shopify domain” or “401 Unauthorized”
This usually means the SHOPIFY_SHOP or SHOPIFY_TOKEN environment variables are missing, malformed, or the token lacks required scopes.
- Double‑check that the shop name does not include
https://or.myshopify.com– just the subdomain. - Verify the token was generated with
read_orders,write_orders,read_products,write_products,read_customers,write_customersscopes. - If you recently rotated the token, update the environment variable and restart the workflow (or redeploy).
2. Google Sheets “Access Not Configured”
n8n’s Google Sheets node uses OAuth2. If you see an error about missing access:
- In n8n, go to Credentials → New Credential → Google Sheets OAuth2.
- Follow the prompts to authorize n8n to access your Google Drive.
- Ensure the target spreadsheet is shared with the email address used in the OAuth flow (or set sharing to “Anyone with the link can edit”).
3. Slack webhook returns “invalid_payload”
The Slack node expects a plain text payload unless you enable “Attachments” or “Blocks”. If you’re using markdown‑style formatting, switch the node to Block Kit mode or escape characters.
- Alternatively, keep the message plain text and use Slack’s native formatting (
*bold*,_italic_).
4. Abandoned cart workflow fires too often or not at all
Because we poll checkouts, timing is crucial.
- If you see many duplicate emails, increase the Cron interval (e.g., to 30 minutes) or raise the minutes‑ago threshold.
- If you see no emails, verify that test checkouts are truly
order_id: nulland that theupdated_atfield is being set correctly (Shopify updates it when cart items change). - Consider adding a filter to exclude checkouts with an email address that matches a known internal address (to avoid spamming yourself).
5. Customer tagging creates duplicate tags
If you notice the same tag appearing multiple times, the merging function may not be deduplicating correctly.
- Ensure you trim whitespace and convert to a consistent case before deduplication.
- In the Function node, replace the merge line with:
const normalized = currentTags.map(t => t.toLowerCase().trim());
const normalizedNew = newTags.map(t => t.toLowerCase().trim());
const mergedSet = new Set([...normalized, ...normalizedNew]);
const merged = Array.from(mergedSet).map(t => t.charAt(0).toUpperCase() + t.slice(1)); // optional title casereturn { tagsString: merged.join(", ") };
6. Workflow exceeds execution time limit
Large stores with thousands of products can cause the Inventory Monitor workflow to timeout.
- Enable pagination in the Shopify node (Return All = false) and use the Shopify Node’s “Page Size” to fetch 50‑100 records per call, then loop using the IF node to continue until
hasNextPageis false. - Alternatively, move the inventory check to a separate serverless function (e.g., AWS Lambda) and call it via n8n’s HTTP Request node.
Conclusion
By leveraging n8n’s flexible node‑based architecture, you can turn repetitive Shopify chores into reliable, event‑driven automations. The four workflows demonstrated here—order logging, low‑stock alerts, abandoned cart recovery, and dynamic customer tagging—form a solid foundation that you can expand:
- Add a Delay node after the abandoned cart email to schedule a second reminder.
- Use the HTTP Request node to push order data into a data warehouse (e.g., Snowflake, BigQuery) for deeper analytics.
- Integrate with SMS providers like Twilio for time‑sensitive alerts.
- Create a customer‑segmentation workflow that tags users based on browsing behavior (using Shopify’s
Visitwebhook or Google Analytics events).
Remember that security and maintainability are key: store secrets in environment variables, document each workflow’s purpose, and periodically review credentials and permissions.
If you prefer a managed experience that handles updates, backups, and SSL automatically, consider hosting your n8n instance on n8nautomation.cloud. Their platform lets you focus on building automations rather than managing infrastructure, ensuring your Shopify workflows stay online and performant 24/7.
Happy automating!