#Where this differs from the online store
The post on Shopify inventory not updating covers the connector between Shopify and an ERP or warehouse: SKUs that don't match, the wrong field mapped, two apps writing the same count. This one is about the till. Shopify POS writes straight into Shopify's inventory, at the location the device is set to, so when its counts go wrong the reason is usually something that happened in a store.
Shopify's own rule is short: "When you sell or restock a product on Shopify POS, the inventory count updates for that location." Every cause below breaks one part of that sentence: the sale, the restock, or the location.
#The 6 store-side causes
#1. The device is set to the wrong location
A device keeps a location, chosen when POS was set up on it. If a tablet moved from one store to another, or a new store copied an old store's setup, its sales come off the other store's stock. Shopify's help pages mention the location mostly for tax, but the stock follows it too.
How to see it: in Shopify POS, tap the menu, then Settings, and scroll to Location. In the admin, each device and its location are listed under the Point of Sale channel's devices. In your figures, it shows as a pair: one store too high, another too low by the same units.
#2. Sales are waiting on an offline device
Shopify is plain about this: "Shopify POS can't sync orders and inventory with your Shopify admin when you're offline." Once the device reconnects, orders and inventory should sync on their own. Until then, every offline sale is a unit Shopify still thinks is on the shelf.
The risk is a device switched off or signed out with sales still pending: Shopify warns that this "might cause loss of offline orders". Then the stock never moves at all.
How to see it: the connectivity icon in POS turns red when the internet is disconnected. The difference equals that till's sales during the outage, and it clears when the device comes back.
#3. It went through as a custom sale
A custom sale is for "an item that you haven't already added as a product". It has a price and a title but no product behind it, so there is no stock for it to reduce. Staff reach for the Add custom sale tile when a barcode won't scan or the item won't come up in search, and the real product's count stays where it was.
How to see it: look for custom sale lines in that store's orders on the day. Shopify notes they don't show in reports the way a product sale does.
#4. The variant isn't tracked, or isn't stocked at that store
POS needs inventory tracking switched on for each product: in the admin, Track quantity on the variant. Without it there is no count to change. A store that opened recently can also have no quantity allocated to its location at all. Shopify's own troubleshooting says that when POS counts don't match the shelf after a new store opens, "quantities likely weren't allocated to the new location before launch."
How to see it: the variant shows as not tracked, or the store's row is missing from the export altogether. In the figures, the store sells and the count never moves, night after night.
#5. A return was refunded without restocking
In a POS return, staff can switch Restock at this location off when an item should not go back into stock. If it is switched off for an item that does go back on the shelf, Shopify's count stays one lower than the shelf for good. The reverse happens too: a damaged item restocked at the till is counted as sellable.
Returns and exchanges can't be done offline at all.
How to see it: the difference matches a return on that store's orders, and the variant's adjustment history shows no restock for it.
#6. The app is showing an old count
Sometimes Shopify's admin is right and only the screen in the store is behind. POS should sync when it opens, and you can force it: tap the connectivity icon, tap Shopify, and under Products and inventory tap Refresh. Shopify's other advice is to keep the app up to date.
How to see it: the admin and your count agree, and the tablet disagrees. Refresh it before you change anything.
#Line up every store at once
Looking at one SKU tells you it is wrong. Looking at every store shows you why, because causes 1, 2 and 5 leave patterns you can only see across locations.
- In the Shopify admin, go to Products > Inventory and click Export.
- Under Export from, choose all locations.
- Under Inventory states shown, select All states.
- Choose the variants, export as CSV, and click Export inventory.
The file has one row per variant per location, with SKU, Location, Available and On hand (current). The other side is the count you trust for each store: the ERP's stock, if it books the store's sales from somewhere other than Shopify, or the store's last count. Save it as counted.csv with three columns, sku, location and on_hand, and name the locations as Shopify does.
This script prints every SKU and location where the two differ, plus the rows on one side only:
import csv
import sys
from collections import defaultdict
def number(text):
text = (text or "").strip()
if text == "":
return 0
try:
return int(float(text))
except ValueError:
return None # "not stocked", "not tracked" and the like
def load(path, sku_col, loc_col, qty_col):
counts = defaultdict(int)
flags = {}
with open(path, newline="", encoding="utf-8-sig") as f:
for row in csv.DictReader(f):
sku = (row.get(sku_col) or "").strip()
if not sku:
continue
key = (sku, row[loc_col].strip())
qty = number(row[qty_col])
if qty is None:
flags[key] = row[qty_col].strip()
else:
counts[key] += qty
return counts, flags
shop, shop_flags = load(sys.argv[1], "SKU", "Location", "On hand (current)")
mine, _ = load(sys.argv[2], "sku", "location", "on_hand")
print("sku,location,shopify,counted,difference,note")
for key in sorted(set(shop) | set(mine) | set(shop_flags)):
sku, loc = key
if key in shop_flags:
print(f"{sku},{loc},,{mine.get(key, '')},,{shop_flags[key]}")
elif key not in shop:
print(f"{sku},{loc},,{mine[key]},,missing in Shopify")
elif key not in mine:
print(f"{sku},{loc},{shop[key]},,,missing in your count")
elif shop[key] != mine[key]:
print(f"{sku},{loc},{shop[key]},{mine[key]},{shop[key] - mine[key]},")Run it as python compare_stock.py inventory_export.csv counted.csv > differences.csv. It compares on hand, not available, because a count on the shelf includes units committed to open orders. If your file names the stores differently from Shopify, rename them first; the CSV comparison post covers keys that almost match.
#A worked example
An invented chain of 120 stores runs Shopify POS on a tablet at every till. The ERP books each store's stock from goods received and a weekly count. One Monday morning, the script returns these rows:
| SKU | Location | Shopify on hand | Counted | Difference |
|---|---|---|---|---|
| TEE-BLK-M | ST-014 | 14 | 9 | +5 |
| TEE-BLK-M | ST-022 | 3 | 8 | −5 |
| MUG-WHT | ST-031 | 12 | 10 | +2 |
| SCARF-RED | ST-037 | 4 | 5 | −1 |
| CAP-NVY | ST-004 | 6 | missing in Shopify |
Invented figures. Read the patterns, not the numbers:
- ST-014 and ST-022, +5 and −5 on the same SKU. The units sold at one store came off the other. A tablet at ST-014 had been set up with ST-022 as its location (cause 1). Changing the device's location stops it; moving five units back in Shopify fixes the count.
- ST-031, +2. Two mugs went through as custom sales on Saturday, when the barcode label wouldn't scan (cause 3). Adjust the count, then fix the label.
- ST-037, −1. One scarf was returned and refunded with Restock at this location off, and went back on the rail (cause 5).
- ST-004, missing. CAP-NVY has never had stock allocated to ST-004 in Shopify, though the store has six (cause 4). Every sale of it at that store has had nothing to reduce.
Four of the six causes, found in one export, and none of them visible from a single product page.
#Doing it every night
The export and the script take a few minutes. The trouble is that the differences come back: another tablet is set up from the wrong template, another Wi-Fi outage falls on a Saturday, another label won't scan. The first person to notice is usually a customer told that the item is in stock at their store.
DataMosaic runs that comparison every night against the systems themselves. Its Shopify connection asks for read-only access to orders, products, stock and locations, and arrives with a Stock by location query and an Orders query that names the store for POS sales. A check sets Shopify's stock by location against the ERP's, per SKU and store; its rules say how far apart is too far. A row that differs offers an investigation, so the +5 and −5 pair points at a device's location rather than at a stock-take. If you want Mosaic to act, say by emailing the store manager when the same store differs two nights running, that is a workflow you build.
The same idea, comparing at a grain both systems keep, is how POS and ERP sales are checked each morning.
#Questions people ask
#Why is my Shopify POS not updating inventory?
Most often the device is set to another location, sales are still pending on an offline device, the item was rung up as a custom sale, or the variant isn't tracked or stocked at that store. Export inventory with all states and compare it per SKU and location to see which.
#Does Shopify POS update inventory when offline?
No. POS can't sync orders or inventory while it is offline; they should sync on their own when the device reconnects. Don't switch the device off or sign out while offline sales are pending, or they can be lost.
#Do custom sales in Shopify POS reduce inventory?
No. A custom sale is for an item that isn't a product in Shopify, so there is no stock count behind it to reduce.
#How do I refresh inventory in Shopify POS?
Tap the connectivity icon, tap Shopify, and tap Refresh under Products and inventory. If the admin is right and the app still isn't, update the app.
#Which location does a Shopify POS sale take stock from?
The location the device is set to, shown under Settings > Location in the app. A device set to the wrong store takes its sales off that store's stock.