automations.help

Inventory & suppliers

Send low-stock Slack alerts from Shopify inventory

A bestseller running down to zero with nobody watching is the most avoidable stockout there is. Here's how to watch Shopify's live inventory and drop a clear, actionable alert in Slack the moment a SKU crosses its low-stock line — once per dip, not on every sale.

Difficulty
Intermediate
Time to build
2-4 hrs
Updated
  • Shopify
  • Slack

The manual way today

Nobody is actually watching inventory. Someone notices a bestseller is low when they happen to open the product, or when a customer asks why it's gone — and by then it's usually already at zero. The reorder that should have gone out a week ago hasn't, because the person who places purchase orders never got a heads-up while there was still time to do anything about it.

A stockout on your best SKU is lost margin on the exact item you can least afford to lose it on — plus the ad spend still driving traffic to a 'sold out' page, plus the customers who buy the substitute from someone else and don't come back. None of it lands in a report. The sale that never happened because the shelf was empty simply isn't a row anywhere.

What running looks like

The moment a SKU's available stock crosses its low-stock threshold, a clear message lands in your #inventory Slack channel: what's low, how many units are left, roughly how many days of cover that is, and a direct link to reorder. It fires once per dip — not on every sale — resets itself when the product restocks, and a daily sweep catches anything a dropped webhook missed.

01The build

How to build it

  1. Set the low-stock line per SKU, not one global number

    Needs a human

    Decide what 'low' means before automating anything, and resist a single store-wide number. A bestseller that sells 40 units a day and takes three weeks to restock needs a far higher threshold than a long-tail SKU that sells one a week. The honest math is average daily velocity × supplier lead time + a safety buffer — enough cover to survive the reorder wait. Pick where the threshold lives so the person who owns the numbers can edit it without touching the flow: a variant metafield, a product tag like reorder-at:50, or a row in a Google Sheet keyed by SKU.

  2. Catch Shopify's inventory_levels/update webhook in n8n

    Runs itself

    Subscribe to the inventory_levels/update webhook and point it at an n8n webhook node. It fires on every stock change — a sale, a restock, a manual count fix — and the payload is lean: inventory_item_id, location_id, and the new available quantity. No product or SKU yet; the next step resolves that. One topic drives the whole thing, because the same event that trips a low alert is the one that later clears it on restock.

  3. Resolve to the product, sum the right locations, read its threshold

    Runs itself

    The webhook only hands you an inventory_item_id, so look up what it belongs to. Use Shopify's GraphQL inventoryItem query to walk inventoryItem → variant → product and pull the SKU, the product and variant title, and the variant's threshold from wherever you stored it in step one. Sum available across only the locations that actually fulfill online orders — ignore a damages, quarantine, or staff location, or you'll treat stock no customer can ever receive as cover.

  4. Alert only on the downward crossing

    Runs itself

    Compare available to the threshold, but alert only on the moment it crosses down — was above, is now at or below. Skip this and you'll re-alert on every single sale while the SKU sits under the line, and the channel turns into noise people mute. Track the last-known state per SKU — a small store in n8n, an Airtable or Sheet field, or a product tag like low-alerted — so a crossing fires exactly one alert and a SKU already known-low stays quiet.

  5. Build a Slack message the team can act on

    Runs itself

    A bare 'X is low' just makes someone go dig. Post the whole picture to a dedicated #inventory channel via a Slack incoming webhook (or chat.postMessage for richer formatting): product and variant, SKU, units left, the threshold it crossed, and a days-of-cover estimate — units left ÷ trailing daily velocity — so the urgency is obvious at a glance. Add the supplier and lead time if you have them, and a direct deep link to the product in Shopify admin so reordering is one click, not a search.

  6. Add a cool-down and a restock reset so it never nags

    Runs itself

    Once a SKU has alerted, suppress further alerts for it until it either restocks back above the threshold plus a small buffer or a cool-down window (say 5 days) passes — whichever comes first. The restock reset is the important half: when stock crosses back up, clear the low-alerted flag so the next genuine dip alerts again. Without the reset you alert once ever; without the cool-down you alert daily. You want exactly one ping per real dip.

  7. Escalate zero louder than low

    Runs itself

    Treat 'low' and 'out' differently. A SKU crossing its low line is an FYI in the channel. A bestseller actually hitting zero is a different message — @-mention the person who places purchase orders, or post to a louder channel — because that one is already costing money, not warning about it. The same flow handles both; it just picks the tone from how far under the line the stock fell.

  8. Backstop with a daily sweep

    Runs itself

    Webhooks get dropped, and stock can drift low through a path that doesn't fire a clean event. Once a day, run an n8n schedule that pulls every SKU with its threshold, finds anything currently at or below that hasn't already alerted, and posts a short digest. It's the safety net that turns 'we usually catch it' into 'we catch it' — and it's where a SKU whose numbers don't add up surfaces for a person to look at.

