diff --git a/src/index.tsx b/src/index.tsx
index 7e4c2eda..7e8ea224 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -25,8 +25,6 @@ render(
 - friendship
 - password restore
 - signup?
-- flow updates
-- flow infinite scroll
 - avatar upload
 
   [stage 1]
@@ -42,6 +40,8 @@ render(
 - comment editing
 
 Done:
+- flow updates
+- flow infinite scroll
 - better node brief update
 - fix: text nodes cell has no preview (actually, that's a problem of brief)
 - relocate files
diff --git a/src/redux/flow/sagas.ts b/src/redux/flow/sagas.ts
index 6d90e6fd..b1a9f452 100644
--- a/src/redux/flow/sagas.ts
+++ b/src/redux/flow/sagas.ts
@@ -8,7 +8,7 @@ import {
 } from "redux-saga/effects";
 import { REHYDRATE } from "redux-persist";
 import { FLOW_ACTIONS } from "./constants";
-import { getNodes, getNodeDiff } from "../node/api";
+import { getNodeDiff } from "../node/api";
 import {
   flowSetNodes,
   flowSetCellView,
@@ -17,13 +17,17 @@ import {
   flowSetUpdated,
   flowSetFlow
 } from "./actions";
-import { IResultWithStatus } from "../types";
+import { IResultWithStatus, INode } from "../types";
 import { selectFlowNodes } from "./selectors";
 import { reqWrapper } from "../auth/sagas";
 import { postCellView } from "./api";
 import { IFlowState } from "./reducer";
 import uniq from "ramda/es/uniq";
 
+function hideLoader() {
+  document.getElementById("main_loader").style.display = "none";
+}
+
 function* onGetFlow() {
   const {
     flow: { _persist }
@@ -31,25 +35,61 @@ function* onGetFlow() {
 
   if (!_persist.rehydrated) return;
 
+  const stored: IFlowState["nodes"] = yield select(selectFlowNodes);
+
+  if (stored.length) {
+    hideLoader();
+  }
+
+  const start =
+    (stored && stored[0] && stored[0].created_at) || new Date().toISOString();
+
+  const end =
+    (stored &&
+      stored[stored.length - 1] &&
+      stored[stored.length - 1].created_at) ||
+    new Date().toISOString();
+
   yield put(flowSetFlow({ is_loading: true }));
 
   const {
-    data: { nodes = [], heroes = [], recent = [], updated = [], mode }
+    data: {
+      before = [],
+      after = [],
+      heroes = [],
+      recent = [],
+      updated = [],
+      valid = null
+    }
   }: IResultWithStatus<{
-    nodes: IFlowState["nodes"];
+    before: IFlowState["nodes"];
+    after: IFlowState["nodes"];
     heroes: IFlowState["heroes"];
     recent: IFlowState["recent"];
     updated: IFlowState["updated"];
-    mode: string;
-  }> = yield call(reqWrapper, getNodes, {});
+    valid: INode["id"][];
+  }> = yield call(reqWrapper, getNodeDiff, {
+    start,
+    end,
+    with_heroes: true,
+    with_updated: true,
+    with_recent: true,
+    with_valid: true
+  });
 
-  yield put(flowSetFlow({ is_loading: false, nodes }));
+  const result = uniq([
+    ...(before || []),
+    ...(valid ? stored.filter(node => valid.includes(node.id)) : stored),
+    ...(after || [])
+  ]);
+
+  yield put(flowSetFlow({ is_loading: false, nodes: result }));
 
   if (heroes.length) yield put(flowSetHeroes(heroes));
   if (recent.length) yield put(flowSetRecent(recent));
   if (updated.length) yield put(flowSetUpdated(updated));
 
-  document.getElementById("main_loader").style.display = "none";
+  if (!stored.length) hideLoader();
 }
 
 function* onSetCellView({ id, flow }: ReturnType<typeof flowSetCellView>) {
@@ -69,17 +109,33 @@ function* getMore() {
   const end =
     nodes && nodes[nodes.length - 1] && nodes[nodes.length - 1].created_at;
 
-  const { error, data } = yield call(reqWrapper, getNodeDiff, { start, end });
+  const { error, data } = yield call(reqWrapper, getNodeDiff, {
+    start,
+    end,
+    with_heroes: false,
+    with_updated: true,
+    with_recent: true,
+    with_valid: true
+  });
 
   if (error || !data) return;
 
   const result = uniq([
     ...(data.before || []),
-    ...nodes,
+    ...(data.valid
+      ? nodes.filter(node => data.valid.includes(node.id))
+      : nodes),
     ...(data.after || [])
   ]);
 
-  yield put(flowSetFlow({ is_loading: false, nodes: result }));
+  yield put(
+    flowSetFlow({
+      is_loading: false,
+      nodes: result,
+      ...(data.recent ? { recent: data.recent } : {}),
+      ...(data.updated ? { updated: data.updated } : {})
+    })
+  );
 
   yield delay(1000);
 }
diff --git a/src/redux/node/api.ts b/src/redux/node/api.ts
index 5e5540d2..5a79b79b 100644
--- a/src/redux/node/api.ts
+++ b/src/redux/node/api.ts
@@ -38,17 +38,35 @@ export const getNodeDiff = ({
   start = null,
   end = null,
   take,
+  with_heroes,
+  with_updated,
+  with_recent,
+  with_valid,
   access
 }: {
   start?: string;
   end?: string;
   take?: number;
   access: string;
+  with_heroes: boolean;
+  with_updated: boolean;
+  with_recent: boolean;
+  with_valid: boolean;
 }): Promise<IResultWithStatus<{ nodes: INode[] }>> =>
   api
     .get(
       API.NODE.GET_DIFF,
-      configWithToken(access, { params: { start, end, take } })
+      configWithToken(access, {
+        params: {
+          start,
+          end,
+          take,
+          with_heroes,
+          with_updated,
+          with_recent,
+          with_valid
+        }
+      })
     )
     .then(resultMiddleware)
     .catch(errorMiddleware);
diff --git a/src/redux/store.ts b/src/redux/store.ts
index 75683af0..e241f2e8 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -45,7 +45,7 @@ const authPersistConfig: PersistConfig = {
 
 const flowPersistConfig: PersistConfig = {
   key: "flow",
-  whitelist: ["nodes"],
+  whitelist: ["nodes", "heroes", "recent", "updated"],
   storage
 };