Offline-First POS Sync: How Checkout Works Without Internet
Local billing, queued stock deductions, and conflict-safe replay — how a checkout counter keeps selling when the internet does not cooperate.
By Samiul Arafah Dhrubo · August 26, 2026
What runs locally
Three capabilities must survive total internet loss, so they run entirely on the shop floor device:
- Billing: barcode scan, price lookup from the locally synced product catalog, discounts, VAT calculation, baki (customer credit) recording, and receipt generation — full checkout with zero network calls.
- Stock deduction queue: each sale writes an inventory event to local storage and appends it to an outgoing sync queue, so on-hand counts stay live on this terminal even while disconnected.
- Receipt printing: thermal printers connect over Bluetooth/USB directly; receipts render from local data and never wait on a server round-trip.
The product catalog, prices, and customer list sync down to the device whenever connectivity exists — a few MBs that fit comfortably on any POS hardware. The one thing we deliberately do not do offline is card/wallet authorization: bKash merchant payments need the network, which is why the payment flow has its own path (below).
The queue-and-replay sync pattern
[Checkout on POS] Sale completed offline
│ written to local DB + outbox queue (ordered by
▼ monotonically increasing local sequence number)
┌──────────────┐ reconnect detected ┌──────────────────┐
│ Outbox queue │ ──────────────────────▶ │ Server replay │
│ sale events, │ batched, oldest first │ validates stock, │
│ idempotency │ ◀────────────────────── │ applies ledger │
│ keys │ ack per batch / │ events │
└──────────────┘ conflict report └──────────────────┘
│ │
▼ ▼
Receipt already Conflict resolution:
printed from LWW per product + audit log
local dataEvery queued event carries an idempotency key (device ID + local sequence), so a retry after a dropped connection can never double-apply a sale. The server replays events in sequence order, revalidates them against current server state — sufficient stock, valid product, sane totals — and acknowledges each batch. Only after an explicit server ack does the client mark the event as synced and remove it from the outbox.
An offline-first system must treat reconnecting as a routine operation, not an emergency — if two days of sales cannot replay cleanly in seconds, the sync design has already failed.
Conflict resolution rules
Conflicts are inevitable when two terminals sell the same SKU while offline. Our rules are deliberately boring and auditable:
- Sales always win: money that changed hands is never reversed automatically; if stock goes negative after replay, we accept the negative balance and flag it rather than un-sell reality.
- Last-write-wins per product for master data only — price edits or product renames — keyed on server timestamp.
- Every conflict writes to an audit log with both versions, timestamps, device IDs, and the rule applied, so owners review discrepancies instead of losing them silently.
- Transfers replay atomically as matched pairs (out + in); a half-arrived transfer parks in a pending state visible on both branches' dashboards until resolved.
What bKash/Nagad reconciliation looks like offline
When the internet drops, cash and baki keep flowing but mobile wallet payments become a deferred problem. The POS records these sales with payment status wallet_pending: the cashier takes the customer's bKash/Nagad confirmation SMS as proof, and the sale completes normally with a printed receipt noting the pending verification.
On reconnect, the sync engine pushes the pending wallet transactions into a dedicated reconciliation view rather than marking them paid. The owner matches each entry against the merchant statement — transaction ID, amount, timestamp — inside a tolerance window (amount exact, time within ±15 minutes). Matched transactions flip to settled; unmatched ones surface as exceptions with both sides shown. This turns what used to be an end-of-day notebook exercise into a queue with a clear count: “7 pending, 6 matched, 1 needs attention.”
Testing approach: the flight-mode suite
Offline behavior that is not tested continuously will rot quietly, so we test it like a feature, not an accident. Our end-to-end suite runs the real checkout flow with the network layer in flight mode: complete a sale, kill the connection mid-batch, restart the app, corrupt a queue entry on purpose, then restore connectivity and assert the replay converges to exactly the expected ledger state. Two assertions matter most — no sale is ever lost or duplicated across any crash/reconnect sequence, and every conflict produced a corresponding audit-log row. The suite runs in CI on every PR, because the most dangerous regression is the silent kind: everything looks fine until the first rainy-season outage.
Related
See our POS software and our work for electronics retailers and grocery stores.
Need a POS that survives outages?
Book a free consultation. We'll demo offline checkout and show you exactly how sync and reconciliation work for your shop.
Get Free Consultation