02The stack

What it’s built on

Shopify
System of record for live inventory. It emits the inventory_levels/update webhook, answers the variant-SKU-threshold lookup, and holds the per-SKU thresholds in metafields or tags. Shopify Flow can even send a basic low-stock Slack message natively, with no glue at all.
Slack
Where the alert lands. A free incoming webhook (one URL) covers simple posts; chat.postMessage gives you richer formatting and @-mentions for the escalation step.
n8n
The glue for the version Shopify Flow can't do: per-SKU thresholds, the days-of-cover math, crossing detection, the cool-down and restock reset, and the daily sweep.n8n is open-source and self-hostable for free; its cloud tier just saves you running it yourself. Be honest with yourself first, though — if one global threshold and a plain 'stock is low' message is all you need, Shopify Flow does that natively at no cost and you can skip the glue entirely. n8n earns its place once you want per-SKU thresholds, days-of-cover, and the cool-down.

03Questions

Before you build

Can't Shopify Flow do this for free?

For the simple version, yes — and you should use it if that's all you need. Shopify Flow can watch inventory and post a basic 'low stock' message to Slack with no extra tools. Where it runs out of room is the stuff that makes the alert actually useful: a different threshold per SKU, a days-of-cover estimate, alerting only on the downward crossing instead of every sale, a cool-down so it doesn't nag, and a daily sweep to catch dropped events. That logic is what the n8n build adds. Start with Flow; graduate when the noise gets annoying.

Should the threshold be one number or per product?

Per product, or at least per tier — a single global number is the thing that makes these alerts useless. The math is average daily units sold × your supplier's lead time in days, plus a safety buffer for a bad week, so a SKU selling 40/day on a three-week lead needs cover in the hundreds while a slow mover needs a handful. Store the number where the person who owns it can edit it — a variant metafield, a reorder-at:N tag, or a SKU-keyed sheet — not buried in the flow.

Won't it spam Slack every time someone buys a unit?

No, because it alerts on the crossing, not the condition. The flow fires only when stock moves from above the threshold to at-or-below it, and then a cool-down plus a restock reset keep it quiet until the SKU genuinely recovers and dips again. You get one ping per real dip — not one per sale while it sits low.

Does it handle multiple warehouses or locations?

Yes. It sums available stock across only the locations that actually fulfill online orders, so the threshold is measured against stock a customer could really receive. A damages, quarantine, or staff location is left out on purpose — counting it would hide a stockout behind units no order can ever pull from.

What if Shopify drops the webhook?

That's what the daily sweep is for. Webhooks do get dropped, and stock sometimes drifts low through a path that doesn't fire a clean event. Once a day the flow pulls every SKU with its threshold, finds anything at or below that didn't already alert, and posts a digest — so a missed real-time event becomes, at worst, a few hours' delay instead of a silent stockout.

Can I build this myself, or should you build it?

Every webhook, field, threshold, and edge case is written out above on purpose — if you've got a few hours and some API comfort, build it yourself, and if your needs are simple, start with Shopify Flow and skip us entirely. If you'd rather not own the crossing logic, the cool-down, and the daily sweep, we'll build it on the Shopify, Slack, and n8n accounts you already pay for, document every piece, and hand you the keys. You own the workflow outright — no monthly retainer, and nothing stops working if you walk away. It starts with a free 20-minute teardown where we map where your stockouts are actually happening, not a contract.