diff --git a/web/crypto/olm-api.js b/web/crypto/olm-api.js
--- a/web/crypto/olm-api.js
+++ b/web/crypto/olm-api.js
@@ -17,6 +17,11 @@
   shouldRotatePrekey,
 } from 'lib/utils/olm-utils.js';
 
+import { getCommSharedWorker } from '../shared-worker/shared-worker-provider.js';
+import { getOlmWasmPath } from '../shared-worker/utils/constants.js';
+import { workerRequestMessageTypes } from '../types/worker-types.js';
+
+const usingSharedWorker = false;
 // methods below are just mocks to SQLite API
 // implement proper methods tracked in ENG-6462
 
@@ -36,7 +41,15 @@
 
 const olmAPI: OlmAPI = {
   async initializeCryptoAccount(): Promise<void> {
-    await olm.init();
+    if (usingSharedWorker) {
+      const sharedWorker = await getCommSharedWorker();
+      await sharedWorker.schedule({
+        type: workerRequestMessageTypes.INITIALIZE_CRYPTO_ACCOUNT,
+        olmWasmPath: getOlmWasmPath(),
+      });
+    } else {
+      await olm.init();
+    }
   },
   async encrypt(content: string, deviceID: string): Promise<string> {
     const session = getOlmSession(deviceID);
diff --git a/web/push-notif/push-notifs-handler.js b/web/push-notif/push-notifs-handler.js
--- a/web/push-notif/push-notifs-handler.js
+++ b/web/push-notif/push-notifs-handler.js
@@ -22,15 +22,9 @@
 import PushNotifModal from '../modals/push-notif-modal.react.js';
 import { updateNavInfoActionType } from '../redux/action-types.js';
 import { useSelector } from '../redux/redux-utils.js';
-import {
-  WORKERS_MODULES_DIR_PATH,
-  DEFAULT_OLM_FILENAME,
-} from '../shared-worker/utils/constants.js';
+import { getOlmWasmPath } from '../shared-worker/utils/constants.js';
 import { useStaffCanSee } from '../utils/staff-utils.js';
 
-declare var baseURL: string;
-declare var olmFilename: string;
-
 function useCreateDesktopPushSubscription() {
   const dispatchActionPromise = useDispatchActionPromise();
   const callSetDeviceToken = useSetDeviceTokenFanout();
@@ -106,11 +100,10 @@
       return;
     }
 
-    const origin = window.location.origin;
-    const olmWasmDirPath = `${origin}${baseURL}${WORKERS_MODULES_DIR_PATH}`;
-    const olmWasmFilename = olmFilename ? olmFilename : DEFAULT_OLM_FILENAME;
-    const olmWasmPath = `${olmWasmDirPath}/${olmWasmFilename}`;
-    workerRegistration.active?.postMessage({ olmWasmPath, staffCanSee });
+    workerRegistration.active?.postMessage({
+      olmWasmPath: getOlmWasmPath(),
+      staffCanSee,
+    });
 
     const subscription = await workerRegistration.pushManager.subscribe({
       userVisibleOnly: true,
diff --git a/web/shared-worker/utils/constants.js b/web/shared-worker/utils/constants.js
--- a/web/shared-worker/utils/constants.js
+++ b/web/shared-worker/utils/constants.js
@@ -46,3 +46,12 @@
   description: 'Comm encrypted database storage',
   version: '1.0',
 };
+
+declare var baseURL: string;
+declare var olmFilename: string;
+export function getOlmWasmPath(): string {
+  const origin = window.location.origin;
+  const olmWasmDirPath = `${origin}${baseURL}${WORKERS_MODULES_DIR_PATH}`;
+  const olmWasmFilename = olmFilename ? olmFilename : DEFAULT_OLM_FILENAME;
+  return `${olmWasmDirPath}/${olmWasmFilename}`;
+}
diff --git a/web/shared-worker/worker/shared-worker.js b/web/shared-worker/worker/shared-worker.js
--- a/web/shared-worker/worker/shared-worker.js
+++ b/web/shared-worker/worker/shared-worker.js
@@ -7,6 +7,7 @@
   getClientStoreFromQueryExecutor,
   processDBStoreOperations,
 } from './process-operations.js';
+import { clearCryptoStore, processAppOlmApiRequest } from './worker-crypto.js';
 import {
   getDBModule,
   getSQLiteQueryExecutor,
@@ -29,6 +30,7 @@
   workerResponseMessageTypes,
   type WorkerRequestProxyMessage,
   workerWriteRequests,
+  workerOlmAPIRequests,
 } from '../../types/worker-types.js';
 import { getDatabaseModule } from '../db-module.js';
 import {
@@ -189,6 +191,7 @@
     await Promise.all(promises);
     return undefined;
   } else if (message.type === workerRequestMessageTypes.CLEAR_SENSITIVE_DATA) {
+    clearCryptoStore();
     encryptionKey = null;
     await localforage.clear();
     if (dbModule && sqliteQueryExecutor) {
@@ -229,8 +232,9 @@
   }
 
   // write operations
-  if (!workerWriteRequests.includes(message.type)) {
-    throw new Error('Request type not supported');
+  const isOlmAPIRequest = workerOlmAPIRequests.includes(message.type);
+  if (!workerWriteRequests.includes(message.type) && !isOlmAPIRequest) {
+    throw new Error(`Request type ${message.type} not supported`);
   }
   if (!sqliteQueryExecutor || !dbModule) {
     throw new Error(
@@ -238,7 +242,11 @@
     );
   }
 
-  if (message.type === workerRequestMessageTypes.PROCESS_STORE_OPERATIONS) {
+  if (isOlmAPIRequest) {
+    await processAppOlmApiRequest(message);
+  } else if (
+    message.type === workerRequestMessageTypes.PROCESS_STORE_OPERATIONS
+  ) {
     processDBStoreOperations(
       sqliteQueryExecutor,
       message.storeOperations,
diff --git a/web/shared-worker/worker/worker-crypto.js b/web/shared-worker/worker/worker-crypto.js
new file mode 100644
--- /dev/null
+++ b/web/shared-worker/worker/worker-crypto.js
@@ -0,0 +1,169 @@
+// @flow
+
+import olm from '@commapp/olm';
+import uuid from 'uuid';
+
+import type { CryptoStore, PickledOLMAccount } from 'lib/types/crypto-types.js';
+
+import { getProcessingStoreOpsExceptionMessage } from './process-operations.js';
+import { getDBModule, getSQLiteQueryExecutor } from './worker-database.js';
+import {
+  type WorkerRequestMessage,
+  type WorkerResponseMessage,
+  workerRequestMessageTypes,
+} from '../../types/worker-types.js';
+
+type WorkerCryptoStore = {
+  +contentAccountPickleKey: string,
+  +contentAccount: olm.Account,
+  +notificationAccountPickleKey: string,
+  +notificationAccount: olm.Account,
+};
+
+let cryptoStore: ?WorkerCryptoStore = null;
+
+function clearCryptoStore() {
+  cryptoStore = null;
+}
+
+function persistCryptoStore() {
+  const sqliteQueryExecutor = getSQLiteQueryExecutor();
+  const dbModule = getDBModule();
+  if (!sqliteQueryExecutor || !dbModule) {
+    throw new Error(
+      "Couldn't persist crypto store because database is not initialized",
+    );
+  }
+  if (!cryptoStore) {
+    throw new Error("Couldn't persist crypto store because it doesn't exist");
+  }
+
+  const {
+    contentAccountPickleKey,
+    contentAccount,
+    notificationAccountPickleKey,
+    notificationAccount,
+  } = cryptoStore;
+
+  const pickledContentAccount: PickledOLMAccount = {
+    picklingKey: contentAccountPickleKey,
+    pickledAccount: contentAccount.pickle(contentAccountPickleKey),
+  };
+
+  const pickledNotificationAccount: PickledOLMAccount = {
+    picklingKey: notificationAccountPickleKey,
+    pickledAccount: notificationAccount.pickle(notificationAccountPickleKey),
+  };
+
+  try {
+    sqliteQueryExecutor.storeOlmPersistAccount(
+      sqliteQueryExecutor.getContentAccountID(),
+      JSON.stringify(pickledContentAccount),
+    );
+    sqliteQueryExecutor.storeOlmPersistAccount(
+      sqliteQueryExecutor.getNotifsAccountID(),
+      JSON.stringify(pickledNotificationAccount),
+    );
+  } catch (err) {
+    throw new Error(getProcessingStoreOpsExceptionMessage(err, dbModule));
+  }
+}
+
+function getOrCreateOlmAccount(accountIDInDB: number): {
+  +picklingKey: string,
+  +account: olm.Account,
+} {
+  const sqliteQueryExecutor = getSQLiteQueryExecutor();
+  const dbModule = getDBModule();
+  if (!sqliteQueryExecutor || !dbModule) {
+    throw new Error('Database not initialized');
+  }
+
+  const account = new olm.Account();
+  let picklingKey;
+
+  let accountDBString;
+  try {
+    accountDBString =
+      sqliteQueryExecutor.getOlmPersistAccountDataWeb(accountIDInDB);
+  } catch (err) {
+    throw new Error(getProcessingStoreOpsExceptionMessage(err, dbModule));
+  }
+
+  if (accountDBString.isNull) {
+    picklingKey = uuid.v4();
+    account.create();
+  } else {
+    const dbAccount: PickledOLMAccount = JSON.parse(accountDBString.value);
+    picklingKey = dbAccount.picklingKey;
+    account.unpickle(picklingKey, dbAccount.pickledAccount);
+  }
+
+  return { picklingKey, account };
+}
+
+function unpickleInitialCryptoStoreAccount(
+  account: PickledOLMAccount,
+): olm.Account {
+  const { picklingKey, pickledAccount } = account;
+  const olmAccount = new olm.Account();
+  olmAccount.unpickle(picklingKey, pickledAccount);
+  return olmAccount;
+}
+
+async function initializeCryptoAccount(
+  olmWasmPath: string,
+  initialCryptoStore: ?CryptoStore,
+) {
+  const sqliteQueryExecutor = getSQLiteQueryExecutor();
+  if (!sqliteQueryExecutor) {
+    throw new Error('Database not initialized');
+  }
+
+  await olm.init({ locateFile: () => olmWasmPath });
+
+  if (initialCryptoStore) {
+    cryptoStore = {
+      contentAccountPickleKey: initialCryptoStore.primaryAccount.picklingKey,
+      contentAccount: unpickleInitialCryptoStoreAccount(
+        initialCryptoStore.primaryAccount,
+      ),
+      notificationAccountPickleKey:
+        initialCryptoStore.notificationAccount.picklingKey,
+      notificationAccount: unpickleInitialCryptoStoreAccount(
+        initialCryptoStore.notificationAccount,
+      ),
+    };
+    persistCryptoStore();
+    return;
+  }
+
+  const contentAccountResult = getOrCreateOlmAccount(
+    sqliteQueryExecutor.getContentAccountID(),
+  );
+  const notificationAccountResult = getOrCreateOlmAccount(
+    sqliteQueryExecutor.getNotifsAccountID(),
+  );
+
+  cryptoStore = {
+    contentAccountPickleKey: contentAccountResult.picklingKey,
+    contentAccount: contentAccountResult.account,
+    notificationAccountPickleKey: notificationAccountResult.picklingKey,
+    notificationAccount: notificationAccountResult.account,
+  };
+
+  persistCryptoStore();
+}
+
+async function processAppOlmApiRequest(
+  message: WorkerRequestMessage,
+): Promise<?WorkerResponseMessage> {
+  if (message.type === workerRequestMessageTypes.INITIALIZE_CRYPTO_ACCOUNT) {
+    await initializeCryptoAccount(
+      message.olmWasmPath,
+      message.initialCryptoStore,
+    );
+  }
+}
+
+export { clearCryptoStore, processAppOlmApiRequest };
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,6 +1,7 @@
 // @flow
 
 import type { AuthMetadata } from 'lib/shared/identity-client-context.js';
+import type { CryptoStore } from 'lib/types/crypto-types.js';
 import type {
   ClientDBStore,
   ClientDBStoreOperations,
@@ -20,6 +21,7 @@
   REMOVE_PERSIST_STORAGE_ITEM: 9,
   CLEAR_SENSITIVE_DATA: 10,
   BACKUP_RESTORE: 11,
+  INITIALIZE_CRYPTO_ACCOUNT: 12,
 });
 
 export const workerWriteRequests: $ReadOnlyArray<number> = [
@@ -28,6 +30,11 @@
   workerRequestMessageTypes.SET_PERSIST_STORAGE_ITEM,
   workerRequestMessageTypes.REMOVE_PERSIST_STORAGE_ITEM,
   workerRequestMessageTypes.BACKUP_RESTORE,
+  workerRequestMessageTypes.INITIALIZE_CRYPTO_ACCOUNT,
+];
+
+export const workerOlmAPIRequests: $ReadOnlyArray<number> = [
+  workerRequestMessageTypes.INITIALIZE_CRYPTO_ACCOUNT,
 ];
 
 export type PingWorkerRequestMessage = {
@@ -93,6 +100,12 @@
   +backupLogDataKey: string,
 };
 
+export type InitializeCryptoAccountRequestMessage = {
+  +type: 12,
+  +olmWasmPath: string,
+  +initialCryptoStore?: CryptoStore,
+};
+
 export type WorkerRequestMessage =
   | PingWorkerRequestMessage
   | InitWorkerRequestMessage
@@ -105,7 +118,8 @@
   | SetPersistStorageItemRequestMessage
   | RemovePersistStorageItemRequestMessage
   | ClearSensitiveDataRequestMessage
-  | BackupRestoreRequestMessage;
+  | BackupRestoreRequestMessage
+  | InitializeCryptoAccountRequestMessage;
 
 export type WorkerRequestProxyMessage = {
   +id: number,