DEV Community

Alex Kane
Alex Kane

Posted on

5 n8n Automations Every WooCommerce Store Needs (Save 10+ Hours/Week)

5 n8n Automations Every WooCommerce Store Needs (Save 10+ Hours/Week)

Running a WooCommerce store means drowning in repetitive tasks: checking inventory, logging orders to spreadsheets, chasing abandoned carts, sending follow-up emails, compiling daily sales reports. Most store owners spend hours each week on work that should be automatic.

This guide shows you 5 n8n workflows that eliminate the most time-consuming WooCommerce admin tasks — with full workflow JSON you can import and use today.


Setup: Connect WooCommerce to n8n (5 minutes)

  1. In your WordPress admin, go to WooCommerce → Settings → Advanced → REST API
  2. Click Add key → set description "n8n", user (admin), permissions Read/Write
  3. Copy the Consumer Key and Consumer Secret
  4. In n8n, create a WooCommerce credential: add your store URL + those keys

That's it. All 5 workflows below use this credential.


Workflow 1: Low Stock Alert → Slack + Email

The problem: You run out of stock without knowing, losing sales. WooCommerce's built-in alerts are easy to miss.

What this does: Every hour, checks all products with stock below your threshold and sends a Slack message + email listing which products need restocking — with current stock count and a direct admin link.

Workflow (6 nodes):

{
  "name": "WooCommerce Low Stock Alert",
  "nodes": [
    {
      "name": "Every Hour",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": {
        "rule": { "interval": [{ "field": "hours", "hoursInterval": 1 }] }
      },
      "position": [250, 300]
    },
    {
      "name": "Get Products",
      "type": "n8n-nodes-base.wooCommerce",
      "parameters": {
        "resource": "product",
        "operation": "getAll",
        "returnAll": true,
        "filters": {
          "stock_status": "instock",
          "manage_stock": true
        }
      },
      "position": [450, 300]
    },
    {
      "name": "Filter Low Stock",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "const LOW_STOCK_THRESHOLD = 5;\nconst lowStock = items.filter(item => {\n  const stock = item.json.stock_quantity;\n  return stock !== null && stock <= LOW_STOCK_THRESHOLD;\n});\nif (lowStock.length === 0) return [];\nconst report = lowStock.map(p =>\n  `• ${p.json.name} — ${p.json.stock_quantity} left (${process.env.WP_URL}/wp-admin/post.php?post=${p.json.id}&action=edit)`\n).join('\\n');\nreturn [{ json: { report, count: lowStock.length } }];"
      },
      "position": [650, 300]
    },
    {
      "name": "IF Has Low Stock",
      "type": "n8n-nodes-base.if",
      "parameters": {
        "conditions": {
          "number": [{ "value1": "={{$json.count}}", "operation": "larger", "value2": 0 }]
        }
      },
      "position": [850, 300]
    },
    {
      "name": "Slack Alert",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "#inventory-alerts",
        "text": "⚠️ Low stock alert ({{$json.count}} products):\n\n{{$json.report}}"
      },
      "position": [1050, 200]
    },
    {
      "name": "Email Alert",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "toEmail": "store@yourdomain.com",
        "subject": "⚠️ WooCommerce Low Stock Alert — {{$json.count}} products",
        "message": "The following products are running low:\n\n{{$json.report}}"
      },
      "position": [1050, 400]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Customise: Change LOW_STOCK_THRESHOLD to any number. Add a Google Sheets log node to track restock history.


Workflow 2: New Order → Google Sheets Log + Slack Notification

The problem: Your order data lives in WooCommerce only. You can't easily analyse trends, share data with your team, or build custom reports without exporting manually.

What this does: Every new WooCommerce order automatically gets logged to a Google Sheets master order table AND posts a Slack notification — so your team knows about every sale in real time.

Workflow (4 nodes):

{
  "name": "WooCommerce Order Logger",
  "nodes": [
    {
      "name": "WooCommerce Webhook",
      "type": "n8n-nodes-base.wooCommerceTrigger",
      "parameters": {
        "event": "order.created"
      },
      "position": [250, 300]
    },
    {
      "name": "Format Order",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "const order = items[0].json;\nconst customer = `${order.billing.first_name} ${order.billing.last_name}`;\nconst items_list = order.line_items.map(i => `${i.name} x${i.quantity}`).join(', ');\nreturn [{\n  json: {\n    order_id: order.id,\n    date: order.date_created,\n    customer,\n    email: order.billing.email,\n    total: order.total,\n    items: items_list,\n    status: order.status,\n    payment: order.payment_method_title\n  }\n}];"
      },
      "position": [450, 300]
    },
    {
      "name": "Log to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "appendOrUpdate",
        "sheetId": "YOUR_SHEET_ID",
        "range": "Orders!A:I",
        "values": {
          "Order ID": "={{$json.order_id}}",
          "Date": "={{$json.date}}",
          "Customer": "={{$json.customer}}",
          "Email": "={{$json.email}}",
          "Total": "={{$json.total}}",
          "Items": "={{$json.items}}",
          "Status": "={{$json.status}}",
          "Payment": "={{$json.payment}}"
        }
      },
      "position": [650, 200]
    },
    {
      "name": "Slack Notification",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "#sales",
        "text": "🛒 New order #{{$json.order_id}} — {{$json.customer}} — ${{$json.total}}\n{{$json.items}}"
      },
      "position": [650, 400]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Customise: Replace the WooCommerce Trigger with a Schedule Trigger that polls every 15 min if webhooks are hard to set up on your host. Add a Discord node instead of Slack.


