How to Work Offline with PowerApps
In this post I will show you step by step how to work offline with PowerApps. To make your app work offline there are essentially three processes you must solve for. Saving data to device when online for offline use. Saving data to device when working offline and sync data up when your back online. In the following steps I will use actual samples of an app I created with offline capabilities, so excuse the length. For your app you just substitute with your data. Continue reading and you too will become an Office Power User!

Preparing AppData on Start Up
First thing you need to decide is which parts of your app will function offline and which will function only online. Once you have decided you load all your offline content into collections and then save them on your device.
- App On Start
- OnStart:
Set(
varUser,
varOfficeUser.Email
);
Set(
varClientID,
72
); //We check if we are connected and if so we collect the data we need for the app into collections
If(
Connection.Connected,
Concurrent(
ClearCollect(
colUserPref,
Filter(
‘[dbo].[tblWPO_preferences]’,
TheUser = varUser
)
),
ClearCollect(
colOUs,
Filter(
‘[dbo].[tblQltyOUs]’,
ClientID = varClientID
)
),
ClearCollect(
colLocations,
Filter(
‘[dbo].[tblQltyLocations]’,
ClientID = varClientID
)
),
ClearCollect(
colTeams,
‘[dbo].[tblWPO_Teams]’
),
ClearCollect(
colTeamsDepartments,
‘[dbo].[tblWPO_TeamDepartments]’
),
ClearCollect(
colSafetyAreas,
‘[dbo].[tblWPO_SafetyAreas]’
),
ClearCollect(
colWPOItems,
‘[dbo].[tblWPO_Items]’
),
ClearCollect(
colTranslations,
Filter(
‘[dbo].[tblWPOTranslations]’,
ClientID = varClientID
)
)
); // Below I have a table that may have more than 2K records.
If(
CountRows(colTranslations) = 2000,
Set(
varIDForNextTransRun,
Max(
colTranslations,
ID
)
);
Collect(
colTranslations,
Filter(
‘[dbo].[tblWPOTranslations]’,
ClientID = varClientID && ID > varIDForNextTransRun
)
)
);
If(
CountRows(colTranslations) = 4000,
Set(
varIDForNextTransRun,
Max(
colTranslations,
ID
)
);
Collect(
colTranslations,
Filter(
‘[dbo].[tblWPOTranslations]’,
ClientID = varClientID && ID > varIDForNextTransRun
)
)
); // Now that we have the data in collections we save them to device for offline use.
SaveData(
colOUs,
“LocalcolOUs”
);
SaveData(
colLocations,
“LocalcolLocations”
);
SaveData(
colTeams,
“LocalcolTeams”
);
SaveData(
colTeamsDepartments,
“LocalcolTeamsDepartments”
);
SaveData(
colSafetyAreas,
“LocalcolSafetyAreas”
);
SaveData(
colWPOItems,
“LocalcolWPOItems”
);
SaveData(
colTranslations,
“LocalcolTranslations”
);
SaveData(
colUserPref,
“LocalcolUserPref”
);// Here we will load data from device that has not been uploaded yet from previous offline use and upload while online.
LoadData(
coltblWPO_Header,
“LocalcoltblWPO_Header”,
true
);
LoadData(
coltblWPO_Details,
“LocalcoltblWPO_Details”,
true
);
Set(
varUserPicture,
Office365Users.UserPhoto(varUser)
);
If(
CountRows(coltblWPO_Header) > 0,
ForAll(
coltblWPO_Header,
With(
Patch(
‘[dbo].[tblWPO_Header]’,
Defaults(‘[dbo].[tblWPO_Header]’),
{
CheckDT: CheckDT,
CompletedBY: CompletedBY,
HeaderID: HeaderTempID,
LocationID: LocationID,
Note: Note,
OUid: OUid,
TeamID: TeamID
}
),
ForAll(
Filter(
coltblWPO_Details,
Text(TempHeaderID) = Text(HeaderTempID)
),
Patch(
‘[dbo].[tblWPO_Details]’,
Defaults(‘[dbo].[tblWPO_Details]’),
{
HeaderID: ID,
CheckDT: CheckDT,
ItemID: ItemID,
Status: Status
}
)
)
)
); // Now that the data has been captured we clear the collections and write the empty collection back to the device.
Clear(coltblWPO_Header);
Clear(coltblWPO_Details);
SaveData(
coltblWPO_Header,
“LocalcoltblWPO_Header”
);
SaveData(
coltblWPO_Details,
“LocalcoltblWPO_Details”
),
“”
), // If we are not online then we load app data into collections from device.
Set(
varUserPicture,
GreyTeamDepartment
);
LoadData(
colOUs,
“LocalcolOUs”,
true
);
LoadData(
colLocations,
“LocalcolLocations”,
true
);
LoadData(
colTeams,
“LocalcolTeams”,
true
);
LoadData(
colTeamsDepartments,
“LocalcolTeamsDepartments”,
true
);
LoadData(
colSafetyAreas,
“LocalcolSafetyAreas”,
true
);
LoadData(
colWPOItems,
“LocalcolWPOItems”,
true
);
LoadData(
colTranslations,
“LocalcolTranslations”,
true
);
LoadData(
colUserPref,
“LocalcolUserPref”,
true
);
LoadData(
coltblWPO_Header,
“LocalcoltblWPO_Header”,
true
);
LoadData(
coltblWPO_Details,
“LocalcoltblWPO_Details”,
true
);
)
- OnStart:
Saving Data During Run Time
When saving data in your app you must look for the online status and update collections and offline data appropriately. We are almost there. Soon you will know to work offline with PowerApps!
- Save Record
- OnSelect:
UpdateContext({varShowSpinner: true}); // See link below to learn how to create a spinner component.
UpdateContext({varHeaderID: Text(GUID())});
Collect( // We collect the header informtion.
coltblWPO_Header,
{
CheckDT: Today(),
Note: txtNote.Text,
CompletedBY: varUser,
OUid: varOU,
LocationID: varLocation,
TeamID: varTeam,
HeaderTempID: varHeaderID
}
);
Reset(txtNote);
Clear(colDetails); // We load the data from the gallery “colCheckList” collection into this temp “colDetails” collection.
ForAll(
colCheckList,
Collect(
colDetails,
{
HeaderID: 0,
ItemID: ID,
Status: CheckStat,
CheckDT: Today()
}
)
);
Collect(
coltblWPO_Details,
AddColumns(
colDetails,
“TempHeaderID”,
varHeaderID
)
);
If(
Connection.Connected, //
ForAll(
coltblWPO_Header,
With(
Patch(
‘[dbo].[tblWPO_Header]’,
Defaults(‘[dbo].[tblWPO_Header]’),
{
CheckDT: CheckDT,
CompletedBY: CompletedBY,
HeaderID: HeaderTempID,
LocationID: LocationID,
Note: Note,
OUid: OUid,
TeamID: TeamID
}
),
ForAll(
Filter(
coltblWPO_Details,
Text(TempHeaderID) = Text(HeaderTempID)
),
Patch(
‘[dbo].[tblWPO_Details]’,
Defaults(‘[dbo].[tblWPO_Details]’),
{
HeaderID: ID,
CheckDT: CheckDT,
ItemID: ItemID,
Status: Status
}
)
)
)
);
Clear(coltblWPO_Header);
Clear(coltblWPO_Details);
SaveData( // Save empty collection back to device.
coltblWPO_Header,
“LocalcoltblWPO_Header”
);
SaveData(
coltblWPO_Details,
“LocalcoltblWPO_Details”
), // If we are not online then we save collection with data to device for later uploading.
SaveData(
coltblWPO_Header,
“LocalcoltblWPO_Header”
);
SaveData(
coltblWPO_Details,
“LocalcoltblWPO_Details”
)
);
UpdateContext({varShowSpinner: false})
- OnSelect:
Managing Unsaved Data During Run Time
Lastly we will use a timer control to check if device is online and if there are unsaved records and when true you save unsaved data back to data source, clear your collections and write updated data back to collections and save to device again for when you are offline.
- Save unsaved data when back online.
- OnTimerEnd:
If(
CountRows(coltblWPO_Header) > 0, // Check if records need saving.
If(
Connection.Connected, // If online then save the records.
UpdateContext({varShowSpinner: true});
ForAll(
coltblWPO_Header,
With(
Patch(
‘[dbo].[tblWPO_Header]’,
Defaults(‘[dbo].[tblWPO_Header]’),
{
CheckDT: CheckDT,
CompletedBY: CompletedBY,
HeaderID: HeaderTempID,
LocationID: LocationID,
Note: Note,
OUid: OUid,
TeamID: TeamID
}
),
ForAll(
Filter(
coltblWPO_Details,
Text(TempHeaderID) = Text(HeaderTempID)
),
Patch(
‘[dbo].[tblWPO_Details]’,
Defaults(‘[dbo].[tblWPO_Details]’),
{
HeaderID: ID,
CheckDT: CheckDT,
ItemID: ItemID,
Status: Status
}
)
)
)
);
Clear(coltblWPO_Header);
Clear(coltblWPO_Details);
SaveData( // Save empty collections to device.
coltblWPO_Header,
“LocalcoltblWPO_Header”
);
SaveData(
coltblWPO_Details,
“LocalcoltblWPO_Details”
);
Set(
varSyncWarning,
false
);
UpdateContext({varShowSpinner: false});
,
“”
)
)
- OnTimerEnd:
Now you know how to work offline with PowerApps! Please leave your feedback. I hope this article has been helpful for you so bookmark this blog as new articles are posted regularly.
Additional Resources
Do It For Me
how-to-create-a-spinner-component-in-powerapps
how-to-create-a-popup-confirmation-in-powerapps