diff --git a/lib/facts/backup-service.js b/lib/facts/backup-service.js
new file mode 100644
--- /dev/null
+++ b/lib/facts/backup-service.js
@@ -0,0 +1,15 @@
+// @flow
+
+import { isDev } from '../utils/dev-utils.js';
+
+type BackupServiceConfig = {
+  +url: string,
+};
+
+const config: BackupServiceConfig = {
+  url: isDev
+    ? 'https://backup.staging.commtechnologies.org'
+    : 'https://backup.commtechnologies.org',
+};
+
+export default config;
diff --git a/web/database/utils/constants.js b/web/database/utils/constants.js
--- a/web/database/utils/constants.js
+++ b/web/database/utils/constants.js
@@ -16,6 +16,8 @@
 export const DEFAULT_OLM_FILENAME = 'olm.wasm';
 
 export const COMM_SQLITE_DATABASE_PATH = 'comm.sqlite';
+export const COMM_SQLITE_BACKUP_RESTORE_DATABASE_PATH =
+  'comm_backup_restore.sqlite';
 
 export const NOTIFICATIONS_OLM_DATA_CONTENT = 'notificationsOlmDataContent';
 
diff --git a/web/database/worker/backup.js b/web/database/worker/backup.js
new file mode 100644
--- /dev/null
+++ b/web/database/worker/backup.js
@@ -0,0 +1,64 @@
+// @flow
+
+import backupService from 'lib/facts/backup-service.js';
+import type { AuthMetadata } from 'lib/shared/identity-client-context.js';
+
+import { getProcessingStoreOpsExceptionMessage } from './process-operations.js';
+import {
+  BackupClient,
+  RequestedData,
+} from '../../backup-client-wasm/wasm/backup-client-wasm.js';
+import { completeRootKey } from '../../redux/persist-constants.js';
+import type { EmscriptenModule } from '../types/module.js';
+import type { SQLiteQueryExecutor } from '../types/sqlite-query-executor.js';
+import { COMM_SQLITE_BACKUP_RESTORE_DATABASE_PATH } from '../utils/constants.js';
+import { importDatabaseContent } from '../utils/db-utils.js';
+
+async function restoreBackup(
+  sqliteQueryExecutor: SQLiteQueryExecutor,
+  dbModule: EmscriptenModule,
+  authMetadata: AuthMetadata,
+  backupID: string,
+  backupDataKey: string,
+) {
+  const { userID, deviceID, accessToken } = authMetadata;
+  if (!userID || !deviceID || !accessToken) {
+    throw new Error('Backup restore requires full authMetadata');
+  }
+  const userIdentity = { userID, deviceID, accessToken };
+
+  const client = new BackupClient(backupService.url);
+  const result = await client.downloadBackupData(
+    {
+      type: 'BackupID',
+      backupID,
+      userIdentity,
+    },
+    RequestedData.UserData,
+  );
+
+  importDatabaseContent(
+    result,
+    dbModule,
+    COMM_SQLITE_BACKUP_RESTORE_DATABASE_PATH,
+  );
+
+  try {
+    const reduxPersistData =
+      sqliteQueryExecutor.getPersistStorageItem(completeRootKey);
+
+    sqliteQueryExecutor.restoreFromMainCompaction(
+      COMM_SQLITE_BACKUP_RESTORE_DATABASE_PATH,
+      backupDataKey,
+    );
+
+    sqliteQueryExecutor.setPersistStorageItem(
+      completeRootKey,
+      reduxPersistData,
+    );
+  } catch (err) {
+    throw new Error(getProcessingStoreOpsExceptionMessage(err, dbModule));
+  }
+}
+
+export { restoreBackup };
diff --git a/web/database/worker/db-worker.js b/web/database/worker/db-worker.js
--- a/web/database/worker/db-worker.js
+++ b/web/database/worker/db-worker.js
@@ -2,6 +2,7 @@
 
 import localforage from 'localforage';
 
+import { restoreBackup } from './backup.js';
 import {
   getClientStoreFromQueryExecutor,
   processDBStoreOperations,
@@ -246,6 +247,14 @@
     message.type === workerRequestMessageTypes.REMOVE_PERSIST_STORAGE_ITEM
   ) {
     sqliteQueryExecutor.removePersistStorageItem(message.key);
+  } else if (message.type === workerRequestMessageTypes.BACKUP_RESTORE) {
+    await restoreBackup(
+      sqliteQueryExecutor,
+      dbModule,
+      message.authMetadata,
+      message.backupID,
+      message.backupDataKey,
+    );
   }
 
   persistNeeded = true;