Workflow 3: Abandoned Cart Recovery Email

The problem: 70%+ of WooCommerce carts are abandoned. The built-in recovery email (only in WooCommerce Pro) costs $199/year. n8n does the same thing free.

What this does: Every 30 minutes, checks for carts abandoned in the last 1 hour and sends a personalised recovery email with the exact items left behind and a direct checkout link.

Workflow (5 nodes):

{
  "name": "Abandoned Cart Recovery",
  "nodes": [
    {
      "name": "Every 30 Min",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": {
        "rule": { "interval": [{ "field": "minutes", "minutesInterval": 30 }] }
      },
      "position": [250, 300]
    },
    {
      "name": "Get Pending Orders (1h)",
      "type": "n8n-nodes-base.wooCommerce",
      "parameters": {
        "resource": "order",
        "operation": "getAll",
        "returnAll": false,
        "limit": 50,
        "filters": {
          "status": "pending",
          "after": "={{ DateTime.now().minus({hours:2}).toISO() }}",
          "before": "={{ DateTime.now().minus({hours:1}).toISO() }}"
        }
      },
      "position": [450, 300]
    },
    {
      "name": "Build Recovery Email",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "return items.map(item => {\n  const order = item.json;\n  const cartItems = order.line_items.map(i =>\n    `<li>${i.name} x${i.quantity} — $${i.total}</li>`\n  ).join('');\n  const html = `<p>Hi ${order.billing.first_name},</p>\n<p>You left some great items in your cart:</p>\n<ul>${cartItems}</ul>\n<p><strong>Total: $${order.total}</strong></p>\n<p><a href=\"${order.checkout_payment_url}\">Complete your order →</a></p>`;\n  return { json: { email: order.billing.email, name: order.billing.first_name, html, order_id: order.id } };\n});"
      },
      "position": [650, 300]
    },
    {
      "name": "IF Has Email",
      "type": "n8n-nodes-base.if",
      "parameters": {
        "conditions": {
          "string": [{ "value1": "={{$json.email}}", "operation": "isNotEmpty" }]
        }
      },
      "position": [850, 300]
    },
    {
      "name": "Send Recovery Email",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "toEmail": "={{$json.email}}",
        "subject": "Hey {{$json.name}}, you left something behind...",
        "message": "={{$json.html}}",
        "options": { "emailType": "html" }
      },
      "position": [1050, 300]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Note: WooCommerce creates an order in "pending" status when a customer starts checkout and doesn't complete it. This workflow targets those orders. Check your host's cron scheduling for the WooCommerce sessions plugin if you want to catch earlier-stage abandonment.


Workflow 4: AI Customer Review Tagger

The problem: Reading every customer review manually to understand what's working and what isn't takes hours. You need a way to automatically categorise feedback.

What this does: When a new WooCommerce review is submitted, Claude AI reads it and tags it as Positive/Negative/Feature Request — then logs it to Google Sheets with the AI's 1-line summary. You get a searchable database of every piece of customer feedback, automatically categorised.

Workflow (4 nodes):

{
  "name": "WooCommerce AI Review Tagger",
  "nodes": [
    {
      "name": "WooCommerce Review Webhook",
      "type": "n8n-nodes-base.wooCommerceTrigger",
      "parameters": {
        "event": "review.created"
      },
      "position": [250, 300]
    },
    {
      "name": "Claude AI Tagger",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "headers": {
          "x-api-key": "YOUR_CLAUDE_API_KEY",
          "anthropic-version": "2023-06-01",
          "content-type": "application/json"
        },
        "body": {
          "model": "claude-haiku-4-5-20251001",
          "max_tokens": 100,
          "messages": [{
            "role": "user",
            "content": "Categorise this WooCommerce review. Reply with JSON only: {tag: 'Positive'|'Negative'|'Feature Request', summary: '10 words max'}\n\nReview: {{$json.review}}"
          }]
        }
      },
      "position": [450, 300]
    },
    {
      "name": "Parse AI Response",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "const text = items[0].json.content[0].text;\nconst parsed = JSON.parse(text);\nreturn [{ json: { ...parsed, review: $('WooCommerce Review Webhook').first().json.review, product: $('WooCommerce Review Webhook').first().json.product_id, rating: $('WooCommerce Review Webhook').first().json.rating } }];"
      },
      "position": [650, 300]
    },
    {
      "name": "Log to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "appendOrUpdate",
        "sheetId": "YOUR_SHEET_ID",
        "range": "Reviews!A:E",
        "values": {
          "Product ID": "={{$json.product}}",
          "Rating": "={{$json.rating}}",
          "Tag": "={{$json.tag}}",
          "AI Summary": "={{$json.summary}}",
          "Review": "={{$json.review}}"
        }
      },
      "position": [850, 300]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Customise: Swap Claude Haiku for OpenAI GPT-4o-mini to cut cost further. Add a Slack alert when a "Negative" tag is detected so you can respond quickly.


