diff --git a/src/lib/project-saver-hoc.jsx b/src/lib/project-saver-hoc.jsx
index 911769762a8570aab8b68964a6238f90baa0407b..ee56b4b582c0453960aba4fe82db60b34490ba93 100644
--- a/src/lib/project-saver-hoc.jsx
+++ b/src/lib/project-saver-hoc.jsx
@@ -59,7 +59,12 @@ const ProjectSaverHOC = function (WrappedComponent) {
                 // but then it'd be hard to turn this listening off in our tests
                 window.onbeforeunload = e => this.leavePageConfirm(e);
             }
+
+            // Allow the GUI consumer to pass in a function to receive a trigger
+            // for triggering thumbnail or whole project saves.
+            // These functions are called with null on unmount to prevent stale references.
             this.props.onSetProjectThumbnailer(this.getProjectThumbnail);
+            this.props.onSetProjectSaver(this.tryToAutoSave);
         }
         componentDidUpdate (prevProps) {
             if (!this.props.isAnyCreatingNewState && prevProps.isAnyCreatingNewState) {
@@ -116,6 +121,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
             // window.onbeforeunload = undefined; // eslint-disable-line no-undefined
             // Remove project thumbnailer function since the components are unmounting
             this.props.onSetProjectThumbnailer(null);
+            this.props.onSetProjectSaver(null);
         }
         leavePageConfirm (e) {
             if (this.props.projectChanged) {
@@ -310,6 +316,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
                 onRemixing,
                 onSetProjectUnchanged,
                 onSetProjectThumbnailer,
+                onSetProjectSaver,
                 onShowAlert,
                 onShowCopySuccessAlert,
                 onShowRemixSuccessAlert,
@@ -376,6 +383,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
         autoSaveIntervalSecs: 120,
         onRemixing: () => {},
         onSetProjectThumbnailer: () => {},
+        onSetProjectSaver: () => {},
         onUpdateProjectData: saveProjectToServer
     };
     const mapStateToProps = (state, ownProps) => {
diff --git a/test/unit/util/project-saver-hoc.test.jsx b/test/unit/util/project-saver-hoc.test.jsx
index 1336daef0b0a8f9bd0bbb13ebd4b1984d4dff52c..56ed39d44f9816dc7fd4015b2d242829bc2232c7 100644
--- a/test/unit/util/project-saver-hoc.test.jsx
+++ b/test/unit/util/project-saver-hoc.test.jsx
@@ -465,4 +465,27 @@ describe('projectSaverHOC', () => {
         expect(setThumb).toHaveBeenCalledTimes(2);
         expect(setThumb.mock.calls[1][0]).toBe(null);
     });
+
+    test('uses onSetProjectSaver on mount/unmount', () => {
+        const Component = () => <div />;
+        const WrappedComponent = projectSaverHOC(Component);
+        const setSaver = jest.fn();
+        const mounted = mount(
+            <WrappedComponent
+                store={store}
+                vm={vm}
+                onSetProjectSaver={setSaver}
+            />
+        );
+        // Set project saver should be called on mount
+        expect(setSaver).toHaveBeenCalledTimes(1);
+
+        // And it should not pass that function on to wrapped element
+        expect(mounted.find(Component).props().onSetProjectSaver).toBeUndefined();
+
+        // Unmounting should call it again with null
+        mounted.unmount();
+        expect(setSaver).toHaveBeenCalledTimes(2);
+        expect(setSaver.mock.calls[1][0]).toBe(null);
+    });
 });