diff --git a/keyserver/src/responders/website-responders.js b/keyserver/src/responders/website-responders.js
--- a/keyserver/src/responders/website-responders.js
+++ b/keyserver/src/responders/website-responders.js
@@ -237,6 +237,7 @@
   commServicesAccessToken: t.Nil,
   inviteLinksStore: inviteLinksStoreValidator,
   keyserverStore: keyserverStoreValidator,
+  initialStateLoaded: tBool(false),
 });
 
 async function websiteResponder(
@@ -603,6 +604,7 @@
     commServicesAccessToken: null,
     inviteLinksStore: inviteLinksStorePromise,
     keyserverStore: keyserverStorePromise,
+    initialStateLoaded: false,
   });
   const validatedInitialReduxState = validateOutput(
     viewer.platformDetails,
diff --git a/web/redux/initial-state-gate.js b/web/redux/initial-state-gate.js
new file mode 100644
--- /dev/null
+++ b/web/redux/initial-state-gate.js
@@ -0,0 +1,66 @@
+// @flow
+
+import * as React from 'react';
+import { useDispatch } from 'react-redux';
+import { PersistGate } from 'redux-persist/es/integration/react.js';
+import type { Persistor } from 'redux-persist/es/types';
+
+import { useServerCall } from 'lib/utils/action-utils.js';
+import { infoFromURL } from 'lib/utils/url-utils.js';
+
+import { getInitialReduxState, setInitialReduxState } from './action-types.js';
+import { useSelector } from './redux-utils.js';
+import Loading from '../loading.react.js';
+
+type Props = {
+  +persistor: Persistor,
+  +children: React.Node,
+};
+function InitialReduxStateGate(props: Props): React.Node {
+  const { children, persistor } = props;
+  const callGetInitialReduxState = useServerCall(getInitialReduxState);
+  const dispatch = useDispatch();
+
+  const [initError, setInitError] = React.useState<?Error>(null);
+  React.useEffect(() => {
+    if (initError) {
+      throw initError;
+    }
+  }, [initError]);
+
+  const isRehydrated = useSelector(state => !!state._persist?.rehydrated);
+  const prevIsRehydrated = React.useRef(false);
+  React.useEffect(() => {
+    if (!prevIsRehydrated.current && isRehydrated) {
+      prevIsRehydrated.current = isRehydrated;
+      (async () => {
+        try {
+          const urlInfo = infoFromURL(decodeURI(window.location.href));
+          const payload = await callGetInitialReduxState(urlInfo);
+          dispatch({ type: setInitialReduxState, payload });
+        } catch (err) {
+          setInitError(err);
+        }
+      })();
+    }
+  }, [callGetInitialReduxState, dispatch, isRehydrated]);
+
+  const initialStateLoaded = useSelector(state => state.initialStateLoaded);
+
+  const childFunction = React.useCallback(
+    // This argument is passed from `PersistGate`. It means that the state is
+    // rehydrated and we can start fetching the initial info.
+    bootstrapped => {
+      if (bootstrapped && initialStateLoaded) {
+        return children;
+      } else {
+        return <Loading />;
+      }
+    },
+    [children, initialStateLoaded],
+  );
+
+  return <PersistGate persistor={persistor}>{childFunction}</PersistGate>;
+}
+
+export default InitialReduxStateGate;
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
@@ -97,6 +97,7 @@
   +commServicesAccessToken: ?string,
   +inviteLinksStore: InviteLinksStore,
   +keyserverStore: KeyserverStore,
+  +initialStateLoaded: boolean,
 };
 
 export type Action =
@@ -140,6 +141,7 @@
           },
         },
       },
+      initialStateLoaded: true,
     });
   } else if (action.type === updateWindowDimensionsActionType) {
     return validateState(oldState, {
diff --git a/web/root.js b/web/root.js
--- a/web/root.js
+++ b/web/root.js
@@ -7,7 +7,6 @@
 import { createStore, applyMiddleware, type Store } from 'redux';
 import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction.js';
 import { persistReducer, persistStore } from 'redux-persist';
-import { PersistGate } from 'redux-persist/es/integration/react.js';
 import thunk from 'redux-thunk';
 
 import { reduxLoggerMiddleware } from 'lib/utils/action-logger.js';
@@ -16,7 +15,7 @@
 import { SQLiteDataHandler } from './database/sqlite-data-handler.js';
 import { localforageConfig } from './database/utils/constants.js';
 import ErrorBoundary from './error-boundary.react.js';
-import Loading from './loading.react.js';
+import InitialReduxStateGate from './redux/initial-state-gate.js';
 import { persistConfig } from './redux/persist.js';
 import { type AppState, type Action, reducer } from './redux/redux-setup.js';
 import history from './router-history.js';
@@ -36,15 +35,15 @@
 
 const RootProvider = (): React.Node => (
   <Provider store={store}>
-    <PersistGate persistor={persistor} loading={<Loading />}>
-      <ErrorBoundary>
+    <ErrorBoundary>
+      <InitialReduxStateGate persistor={persistor}>
         <Router history={history.getHistoryObject()}>
           <Route path="*" component={App} />
         </Router>
         <Socket />
         <SQLiteDataHandler />
-      </ErrorBoundary>
-    </PersistGate>
+      </InitialReduxStateGate>
+    </ErrorBoundary>
   </Provider>
 );