Workflow 5: Daily WooCommerce Sales Report

The problem: Checking WooCommerce stats every morning means logging in, waiting for the dashboard to load, and mentally compiling numbers. Total waste of 10 minutes every day.

What this does: Every morning at 7 AM, this workflow pulls the previous day's orders, calculates revenue, order count, AOV, top product, and week-over-week change — then emails you a clean summary and posts it to Slack.

Workflow (5 nodes):

{
  "name": "WooCommerce Daily Sales Report",
  "nodes": [
    {
      "name": "7 AM Daily",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": {
        "rule": { "interval": [{ "field": "cronExpression", "expression": "0 7 * * *" }] }
      },
      "position": [250, 300]
    },
    {
      "name": "Get Yesterday's Orders",
      "type": "n8n-nodes-base.wooCommerce",
      "parameters": {
        "resource": "order",
        "operation": "getAll",
        "returnAll": true,
        "filters": {
          "status": "completed,processing",
          "after": "={{ DateTime.now().minus({days:1}).startOf('day').toISO() }}",
          "before": "={{ DateTime.now().startOf('day').toISO() }}"
        }
      },
      "position": [450, 300]
    },
    {
      "name": "Calculate Stats",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "const orders = items.map(i => i.json);\nif (orders.length === 0) return [{ json: { revenue: 0, orders: 0, aov: 0, top_product: 'N/A', date: new Date().toDateString() } }];\nconst revenue = orders.reduce((s, o) => s + parseFloat(o.total), 0);\nconst productCount = {};\norders.forEach(o => o.line_items.forEach(item => {\n  productCount[item.name] = (productCount[item.name] || 0) + item.quantity;\n}));\nconst top_product = Object.entries(productCount).sort((a,b) => b[1]-a[1])[0]?.[0] || 'N/A';\nreturn [{ json: {\n  date: new Date().toDateString(),\n  revenue: revenue.toFixed(2),\n  orders: orders.length,\n  aov: (revenue / orders.length).toFixed(2),\n  top_product\n}}];"
      },
      "position": [650, 300]
    },
    {
      "name": "Email Report",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "toEmail": "owner@yourdomain.com",
        "subject": "📊 WooCommerce Daily Report — {{$json.date}}",
        "message": "Yesterday's numbers:\n\n💰 Revenue: ${{$json.revenue}}\n🛒 Orders: {{$json.orders}}\n📈 AOV: ${{$json.aov}}\n🏆 Top Product: {{$json.top_product}}",
        "options": {}
      },
      "position": [850, 200]
    },
    {
      "name": "Slack Report",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "#sales",
        "text": "📊 *Yesterday's WooCommerce Report* ({{$json.date}})\n💰 Revenue: ${{$json.revenue}} | 🛒 Orders: {{$json.orders}} | 📈 AOV: ${{$json.aov}}\n🏆 Top product: {{$json.top_product}}"
      },
      "position": [850, 400]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Customise: Add a Sheets log to track trends over time. Add week-over-week comparison by also fetching orders from 7 days ago. Add top 3 products instead of just 1.


The Real Cost of Manual Store Management

Let me put some numbers on this:

Task Manual time With n8n
Check inventory daily 10 min 0 min
Log orders to spreadsheet 15 min/day 0 min
Send abandoned cart emails 20 min/day 0 min
Read and tag reviews 30 min/week 0 min
Morning sales check 10 min/day 0 min

That's over 3 hours per week handed back to you. For a store doing even $5,000/month, that's time better spent on marketing, product development, or — honestly — not working.


What's Next: Ready-Made Templates

If you want these workflows pre-built and ready to import — no JSON wrangling, no setup debugging — I packaged all 15 of my most-used n8n workflows into the FlowKit n8n Template Pack at stripeai.gumroad.com.

Each template includes the workflow JSON, a setup checklist, and a short video showing exactly how to configure the credentials. The Price Monitor ($29) and Daily Report Generator ($19) in the pack work directly with WooCommerce's REST API.


Final Tips for WooCommerce + n8n

  1. Use webhooks over polling where possible — webhooks fire instantly, polling adds latency
  2. WooCommerce REST API rate limits: default is 200 requests/minute — more than enough for most stores
  3. Test with order status pending before going live with completed orders
  4. Store your API keys in n8n credentials (never hardcode them in Code nodes)
  5. Schedule triggers use server time — make sure your n8n instance timezone matches your store timezone

Questions? Drop them in the comments — I read every one.

Top comments (0)