diff --git a/lib/types/crypto-types.js b/lib/types/crypto-types.js
--- a/lib/types/crypto-types.js
+++ b/lib/types/crypto-types.js
@@ -151,6 +151,10 @@
     deviceID: string,
     messageID: string,
   ) => Promise<EncryptedData>,
+  +encryptNotification: (
+    payload: string,
+    deviceID: string,
+  ) => Promise<EncryptedData>,
   +decrypt: (encryptedData: EncryptedData, deviceID: string) => Promise<string>,
   +decryptAndPersist: (
     encryptedData: EncryptedData,
diff --git a/lib/utils/__mocks__/config.js b/lib/utils/__mocks__/config.js
--- a/lib/utils/__mocks__/config.js
+++ b/lib/utils/__mocks__/config.js
@@ -17,6 +17,7 @@
     getUserPublicKey: jest.fn(),
     encrypt: jest.fn(),
     encryptAndPersist: jest.fn(),
+    encryptNotification: jest.fn(),
     decrypt: jest.fn(),
     decryptAndPersist: jest.fn(),
     contentInboundSessionCreator: jest.fn(),
diff --git a/native/crypto/olm-api.js b/native/crypto/olm-api.js
--- a/native/crypto/olm-api.js
+++ b/native/crypto/olm-api.js
@@ -21,6 +21,7 @@
   getUserPublicKey: commCoreModule.getUserPublicKey,
   encrypt: commCoreModule.encrypt,
   encryptAndPersist: commCoreModule.encryptAndPersist,
+  encryptNotification: commCoreModule.encryptNotification,
   decrypt: commCoreModule.decrypt,
   decryptAndPersist: commCoreModule.decryptAndPersist,
   async contentInboundSessionCreator(
diff --git a/native/push/encrypted-notif-utils-api.js b/native/push/encrypted-notif-utils-api.js
--- a/native/push/encrypted-notif-utils-api.js
+++ b/native/push/encrypted-notif-utils-api.js
@@ -1,8 +1,9 @@
 // @flow
 
 import type { EncryptedNotifUtilsAPI } from 'lib/types/notif-types.js';
+import { getConfig } from 'lib/utils/config.js';
 
-import { commUtilsModule, commCoreModule } from '../native-modules.js';
+import { commUtilsModule } from '../native-modules.js';
 
 const encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI = {
   encryptSerializedNotifPayload: async (
@@ -13,8 +14,12 @@
       type: '1' | '0',
     ) => boolean,
   ) => {
-    const { message: body, messageType: type } =
-      await commCoreModule.encryptNotification(unencryptedPayload, cryptoID);
+    const { initializeCryptoAccount, encryptNotification } = getConfig().olmAPI;
+    await initializeCryptoAccount();
+    const { message: body, messageType: type } = await encryptNotification(
+      unencryptedPayload,
+      cryptoID,
+    );
     return {
       encryptedData: { body, type },
       sizeLimitViolated: encryptedPayloadSizeValidator
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
@@ -46,6 +46,7 @@
   getUserPublicKey: proxyToWorker('getUserPublicKey'),
   encrypt: proxyToWorker('encrypt'),
   encryptAndPersist: proxyToWorker('encryptAndPersist'),
+  encryptNotification: proxyToWorker('encryptNotification'),
   decrypt: proxyToWorker('decrypt'),
   decryptAndPersist: proxyToWorker('decryptAndPersist'),
   contentInboundSessionCreator: proxyToWorker('contentInboundSessionCreator'),
diff --git a/web/push-notif/encrypted-notif-utils-api.js b/web/push-notif/encrypted-notif-utils-api.js
--- a/web/push-notif/encrypted-notif-utils-api.js
+++ b/web/push-notif/encrypted-notif-utils-api.js
@@ -1,6 +1,7 @@
 // @flow
 
 import type { EncryptedNotifUtilsAPI } from 'lib/types/notif-types.js';
+import { getConfig } from 'lib/utils/config.js';
 
 const encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI = {
   encryptSerializedNotifPayload: async (
@@ -11,16 +12,16 @@
       type: '1' | '0',
     ) => boolean,
   ) => {
-    // The "mock" implementation below will be replaced with proper
-    // implementation after olm notif sessions initialization is
-    // implemented. for now it is actually beneficial to return
-    // original string as encrypted string since it allows for
-    // better testing as we can verify which data are encrypted
-    // and which aren't.
+    const { initializeCryptoAccount, encryptNotification } = getConfig().olmAPI;
+    await initializeCryptoAccount();
+    const { message: body, messageType: type } = await encryptNotification(
+      unencryptedPayload,
+      cryptoID,
+    );
     return {
-      encryptedData: { body: unencryptedPayload, type: 1 },
+      encryptedData: { body, type },
       sizeLimitViolated: encryptedPayloadSizeValidator
-        ? !encryptedPayloadSizeValidator(unencryptedPayload, '1')
+        ? !encryptedPayloadSizeValidator(body, type ? '1' : '0')
         : false,
     };
   },
diff --git a/web/push-notif/notif-crypto-utils.js b/web/push-notif/notif-crypto-utils.js
--- a/web/push-notif/notif-crypto-utils.js
+++ b/web/push-notif/notif-crypto-utils.js
@@ -1,6 +1,7 @@
 // @flow
 
 import olm from '@commapp/olm';
+import type { EncryptResult } from '@commapp/olm';
 import invariant from 'invariant';
 import localforage from 'localforage';
 
@@ -13,6 +14,7 @@
   EncryptedWebNotification,
 } from 'lib/types/notif-types.js';
 import { getCookieIDFromCookie } from 'lib/utils/cookie-utils.js';
+import { getMessageForException } from 'lib/utils/errors.js';
 
 import {
   type EncryptedData,
@@ -86,9 +88,9 @@
       displayErrorMessage: staffCanSee,
     };
   }
-  const { olmDataContentKey, encryptionKeyDBKey } = olmDBKeys;
+  const { olmDataKey, encryptionKeyDBKey } = olmDBKeys;
   const [encryptedOlmData, encryptionKey] = await Promise.all([
-    localforage.getItem<EncryptedData>(olmDataContentKey),
+    localforage.getItem<EncryptedData>(olmDataKey),
     retrieveEncryptionKey(encryptionKeyDBKey),
   ]);
 
@@ -105,7 +107,7 @@
 
     const decryptedNotification = await commonDecrypt<PlainTextWebNotification>(
       encryptedOlmData,
-      olmDataContentKey,
+      olmDataKey,
       encryptionKey,
       encryptedPayload,
     );
@@ -132,15 +134,15 @@
   staffCanSee: boolean,
   keyserverID?: string,
 ): Promise<{ +[string]: mixed }> {
-  let encryptedOlmData, encryptionKey, olmDataContentKey;
+  let encryptedOlmData, encryptionKey, olmDataKey;
   try {
-    const { olmDataContentKey: olmDataContentKeyValue, encryptionKeyDBKey } =
+    const { olmDataKey: olmDataKeyValue, encryptionKeyDBKey } =
       await getNotifsOlmSessionDBKeys(keyserverID);
 
-    olmDataContentKey = olmDataContentKeyValue;
+    olmDataKey = olmDataKeyValue;
 
     [encryptedOlmData, encryptionKey] = await Promise.all([
-      localforage.getItem<EncryptedData>(olmDataContentKey),
+      localforage.getItem<EncryptedData>(olmDataKey),
       retrieveEncryptionKey(encryptionKeyDBKey),
       initOlm(),
     ]);
@@ -162,7 +164,7 @@
   try {
     decryptedNotification = await commonDecrypt<{ +[string]: mixed }>(
       encryptedOlmData,
-      olmDataContentKey,
+      olmDataKey,
       encryptionKey,
       encryptedPayload,
     );
@@ -197,7 +199,7 @@
 
 async function commonDecrypt<T>(
   encryptedOlmData: EncryptedData,
-  olmDataContentKey: string,
+  olmDataKey: string,
   encryptionKey: CryptoKey,
   encryptedPayload: string,
 ): Promise<T> {
@@ -257,7 +259,7 @@
     encryptionKey,
   );
 
-  await localforage.setItem(olmDataContentKey, updatedEncryptedSession);
+  await localforage.setItem(olmDataKey, updatedEncryptedSession);
 
   return decryptedNotification;
 }
@@ -309,6 +311,87 @@
   }
 }
 
+async function encryptNotification(
+  payload: string,
+  deviceID: string,
+): Promise<EncryptResult> {
+  const olmDataKey = getOlmDataKeyForDeviceID(deviceID);
+  const olmEncryptionKeyDBLabel =
+    getOlmEncryptionKeyDBLabelForDeviceID(deviceID);
+
+  let encryptedOlmData, encryptionKey;
+  try {
+    [encryptedOlmData, encryptionKey] = await Promise.all([
+      localforage.getItem<EncryptedData>(olmDataKey),
+      retrieveEncryptionKey(olmEncryptionKeyDBLabel),
+      initOlm(),
+    ]);
+  } catch (e) {
+    throw new Error(
+      `Failed to fetch olm session from IndexedDB for device: ${deviceID}. Details: ${
+        getMessageForException(e) ?? ''
+      }`,
+    );
+  }
+
+  if (!encryptionKey || !encryptedOlmData) {
+    throw new Error(`Session with device: ${deviceID} not initialized.`);
+  }
+
+  let encryptedNotification;
+  try {
+    encryptedNotification = await encryptNotificationWithOlmSession(
+      payload,
+      encryptedOlmData,
+      olmDataKey,
+      encryptionKey,
+    );
+  } catch (e) {
+    throw new Error(
+      `Failed encrypt notification for device: ${deviceID}. Details: ${
+        getMessageForException(e) ?? ''
+      }`,
+    );
+  }
+  return encryptedNotification;
+}
+
+async function encryptNotificationWithOlmSession(
+  payload: string,
+  encryptedOlmData: EncryptedData,
+  olmDataKey: string,
+  encryptionKey: CryptoKey,
+): Promise<EncryptResult> {
+  const serializedOlmData = await decryptData(encryptedOlmData, encryptionKey);
+  const {
+    mainSession,
+    picklingKey,
+    pendingSessionUpdate,
+    updateCreationTimestamp,
+  }: NotificationsOlmDataType = JSON.parse(
+    new TextDecoder().decode(serializedOlmData),
+  );
+
+  const session = new olm.Session();
+  session.unpickle(picklingKey, pendingSessionUpdate);
+  const encryptedNotification = session.encrypt(payload);
+
+  const newPendingSessionUpdate = session.pickle(picklingKey);
+  const updatedOlmData: NotificationsOlmDataType = {
+    mainSession,
+    pendingSessionUpdate: newPendingSessionUpdate,
+    picklingKey,
+    updateCreationTimestamp,
+  };
+  const updatedEncryptedSession = await encryptData(
+    new TextEncoder().encode(JSON.stringify(updatedOlmData)),
+    encryptionKey,
+  );
+
+  await localforage.setItem(olmDataKey, updatedEncryptedSession);
+  return encryptedNotification;
+}
+
 async function retrieveEncryptionKey(
   encryptionKeyDBLabel: string,
 ): Promise<?CryptoKey> {
@@ -326,10 +409,10 @@
 }
 
 async function getNotifsOlmSessionDBKeys(keyserverID?: string): Promise<{
-  +olmDataContentKey: string,
+  +olmDataKey: string,
   +encryptionKeyDBKey: string,
 }> {
-  const olmDataContentKeyForKeyserverPrefix = getOlmDataContentKeyForCookie(
+  const olmDataKeyForKeyserverPrefix = getOlmDataKeyForCookie(
     undefined,
     keyserverID,
   );
@@ -338,8 +421,8 @@
     getOlmEncryptionKeyDBLabelForCookie(undefined, keyserverID);
 
   const dbKeys = await localforage.keys();
-  const olmDataContentKeys = sortOlmDBKeysArray(
-    dbKeys.filter(key => key.startsWith(olmDataContentKeyForKeyserverPrefix)),
+  const olmDataKeys = sortOlmDBKeysArray(
+    dbKeys.filter(key => key.startsWith(olmDataKeyForKeyserverPrefix)),
   );
   const encryptionKeyDBLabels = sortOlmDBKeysArray(
     dbKeys.filter(key =>
@@ -347,38 +430,36 @@
     ),
   );
 
-  if (olmDataContentKeys.length === 0 || encryptionKeyDBLabels.length === 0) {
+  if (olmDataKeys.length === 0 || encryptionKeyDBLabels.length === 0) {
     throw new Error(
       'Received encrypted notification but olm session was not created',
     );
   }
 
-  const latestDataContentKey =
-    olmDataContentKeys[olmDataContentKeys.length - 1];
+  const latestDataKey = olmDataKeys[olmDataKeys.length - 1];
   const latestEncryptionKeyDBKey =
     encryptionKeyDBLabels[encryptionKeyDBLabels.length - 1];
 
-  const latestDataContentCookieID =
-    getCookieIDFromOlmDBKey(latestDataContentKey);
+  const latestDataCookieID = getCookieIDFromOlmDBKey(latestDataKey);
   const latestEncryptionKeyCookieID = getCookieIDFromOlmDBKey(
     latestEncryptionKeyDBKey,
   );
 
-  if (latestDataContentCookieID !== latestEncryptionKeyCookieID) {
+  if (latestDataCookieID !== latestEncryptionKeyCookieID) {
     throw new Error(
       'Olm sessions and their encryption keys out of sync. Latest cookie ' +
-        `id for olm sessions ${latestDataContentCookieID}. Latest cookie ` +
+        `id for olm sessions ${latestDataCookieID}. Latest cookie ` +
         `id for olm session encryption keys ${latestEncryptionKeyCookieID}`,
     );
   }
 
   const olmDBKeys = {
-    olmDataContentKey: latestDataContentKey,
+    olmDataKey: latestDataKey,
     encryptionKeyDBKey: latestEncryptionKeyDBKey,
   };
 
   const keysToDelete: $ReadOnlyArray<string> = [
-    ...olmDataContentKeys.slice(0, olmDataContentKeys.length - 1),
+    ...olmDataKeys.slice(0, olmDataKeys.length - 1),
     ...encryptionKeyDBLabels.slice(0, encryptionKeyDBLabels.length - 1),
   ];
 
@@ -386,29 +467,26 @@
   return olmDBKeys;
 }
 
-function getOlmDataContentKeyForCookie(
-  cookie: ?string,
-  keyserverID?: string,
-): string {
-  let olmDataContentKeyBase;
+function getOlmDataKeyForCookie(cookie: ?string, keyserverID?: string): string {
+  let olmDataKeyBase;
   if (keyserverID) {
-    olmDataContentKeyBase = [
+    olmDataKeyBase = [
       INDEXED_DB_KEYSERVER_PREFIX,
       keyserverID,
       NOTIFICATIONS_OLM_DATA_CONTENT,
     ].join(INDEXED_DB_KEY_SEPARATOR);
   } else {
-    olmDataContentKeyBase = NOTIFICATIONS_OLM_DATA_CONTENT;
+    olmDataKeyBase = NOTIFICATIONS_OLM_DATA_CONTENT;
   }
 
   if (!cookie) {
-    return olmDataContentKeyBase;
+    return olmDataKeyBase;
   }
   const cookieID = getCookieIDFromCookie(cookie);
-  return [olmDataContentKeyBase, cookieID].join(INDEXED_DB_KEY_SEPARATOR);
+  return [olmDataKeyBase, cookieID].join(INDEXED_DB_KEY_SEPARATOR);
 }
 
-function getOlmDataContentKeyForDeviceID(deviceID: string): string {
+function getOlmDataKeyForDeviceID(deviceID: string): string {
   return [
     INDEXED_DB_DEVICE_PREFIX,
     deviceID,
@@ -480,7 +558,7 @@
     let keyToInsert;
     if (key.startsWith(NOTIFICATIONS_OLM_DATA_CONTENT)) {
       const cookieID = getCookieIDFromOlmDBKey(key);
-      keyToInsert = getOlmDataContentKeyForCookie(
+      keyToInsert = getOlmDataKeyForCookie(
         cookieID,
         ASHOAT_KEYSERVER_ID_USED_ONLY_FOR_MIGRATION_FROM_LEGACY_NOTIF_STORAGE,
       );
@@ -557,9 +635,10 @@
 export {
   decryptWebNotification,
   decryptDesktopNotification,
-  getOlmDataContentKeyForCookie,
+  encryptNotification,
+  getOlmDataKeyForCookie,
   getOlmEncryptionKeyDBLabelForCookie,
-  getOlmDataContentKeyForDeviceID,
+  getOlmDataKeyForDeviceID,
   getOlmEncryptionKeyDBLabelForDeviceID,
   migrateLegacyOlmNotificationsSessions,
   updateNotifsUnreadCountStorage,
diff --git a/web/shared-worker/worker/worker-crypto.js b/web/shared-worker/worker/worker-crypto.js
--- a/web/shared-worker/worker/worker-crypto.js
+++ b/web/shared-worker/worker/worker-crypto.js
@@ -50,10 +50,11 @@
   generateCryptoKey,
 } from '../../crypto/aes-gcm-crypto-utils.js';
 import {
-  getOlmDataContentKeyForCookie,
+  getOlmDataKeyForCookie,
   getOlmEncryptionKeyDBLabelForCookie,
-  getOlmDataContentKeyForDeviceID,
+  getOlmDataKeyForDeviceID,
   getOlmEncryptionKeyDBLabelForDeviceID,
+  encryptNotification,
 } from '../../push-notif/notif-crypto-utils.js';
 import {
   type WorkerRequestMessage,
@@ -439,16 +440,13 @@
         cookie,
         keyserverID,
       ),
-      notifsOlmDataContentKey: getOlmDataContentKeyForCookie(
-        cookie,
-        keyserverID,
-      ),
+      notifsOlmDataContentKey: getOlmDataKeyForCookie(cookie, keyserverID),
     };
   } else {
     return {
       notifsOlmDataEncryptionKeyDBLabel:
         getOlmEncryptionKeyDBLabelForCookie(cookie),
-      notifsOlmDataContentKey: getOlmDataContentKeyForCookie(cookie),
+      notifsOlmDataContentKey: getOlmDataKeyForCookie(cookie),
     };
   }
 }
@@ -567,6 +565,16 @@
 
     return result;
   },
+  async encryptNotification(
+    payload: string,
+    deviceID: string,
+  ): Promise<EncryptedData> {
+    const { body: message, type: messageType } = await encryptNotification(
+      payload,
+      deviceID,
+    );
+    return { message, messageType };
+  },
   async decrypt(
     encryptedData: EncryptedData,
     deviceID: string,
@@ -728,7 +736,7 @@
     notificationsIdentityKeys: OLMIdentityKeys,
     notificationsInitializationInfo: OlmSessionInitializationInfo,
   ): Promise<EncryptedData> {
-    const dataPersistenceKey = getOlmDataContentKeyForDeviceID(deviceID);
+    const dataPersistenceKey = getOlmDataKeyForDeviceID(deviceID);
     const dataEncryptionKeyDBLabel =
       getOlmEncryptionKeyDBLabelForDeviceID(deviceID);
     return createAndPersistNotificationsOutboundSession(