Daily
Get low-stock warnings from Shopify in Slack
Each morning Slack lists the products that will run out within two weeks at their current sales rate.
- Runs
- Daily
- Apps
- Shopify, Slack
- AI
- Not needed
- Access
- Shopify read_products, read_inventory, read_orders; Slack chat:write
Send this to your assistant
Create a ClickRuntime automation: every morning, check Shopify stock against the last 30 days of sales and post to #ops any product with less than 14 days of stock left.
First time? Adding ClickRuntime to your assistant takes about two minutes.
Why use it
Why teams use this automation
A coffee roaster sells beans, grinders and filters online. The best-selling blend sold out twice last quarter because nobody noticed stock running down until the product page showed 'sold out'. Each stockout meant lost orders and a week of waiting for the next roast.
A daily warning based on how fast each product is selling gives the team time to reorder or roast before it runs out. Slow movers show up too, so money is not tied up in stock that is not selling.
What you get out of it
Reorder before you sell out
Products are flagged by days of stock left, not a fixed number. A fast seller with 40 units left is flagged before a slow one with 10.
Fewer lost sales
Every day a best seller is out of stock is revenue that goes to a competitor. Early warnings keep popular products available.
Each product is flagged once
A product is posted when it first drops below the threshold, not every morning. The channel stays readable and each alert gets attention.
The team that orders sees it
Posting in the operations channel puts the warning in front of whoever places orders with suppliers. Nobody has to remember to check stock reports.
How it works
What happens, step by step
Every morning, ClickRuntime reads current stock for each product variant in your Shopify store.
It counts how many of each were sold in the last 30 days and works out how many days of stock remain.
Any variant with less than 14 days left is flagged, unless it was already flagged and has not been restocked.
The list is posted in your #ops Slack channel, starting with the most urgent.
Before it runs live
- Connect Shopify
- Connect Slack, then invite the app to the channel (type /invite @ClickRuntime there)
What you get
Build your own
Need it to work differently?
Your own rules
Conditions, thresholds, filters and exceptions, written the way you'd explain them to a colleague.
Any number of apps
One automation can read from one app and update several others. Over 248 apps are ready, and anything with an API works too.
AI where it helps
Summaries, classification, extraction and drafts use ClickRuntime's built-in AI, with no extra key.
On a schedule or on each event
Runs as often as every 5 minutes, or the moment an app sends an event, and keeps track of what it already handled.
Changes you can ask for
- Run it at a different time, more or less often, or only on weekdays
- Add an AI step, for example to summarize, sort or draft a reply
- Add another app, for example also send it to Google Sheets
- Combine it with other Shopify and Slack steps into one automation
Under the hood
The code that runs this automation
from datetime import date, timedelta
from collections import Counter
from clickruntime import on_trigger, credentials, http, notify, state
STORE = "your-store.myshopify.com"
def gql(query, variables=None):
resp = http.post(f"https://{STORE}/admin/api/2025-07/graphql.json", json={"query": query, "variables": variables or {}},
headers={"X-Shopify-Access-Token": credentials.connection("shopify", "store")})
return resp.raise_for_status() or resp.json()["data"]
DAYS = 14
@on_trigger
def run(event):
sold, after = Counter(), None
while True:
page = gql("""query($q: String!, $a: String) { orders(first: 100, after: $a, query: $q) { pageInfo { hasNextPage endCursor }
nodes { lineItems(first: 50) { nodes { quantity variant { id } } } } } }""", {"q": f"created_at:>={date.today() - timedelta(days=30)}", "a": after})["orders"]
sold.update({li["variant"]["id"]: li["quantity"] for o in page["nodes"] for li in o["lineItems"]["nodes"] if li["variant"]})
if not page["pageInfo"]["hasNextPage"]:
break
after = page["pageInfo"]["endCursor"]
variants = gql("{ productVariants(first: 250) { nodes { id displayName inventoryQuantity } } }")["productVariants"]["nodes"]
flagged, low = set(state.get("flagged") or []), []
for v in variants:
days = v["inventoryQuantity"] / (sold[v["id"]] / 30) if sold[v["id"]] else None
if days is not None and days < DAYS:
if v["id"] not in flagged:
low.append((days, f"{v['displayName']}: {v['inventoryQuantity']} left, about {days:.0f} days"))
flagged.add(v["id"])
else:
flagged.discard(v["id"])
if low:
notify.slack("Running low in Shopify\n" + "\n".join(t for _, t in sorted(low)), channel="#ops")
state.set("flagged", sorted(flagged))
return {"new_low": len(low)}FAQ
Common questions
How is 'days of stock' worked out?
What about products that never sell?
Does it handle variants like sizes and colours?
What permissions does it need?
Does it need AI?
How many runs does it use?
Can I change how it works?
Related
You might also like
Get a Slack alert when orders stop or ship late
Slack tells you when no orders have come in for longer than usual, or when paid orders are waiting too long to ship.
See how it worksPost yesterday's Shopify orders to Slack
Every weekday at 9, yesterday's order count and revenue are posted to your sales channel.
See how it worksPost a weekly Shopify sales report in Slack
Every Monday Slack shows last week's orders, revenue and best sellers, with a short comment on what changed.
See how it worksKeep exploring
Set up “Get low-stock warnings from Shopify in Slack” from your assistant
Copy the prompt above, or connect your assistant first. Free plan, no credit card.