diff --git a/web/database/worker/process-operations.js b/web/database/worker/process-operations.js
--- a/web/database/worker/process-operations.js
+++ b/web/database/worker/process-operations.js
@@ -261,4 +261,8 @@
   };
 }
 
-export { processDBStoreOperations, getClientStoreFromQueryExecutor };
+export {
+  processDBStoreOperations,
+  getProcessingStoreOpsExceptionMessage,
+  getClientStoreFromQueryExecutor,
+};
diff --git a/web/redux/persist-constants.js b/web/redux/persist-constants.js
new file mode 100644
--- /dev/null
+++ b/web/redux/persist-constants.js
@@ -0,0 +1,7 @@
+// @flow
+
+const rootKey = 'root';
+const rootKeyPrefix = 'persist:';
+const completeRootKey = `${rootKeyPrefix}${rootKey}`;
+
+export { rootKey, rootKeyPrefix, completeRootKey };
diff --git a/web/redux/persist.js b/web/redux/persist.js
--- a/web/redux/persist.js
+++ b/web/redux/persist.js
@@ -31,6 +31,7 @@
 
 import commReduxStorageEngine from './comm-redux-storage-engine.js';
 import { defaultWebState } from './default-state.js';
+import { rootKey, rootKeyPrefix } from './persist-constants.js';
 import type { AppState } from './redux-setup.js';
 import { nonUserSpecificFieldsWeb } from './redux-setup.js';
 import { authoritativeKeyserverID } from '../authoritative-keyserver.js';
@@ -263,8 +264,6 @@
   },
 };
 
-const rootKey = 'root';
-
 const migrateStorageToSQLite: StorageMigrationFunction = async debug => {
   const databaseModule = await getDatabaseModule();
   const isSupported = await databaseModule.isDatabaseSupported();
@@ -297,6 +296,7 @@
 };
 
 const persistConfig: PersistConfig = {
+  keyPrefix: rootKeyPrefix,
   key: rootKey,
   storage: commReduxStorageEngine,
   whitelist: isSQLiteSupported()
diff --git a/web/types/worker-types.js b/web/types/worker-types.js
--- a/web/types/worker-types.js
+++ b/web/types/worker-types.js
@@ -1,5 +1,6 @@
 // @flow
 
+import type { AuthMetadata } from 'lib/shared/identity-client-context.js';
 import type {
   ClientDBStore,
   ClientDBStoreOperations,
@@ -18,6 +19,7 @@
   SET_PERSIST_STORAGE_ITEM: 8,
   REMOVE_PERSIST_STORAGE_ITEM: 9,
   CLEAR_SENSITIVE_DATA: 10,
+  BACKUP_RESTORE: 11,
 });
 
 export const workerWriteRequests: $ReadOnlyArray<number> = [
@@ -25,6 +27,7 @@
   workerRequestMessageTypes.SET_CURRENT_USER_ID,
   workerRequestMessageTypes.SET_PERSIST_STORAGE_ITEM,
   workerRequestMessageTypes.REMOVE_PERSIST_STORAGE_ITEM,
+  workerRequestMessageTypes.BACKUP_RESTORE,
 ];
 
 export type PingWorkerRequestMessage = {
@@ -82,6 +85,13 @@
   +type: 10,
 };
 
+export type BackupRestoreRequestMessage = {
+  +type: 11,
+  +authMetadata: AuthMetadata,
+  +backupID: string,
+  +backupDataKey: string,
+};
+
 export type WorkerRequestMessage =
   | PingWorkerRequestMessage
   | InitWorkerRequestMessage
@@ -93,7 +103,8 @@
   | GetPersistStorageItemRequestMessage
   | SetPersistStorageItemRequestMessage
   | RemovePersistStorageItemRequestMessage
-  | ClearSensitiveDataRequestMessage;
+  | ClearSensitiveDataRequestMessage
+  | BackupRestoreRequestMessage;
 
 export type WorkerRequestProxyMessage = {
   +id: number,