Start your free 14-day trial
Product Job Scheduling & RotasInvoicing & BACSHealth & SafetyStaff Mobile AppAnalytics & Reporting
Solutions Commercial CleaningDomestic CleaningEnd of TenancyFacilities ManagementWindow Cleaning
Free tools Cleaning Quote CalculatorPrice Per m² CalculatorUK VAT CalculatorProfit Margin CalculatorTrue Cost of a CleanerHoliday Entitlement CalculatorContract Tender CalculatorClient Lifetime Value All 14 free tools →
Learn How to start a cleaning businessHow to price cleaning jobsHow to win cleaning contractsHealth & safety for cleaners CleanFlo vs JobberCleanFlo vs ZenMaid
Browse all guides

Working with no signal

Cleaners work in basements, plant rooms and stairwells. CleanFlo is built on the assumption that the network is missing rather than present, so nothing a cleaner taps depends on it.

In the app: Cleaner app Open CleanFlo
On this page

Most software treats a lost connection as an error. In this trade it is a Tuesday. A cleaner spends the middle of their shift in a basement with a phone showing no bars, and a product that responds by throwing an error, or worse by quietly dropping the tap, teaches them to stop tapping. That is how you end up with a schedule full of jobs that were done and never marked.

So the rule in the cleaner app is absolute: every write is applied locally first and queued. The screen changes on the tap. The network catches up later, or it does not, and either way the work is safe on the phone.

What happens when the signal goes

Nothing visible, which is the point. The list stays on screen because it was painted from the phone's own copy in the first place. Taps keep landing. The only change is a small amber pill in the header, showing the word Offline on its own or the number of changes waiting once anything is queued. That pill is the cleaner app's own wording, not the banner you get in the web app; the two are different components and are described separately further down.

09:41
Thursday 13 August Offline
48m Weekly clean Harbour Lettings · 12 Quay Street Started at 13:04
Today 2/3
8:00 am Communal areas Riverside Homes · Flat 4B Done
10:30 am Plant room and stores Bay View Offices Done
This week 2
9:00 am Weekly clean St Marks Medical Centre
1:00 pm End of tenancy Harbour Lettings · 14 Fore St
Waiting to send
Jobs History My Time Messages Me
The Jobs tab with no signal, and it is the same page it always was. The only change is one small pill in the header, reading Offline on its own or the number of changes waiting once anything is queued, and the sync line at the foot. Every entry below is being read from this phone rather than from the server.

CleanFlo does not decide whether it is online by asking the phone. navigator.onLine answers a narrower question than the app needs: it is true whenever any network interface is up, which includes a site wifi with no route out, a captive portal at a reception desk, and one bar that never completes a request. Those three are exactly the conditions this app exists for. Instead it makes a real HTTPS request to the server and waits up to six seconds for an answer. A captive portal cannot fake that, because it cannot complete the handshake.

OfflineSyncingCached
The three states the cleaner app's own header pill can show, and the whole of its offline vocabulary. Cached appears when the list on screen came from the phone rather than the server, which is normal and is not an error.

The queue

Every change goes into a queue held in IndexedDB on the phone itself. Two properties of that queue matter more than anything else about it.

Order
"Started a job" has to land before "Finished a job", or your records are nonsense. The queue is strict first in, first out, and it stops at the first failure rather than letting later writes overtake a stuck one.
Liveness
A write that can never succeed used to be retried on every reconnect forever, blocking everything behind it. Each operation now carries an attempt count and is set aside after five tries so the rest can drain.

The queue flushes in three ways: the moment the connection is verified back, when the service worker fires a background sync, and on a 30-second backstop timer that runs the whole time the app is open. A cleaner does not have to do anything, and in normal use never sees any of it.

The queue does not hold table names and column payloads as far as the cleaner is concerned. Every operation is described in their own words, because a bare count ("3 changes pending") tells somebody that work of theirs is unsaved without telling them which work, and the only safe response to that is to redo all of it. This is the complete vocabulary:

Label in the queueWhat it was
Started a jobPressing Start Job
Finished a jobPressing Yes, complete
Confirmed a shiftYes, I'll be there
Said you were on the wayOn my way
Recorded where you wereA location stamp at a start or a completion
Updated a jobAny other change to a job
Ticked a taskOne checklist row
A photoA job photo, with the file name beside it
A file on a messageAn attachment sent in a conversation
A messageA chat message, with its first 60 characters beside it
A reactionAn emoji on somebody else's message
Marked messages as readOpening a conversation
A supply requestAsking for stock from inside a job
A time-off requestA request from My Time
Your availabilityA change to the weekly availability switches
An equipment returnRequest Return on a loan
A change to your detailsA profile change, including the first-run acknowledgement
An email to a clientThe completion or lost property email, with the address beside it
A notificationA push to somebody else that has to go out
A changeThe fallback, which names the table rather than inventing a description

Where a cleaner checks

The Me tab opens with a row labelled Sync carrying a count badge. Its subtitle is the whole status in three words: Everything is saved, Waiting to send, Sending… or Could not be sent. Tapping it opens the queue itself.

