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.
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.
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.
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.
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 queue | What it was |
|---|---|
| Started a job | Pressing Start Job |
| Finished a job | Pressing Yes, complete |
| Confirmed a shift | Yes, I'll be there |
| Said you were on the way | On my way |
| Recorded where you were | A location stamp at a start or a completion |
| Updated a job | Any other change to a job |
| Ticked a task | One checklist row |
| A photo | A job photo, with the file name beside it |
| A file on a message | An attachment sent in a conversation |
| A message | A chat message, with its first 60 characters beside it |
| A reaction | An emoji on somebody else's message |
| Marked messages as read | Opening a conversation |
| A supply request | Asking for stock from inside a job |
| A time-off request | A request from My Time |
| Your availability | A change to the weekly availability switches |
| An equipment return | Request Return on a loan |
| A change to your details | A profile change, including the first-run acknowledgement |
| An email to a client | The completion or lost property email, with the address beside it |
| A notification | A push to somebody else that has to go out |
| A change | The 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.
Keep working. Everything below is saved on this phone and will send itself the moment you have signal.
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.
The office refused these. Try again, or discard them if they are no longer needed.
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.
- 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?
What if two cleaners change the same job while both offline?
Does the cleaner have to remember to press anything to sync?
Our site wifi has a login page at reception. Does that confuse it?
Still stuck?
Open Support in the app and send us a ticket, or email the team. A real person reads every one.