diff --git a/web/redux/action-types.js b/web/redux/action-types.js
--- a/web/redux/action-types.js
+++ b/web/redux/action-types.js
@@ -1,6 +1,39 @@
 // @flow
 
+import type { CallServerEndpoint } from 'lib/utils/call-server-endpoint.js';
+import type { URLInfo } from 'lib/utils/url-utils.js';
+
+import type { InitialReduxState } from '../types/redux-types.js';
+
 export const updateNavInfoActionType = 'UPDATE_NAV_INFO';
 export const updateWindowDimensionsActionType = 'UPDATE_WINDOW_DIMENSIONS';
 export const updateWindowActiveActionType = 'UPDATE_WINDOW_ACTIVE';
 export const setDeviceIDActionType = 'SET_DEVICE_ID';
+export const setInitialReduxState = 'SET_INITIAL_REDUX_STATE';
+
+const getInitialReduxState =
+  (
+    callServerEndpoint: CallServerEndpoint,
+  ): (URLInfo => Promise<InitialReduxState>) =>
+  async urlInfo => {
+    const response = await callServerEndpoint(
+      'get_initial_redux_state',
+      urlInfo,
+    );
+    return {
+      navInfo: response.navInfo,
+      currentUserInfo: response.currentUserInfo,
+      entryStore: response.entryStore,
+      threadStore: response.threadStore,
+      userInfos: response.userInfos,
+      actualizedCalendarQuery: response.actualizedCalendarQuery,
+      messageStore: response.messageStore,
+      dataLoaded: response.dataLoaded,
+      pushApiPublicKey: response.pushApiPublicKey,
+      commServicesAccessToken: response.commServicesAccessToken,
+      inviteLinksStore: response.inviteLinksStore,
+      keyserverInfo: response.keyserverInfo,
+    };
+  };
+
+export { getInitialReduxState };
diff --git a/web/redux/redux-setup.js b/web/redux/redux-setup.js
--- a/web/redux/redux-setup.js
+++ b/web/redux/redux-setup.js
@@ -41,6 +41,7 @@
   setDeviceIDActionType,
   updateNavInfoActionType,
   updateWindowDimensionsActionType,
+  setInitialReduxState,
 } from './action-types.js';
 import { reduceCommunityPickerStore } from './community-picker-reducer.js';
 import {
@@ -56,6 +57,7 @@
 import { getDatabaseModule } from '../database/database-module-provider.js';
 import { activeThreadSelector } from '../selectors/nav-selectors.js';
 import { type NavInfo } from '../types/nav-types.js';
+import type { InitialReduxState } from '../types/redux-types.js';
 import { workerRequestMessageTypes } from '../types/worker-types.js';
 
 export type WindowDimensions = { width: number, height: number };
@@ -115,13 +117,31 @@
   | { +type: 'SET_PRIMARY_IDENTITY_KEYS', payload: ?OLMIdentityKeys }
   | { +type: 'SET_NOTIFICATION_IDENTITY_KEYS', payload: ?OLMIdentityKeys }
   | { +type: 'SET_PICKLED_PRIMARY_ACCOUNT', payload: ?PickledOLMAccount }
-  | { +type: 'SET_PICKLED_NOTIFICATION_ACCOUNT', payload: ?PickledOLMAccount };
+  | { +type: 'SET_PICKLED_NOTIFICATION_ACCOUNT', payload: ?PickledOLMAccount }
+  | { +type: 'SET_INITIAL_REDUX_STATE', payload: InitialReduxState };
 
 export function reducer(oldState: AppState | void, action: Action): AppState {
   invariant(oldState, 'should be set');
   let state = oldState;
 
-  if (action.type === updateWindowDimensionsActionType) {
+  if (action.type === setInitialReduxState) {
+    const { userInfos, keyserverInfo, ...rest } = action.payload;
+    return validateState(oldState, {
+      ...state,
+      ...rest,
+      userStore: { userInfos, inconsistencyReports: [] },
+      keyserverStore: {
+        ...state.keyserverStore,
+        keyserverInfos: {
+          ...state.keyserverStore.keyserverInfos,
+          [ashoatKeyserverID]: {
+            ...state.keyserverStore.keyserverInfos[ashoatKeyserverID],
+            ...keyserverInfo,
+          },
+        },
+      },
+    });
+  } else if (action.type === updateWindowDimensionsActionType) {
     return validateState(oldState, {
       ...state,
       windowDimensions: action.payload,