diff --git a/native/backup/backup-handler.js b/native/backup/backup-handler.js
new file mode 100644
--- /dev/null
+++ b/native/backup/backup-handler.js
@@ -0,0 +1,62 @@
+// @flow
+
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import * as React from 'react';
+import { useSelector } from 'react-redux';
+
+import { isLoggedIn } from 'lib/selectors/user-selectors.js';
+import { isDev } from 'lib/utils/dev-utils.js';
+import { getMessageForException } from 'lib/utils/errors.js';
+
+import { BACKUP_HASH_STORAGE_KEY } from './constants.js';
+import { convertObjToBytes } from './conversion-utils.js';
+import { useClientBackup } from './use-client-backup.js';
+import { commUtilsModule } from '../native-modules.js';
+import Alert from '../utils/alert.js';
+import { useIsCurrentUserStaff } from '../utils/staff-utils.js';
+
+function BackupHandler(): null {
+ const userStore = useSelector(state => state.userStore);
+ const currentUserID = useSelector(
+ state => state.currentUserInfo && state.currentUserInfo.id,
+ );
+ const loggedIn = useSelector(isLoggedIn);
+ const isStaff = useIsCurrentUserStaff();
+
+ const { uploadBackupProtocol } = useClientBackup();
+
+ React.useEffect(() => {
+ (async () => {
+ if (!loggedIn || !(isStaff || isDev)) {
+ return;
+ }
+
+ const userData = { userStore };
+ const userDataBytes = convertObjToBytes(userData);
+ const sha256Hash = commUtilsModule.sha256(userDataBytes.buffer);
+
+ const recentBackupHash = await AsyncStorage.getItem(
+ BACKUP_HASH_STORAGE_KEY,
+ );
+
+ if (!recentBackupHash || sha256Hash !== recentBackupHash) {
+ let message;
+ try {
+ await uploadBackupProtocol(userData);
+ message = 'Backup successfully uploaded';
+ await AsyncStorage.setItem(BACKUP_HASH_STORAGE_KEY, sha256Hash);
+ } catch (e) {
+ console.error(`Backup uploading error: ${e}`);
+ message = `Backup uploading error: ${String(
+ getMessageForException(e),
+ )}`;
+ }
+ Alert.alert('Backup protocol result', message);
+ }
+ })();
+ }, [currentUserID, isStaff, loggedIn, uploadBackupProtocol, userStore]);
+
+ return null;
+}
+
+export default BackupHandler;
diff --git a/native/backup/constants.js b/native/backup/constants.js
--- a/native/backup/constants.js
+++ b/native/backup/constants.js
@@ -1,3 +1,5 @@
// @flow
export const BACKUP_ID_LENGTH = 32; //256 bits
+
+export const BACKUP_HASH_STORAGE_KEY = 'RECENT_USER_DATA_HASH';
diff --git a/native/root.react.js b/native/root.react.js
--- a/native/root.react.js
+++ b/native/root.react.js
@@ -26,6 +26,7 @@
import { RegistrationContextProvider } from './account/registration/registration-context-provider.react.js';
import NativeEditThreadAvatarProvider from './avatars/native-edit-thread-avatar-provider.react.js';
+import BackupHandler from './backup/backup-handler.js';
import ChatContextProvider from './chat/chat-context-provider.react.js';
import MessageEditingContextProvider from './chat/message-editing-context-provider.react.js';
import { FeatureFlagsProvider } from './components/feature-flags-provider.react.js';
@@ -240,6 +241,7 @@
+
>
);
let navigation;