I am working on setting up an offline app where users may be without an internet connection for several weeks at a time. The Appfarm documentation states: “With an offline App, all data in App Variables and Data Sources are cached on the device.”
Where and how is this data cached on the device?
Is there a way to ensure that scheduled CRUD operations are not lost if the local cache/storage is cleared or recycled before the device reconnects and the operations are synchronized?
The documentation states that “Use the On Online Event Handler … Then the Action should read all data from the database.”
The app that we are building may be used in areas with low bandwidth and unstable connection. If the user is frequently connected and disconnected this could cause the app to reload all data frequently.
I believe this could partially be solved by using an updated date filter, to only load the objects that have been changed since last time the user was online. However, even a slimer data load may cause issues if the “On online” event handler is triggered frequently enough. Is there some kind of limit to how often the “On online” event handler may trigger?
Offline data (App Variables and Data Source content) is stored in the browser’s local storage. Specifically IndexedDB, with some data also using localStorage. This is standard browser storage tied to the specific device/browser the app runs on.
There are really only two situations where locally stored data (and any pending CRUD operations) would be lost before it gets a chance to sync:
The user manually clears the browser’s site data, or uninstalls the app along with its data.
The device runs low on storage space. This mainly becomes relevant if the app is caching very large amounts of data (multiple gigabytes), in which case some browsers may decide to reclaim that storage.
Outside of those two cases, data isn’t lost even if sync happens weeks later. There’s no time limit on the sync process itself.
For the second scenario, you can reduce the risk by having the app call navigator.storage.persist(), for example as part of an init action when the app starts. This prompts the user for permission, and if granted, tells the browser not to automatically clear that site’s storage under storage pressure. It won’t protect against a user actively clearing their own data, but it removes the “device ran out of space” risk.
Here is an example on how to set up the init action:
You have an app variable called e.g. “Has Initialized”.
Data type: Boolean, Persistence: Local Storage
Here is a picture of how the Init action can look, where the Run Code is:
On to your second question:
An option is to give the user manual control over when the app goes offline and online. When the user chooses to go offline by pressing a button, it can set a flag in the app that says “I am intentionally working offline”. When the user is ready to synchronize, they press another button to go back online and additionally check if the built-in app variable “Is Online” is true. Only at that point does the app read updated data from the database and persist data that has been updated while offline.
Your suggestion about using a “last online” timestamp as a filter is a good optimization on top of this pattern. The app stores a timestamp for when the user last went online, so that when synchronization does happen, only objects that have changed since that point need to be fetched rather than reloading everything.
Thanks for the reply. This is very useful information.
I have one more follow up question. Giving the user manual control over when to go online and not is a possible solution, but we would like to avoid it if possible. Do you know if there is a rough soft limit to how often “On Online” event handler may triggered?
I see! There’s no hard limit on how often the “On Online” event handler can trigger.
One thing worth keeping in mind, though: “Is Online” (and related handlers) reflects the connection and sync status with the server, so it’s not instantaneous the moment a device physically disconnects or reconnects. There can be a short delay before the state updates to match the actual connection.