diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx
index a83e8c35c9df8bc218231f572e61c8025d8ebe58..94cf25a59342a066a2e88b561cb41604e5ba461f 100644
--- a/src/containers/blocks.jsx
+++ b/src/containers/blocks.jsx
@@ -25,6 +25,7 @@ import {activateColorPicker} from '../reducers/color-picker';
 import {closeExtensionLibrary, openSoundRecorder, openConnectionModal} from '../reducers/modals';
 import {activateCustomProcedures, deactivateCustomProcedures} from '../reducers/custom-procedures';
 import {setConnectionModalExtensionId} from '../reducers/connection-modal';
+import {updateMetrics} from '../reducers/workspace-metrics';
 
 import {
     activateTab,
@@ -79,7 +80,6 @@ class Blocks extends React.Component {
         this.ScratchBlocks.recordSoundCallback = this.handleOpenSoundRecorder;
 
         this.state = {
-            workspaceMetrics: {},
             prompt: null
         };
         this.onTargetsUpdate = debounce(this.onTargetsUpdate, 100);
@@ -301,14 +301,12 @@ class Blocks extends React.Component {
     onWorkspaceMetricsChange () {
         const target = this.props.vm.editingTarget;
         if (target && target.id) {
-            const workspaceMetrics = Object.assign({}, this.state.workspaceMetrics, {
-                [target.id]: {
-                    scrollX: this.workspace.scrollX,
-                    scrollY: this.workspace.scrollY,
-                    scale: this.workspace.scale
-                }
+            this.props.updateMetrics({
+                targetID: target.id,
+                scrollX: this.workspace.scrollX,
+                scrollY: this.workspace.scrollY,
+                scale: this.workspace.scale
             });
-            this.setState({workspaceMetrics});
         }
     }
     onScriptGlowOn (data) {
@@ -355,7 +353,7 @@ class Blocks extends React.Component {
             this.props.updateToolboxState(toolboxXML);
         }
 
-        if (this.props.vm.editingTarget && !this.state.workspaceMetrics[this.props.vm.editingTarget.id]) {
+        if (this.props.vm.editingTarget && !this.props.workspaceMetrics[this.props.vm.editingTarget.id]) {
             this.onWorkspaceMetricsChange();
         }
 
@@ -381,8 +379,8 @@ class Blocks extends React.Component {
         }
         this.workspace.addChangeListener(this.props.vm.blockListener);
 
-        if (this.props.vm.editingTarget && this.state.workspaceMetrics[this.props.vm.editingTarget.id]) {
-            const {scrollX, scrollY, scale} = this.state.workspaceMetrics[this.props.vm.editingTarget.id];
+        if (this.props.vm.editingTarget && this.props.workspaceMetrics[this.props.vm.editingTarget.id]) {
+            const {scrollX, scrollY, scale} = this.props.workspaceMetrics[this.props.vm.editingTarget.id];
             this.workspace.scrollX = scrollX;
             this.workspace.scrollY = scrollY;
             this.workspace.scale = scale;
@@ -506,7 +504,7 @@ class Blocks extends React.Component {
             });
     }
     render () {
-        /* eslint-disable no-unused-vars */
+        /* eslint-disable no-unused-vars, no-shadow */
         const {
             anyModalVisible,
             canUseCloud,
@@ -525,9 +523,11 @@ class Blocks extends React.Component {
             onRequestCloseExtensionLibrary,
             onRequestCloseCustomProcedures,
             toolboxXML,
+            workspaceMetrics,
+            updateMetrics,
             ...props
         } = this.props;
-        /* eslint-enable no-unused-vars */
+        /* eslint-enable no-unused-vars, no-shadow */
         return (
             <React.Fragment>
                 <DroppableBlocks
@@ -654,7 +654,8 @@ const mapStateToProps = state => ({
     locale: state.locales.locale,
     messages: state.locales.messages,
     toolboxXML: state.scratchGui.toolbox.toolboxXML,
-    customProceduresVisible: state.scratchGui.customProcedures.active
+    customProceduresVisible: state.scratchGui.customProcedures.active,
+    workspaceMetrics: state.scratchGui.workspaceMetrics
 });
 
 const mapDispatchToProps = dispatch => ({
@@ -676,6 +677,9 @@ const mapDispatchToProps = dispatch => ({
     },
     updateToolboxState: toolboxXML => {
         dispatch(updateToolbox(toolboxXML));
+    },
+    updateMetrics: metrics => {
+        dispatch(updateMetrics(metrics));
     }
 });
 
diff --git a/src/reducers/gui.js b/src/reducers/gui.js
index 9024b47422a028b7a21587036cd28ed5698e0858..378a3203ca57e325da9db1eb39e3f4fdded156fc 100644
--- a/src/reducers/gui.js
+++ b/src/reducers/gui.js
@@ -25,6 +25,7 @@ import timeoutReducer, {timeoutInitialState} from './timeout';
 import toolboxReducer, {toolboxInitialState} from './toolbox';
 import vmReducer, {vmInitialState} from './vm';
 import vmStatusReducer, {vmStatusInitialState} from './vm-status';
+import workspaceMetricsReducer, {workspaceMetricsInitialState} from './workspace-metrics';
 import throttle from 'redux-throttle';
 
 import decks from '../lib/libraries/decks/index.jsx';
@@ -57,7 +58,8 @@ const guiInitialState = {
     timeout: timeoutInitialState,
     toolbox: toolboxInitialState,
     vm: vmInitialState,
-    vmStatus: vmStatusInitialState
+    vmStatus: vmStatusInitialState,
+    workspaceMetrics: workspaceMetricsInitialState
 };
 
 const initPlayer = function (currentState) {
@@ -155,7 +157,8 @@ const guiReducer = combineReducers({
     timeout: timeoutReducer,
     toolbox: toolboxReducer,
     vm: vmReducer,
-    vmStatus: vmStatusReducer
+    vmStatus: vmStatusReducer,
+    workspaceMetrics: workspaceMetricsReducer
 });
 
 export {
diff --git a/src/reducers/workspace-metrics.js b/src/reducers/workspace-metrics.js
new file mode 100644
index 0000000000000000000000000000000000000000..ca4dd1ec17ca7f192cb48f731ede5d6778c93293
--- /dev/null
+++ b/src/reducers/workspace-metrics.js
@@ -0,0 +1,33 @@
+const UPDATE_METRICS = 'scratch-gui/workspace-metrics/UPDATE_METRICS';
+
+const initialState = {};
+
+const reducer = function (state, action) {
+    if (typeof state === 'undefined') state = initialState;
+
+    switch (action.type) {
+    case UPDATE_METRICS:
+        return Object.assign({}, state, {
+            [action.targetID]: {
+                scrollX: action.scrollX,
+                scrollY: action.scrollY,
+                scale: action.scale
+            }
+        });
+    default:
+        return state;
+    }
+};
+
+const updateMetrics = function (metrics) {
+    return {
+        type: UPDATE_METRICS,
+        ...metrics
+    };
+};
+
+export {
+    reducer as default,
+    initialState as workspaceMetricsInitialState,
+    updateMetrics
+};