09:41
Me
Sync Waiting to send 6
Your kit
Equipment 2 items on loan 2
Request Supplies
Blue roll ×4, Sanitiser ×2 13 Aug · For the Quay Street round Pending
Push Notifications
Enabled
Preferences
Language 🇬🇧 English
Appearance Light
Jobs History My Time Messages Me
The Sync line is the first thing on the Me tab, above the kit and everything else, and it turns red the moment anything has been refused. This is the line to point at during training.
09:41
Me Sync Offline
Waiting to send 6

Keep working. Everything below is saved on this phone and will send itself the moment you have signal.

10:41 am Started a job
10:41 am Recorded where you were
10:58 am Ticked a task
11:12 am A photo IMG_4482.jpg
11:40 am Finished a job
11:40 am An email to a client facilities@stmarks.example
Send now
The Sync screen with work waiting: the same ruled ledger as every other screen, with the time each change was written down the rail. Every line names what it is and when it was made, so a cleaner can see for themselves that the morning is on the phone and nothing has been lost.

When nothing is waiting the heading reads Everything is saved and there is one line under it: "Nothing is waiting. Every change you have made has reached the office." Offline with a queue, the heading is Waiting to send and the line is "Keep working. Everything below is saved on this phone and will send itself the moment you have signal." Above them both sits the honest connection reading: Online or Offline.

When the server refuses something

After five failed attempts an operation is set aside rather than retried forever. Those appear in their own section headed Could not be sent, in red, with the server's own reason on the line ("Rejected by the server" or "Failed repeatedly" when there is nothing more specific). Each row gets a Discard and the section gets a Try again.

09:41
Me Sync Online
Could not be sent 2

The office refused these. Try again, or discard them if they are no longer needed.

9:14 am Ticked a task Rejected by the server
9:31 am A photo IMG_4482.jpg Failed repeatedly
Try again
Waiting to send 1
11:02 am A message Left the keys with reception as agreed
2 changes could not be saved. Check and try again.
Rejected writes. The sync line carries the alert in the app's own words, and in the product that same sentence is a solid red band pinned across the very top of the whole app, above every screen, which opens this one when it is tapped. The wording is deliberate: the office refused these, so somebody has to decide. The alternative, a dismiss cross, threw away work that may have to be redone.

A rejected write is loud on purpose. It appears as a red banner across the very top of the whole app, above everything else, reading "2 changes could not be saved. Check and try again." Tapping the banner opens the Sync screen rather than dismissing it, because this is work somebody may have to redo.

What you see on your side

While a cleaner is offline, your schedule shows the job exactly as it was. There is no "cleaner is offline" indicator, and there deliberately isn't one: it would tell you nothing you can act on. What arrives when the phone reconnects is the whole sequence in order, with the real times attached.

Your own web app has a sync banner of its own, pinned to the top of the window. It is a different component from the cleaner's and is explicitly hidden on /cleaner, so the two never appear together. It has exactly four states.

3 changes could not be saved. Please check and re-enter them.
Syncing 3 changes…
Everything is saved
Offline — 3 changes queued
The four states of the banner in your web app, in the order they outrank each other. Only the first is an alert; the other three are quiet status lines, and the green one disappears by itself after three seconds.
  • Failed outranks everything and is the only one announced as an alert to a screen reader. It reads "3 changes could not be saved. Please check and re-enter them." and drops to "…could not be saved. Please check and re-enter it." for a single one. It carries a dismiss cross.
  • Syncing reads "Syncing 3 changes…" with a turning arrow.
  • Saved reads "All changes saved" and removes itself after three seconds. It is confirmation, not a notice board.
  • Offline reads "Offline" on its own, or "Offline — 3 changes queued" once anything is waiting.

The honest limits

Four controls are switched off while there is no connection, all of them because they exist to talk to the server and would otherwise just fail:

  • Pull to refresh on the Jobs list.
  • The refresh button in the header, whose label changes to "Offline — cannot refresh".
  • Send now on the Sync screen.
  • Try again on rejected writes.

And two things genuinely need a connection:

  • Changing a password. It goes through the authentication service directly and cannot be queued.
  • Loading anything the phone has never seen. A list is cached the first time it is fetched. Screens with no stored copy say so plainly: "You are offline and this device has no saved copy" followed by what to do once there is signal.

The queue is also device-local. It survives closing the app, locking the phone and signing out, which is why the sign-out confirmation says "Anything still waiting to sync stays on this device until you sign back in." It does not follow the person to another handset. In practice the only way to lose queued work is to lose the phone before it next sees a network, which is the same exposure a paper job sheet has always had.

Common questions

How long can a cleaner work offline before something breaks?
There is no time limit and no queue length limit. A cleaner can do a full day without signal and sync the lot on the way home. Photo bytes are held on the phone as well, up to 150 images, so even the evidence stays visible while it waits.
What if two cleaners change the same job while both offline?
It does not arise in practice, because a job belongs to the cleaner it is assigned to and only they see it. Where it can arise is you changing a job on your side while a cleaner is offline: their write lands when they reconnect and takes precedence on the fields it touches, which are the field report fields you were never editing anyway.
Does the cleaner have to remember to press anything to sync?
No. Send now exists for the anxious, not because it is needed. The queue drains on reconnect, on a background sync from the service worker, and on a 30-second timer.
Our site wifi has a login page at reception. Does that confuse it?
That is exactly the case the connection check was built for. A captive portal makes the phone report itself as online while nothing can actually get out. CleanFlo verifies with a real secure request to the server, which a portal cannot answer, so the app correctly treats it as offline and keeps queueing.