Ask a shop owner who also sells online what their worst operational problem is, and a large fraction will describe the same afternoon: a customer orders the last one on the website, and forty minutes earlier somebody bought it off the shelf. Now there is an apology to write and a refund to process.
This is the inventory sync problem, and almost every solution to it is worse than the obvious one, which is to not have two inventories in the first place.
Sync is a workaround, not a goal
The standard architecture is a hosted POS holding one stock number and WooCommerce holding another, with a connector shuttling updates between them. Every connector has the same three weaknesses:
- Latency. Sync happens every few minutes, or every hour, or nightly. The window between a shop sale and the website learning about it is the window in which you oversell.
- Mapping. Products must be matched across two systems by SKU. Someone will eventually create a product in one system and not the other, or change a SKU, and the connector will quietly stop updating that line.
- Conflict. When both systems change the same number before a sync completes, one write wins. Which one is often unspecified.
Connectors are impressive engineering aimed at a problem you can dissolve. If the register writes directly to WooCommerce, the shop and the website are reading the same row of the same table. There is nothing to sync because there is only one number.
What “one inventory” actually means
When a cashier scans a jacket and takes payment, OpenPOS creates a normal WooCommerce order. Not an export, not a nightly summary — the same kind of order the website creates. Stock decrements immediately, the order appears in WooCommerce → Orders, and your reports, exports and accounting integrations all see it because it is not a special case.
The website’s product page updates within the same request. The next online customer to load that page sees the true number.
The three genuine race conditions
Sharing a database removes nearly all the risk, and it is dishonest to claim it removes all of it. Three cases remain.
Two buyers in the same second
Both the counter and the website try to claim the last unit within milliseconds of each other. WooCommerce holds stock during checkout to make this vanishingly rare. If you have one unit of something and a hundred people want it, sell it by auction, not by till.
Offline sales
An offline register decrements stock when its queued orders reach the server, not when the sale happened. During an outage the website does not know about in-store sales. This is unavoidable — the two systems cannot agree on a number they cannot both reach — and it is the price of being able to trade at all when the line drops. Read more in our guide to how offline mode works.
Caching
A page cache serving a stale product page will happily show “in stock” for an item that sold ten minutes ago in the shop. This is not an inventory bug, it is a caching configuration, and it is the most common cause of an apparent sync failure on a WooCommerce site. Exclude cart, checkout and account pages from caching, and be careful about caching product pages with stock counts on them.
Reserving stock for the shop floor
Sometimes one number is not what you want. A shop with a display model, or a chain where the website ships from a warehouse rather than from the stores, needs the shop’s stock and the web’s stock kept apart on purpose.
Model this with outlets. OpenPOS treats each store and each warehouse as a location holding its own quantity, with transfers between them. Make the website’s fulfilment source a warehouse; then a sale at the Manchester till moves Manchester’s number and leaves the warehouse untouched.
Adopt this deliberately, not by accident. Per-location stock is more accurate and requires a person to record every transfer. Shared stock is simpler and occasionally wrong. Pick the failure you prefer.
Practical rules that prevent oversells
- Manage stock at the variation level, not the parent product. Three sizes of a t-shirt are three stock numbers.
- Do not track stock on things that are not countable. Cooked food, services, made-to-order items.
- Keep a buffer on scarce, high-demand lines. Show nine when you have ten, and the last one is always yours to give the customer standing in front of you.
- Count regularly, in small slices. A rolling count of one category a week beats a full stocktake once a year that everybody dreads and nobody finishes.
- Record damage and shrinkage as adjustments. A number you never correct is a number your staff learn to distrust.
Frequently asked questions
How often does OpenPOS sync stock?
There is no sync interval, because there is no second database. The register writes to WooCommerce directly.
Do POS orders appear in WooCommerce reports?
Yes. They are ordinary WooCommerce orders, tagged with the outlet, register and cashier, so you can report on in-store and online separately or together.
Will my accounting or ERP plugin see in-store sales?
If it reads WooCommerce orders, yes, with no special integration. That is the practical benefit of not inventing a parallel order type.
What about products I sell online only?
Hide them from the POS product grid by category. They stay in the same catalogue without cluttering the register.
Sell something on the live demo register (admin / admin123), then open the WordPress admin demo and watch the order and the stock level. That is the whole argument in thirty seconds.
If you are earlier in the decision, start with does WordPress have a POS system? Otherwise, OpenPOS is a one-time purchase with lifetime updates and unlimited registers.