diff --git a/__tests__/fixtures/config/export.example.json b/__tests__/fixtures/config/export.example.json
new file mode 100644
index 0000000000000000000000000000000000000000..15054c42ff63a47515a5e4fbf3c709df976c9da3
--- /dev/null
+++ b/__tests__/fixtures/config/export.example.json
@@ -0,0 +1,298 @@
+{
+  "companionWindows": {
+    "cw-b86f0558-6f04-4b56-ac9b-34b7e0769db3": {
+      "content": "info",
+      "default": true,
+      "id": "cw-b86f0558-6f04-4b56-ac9b-34b7e0769db3",
+      "position": "left"
+    },
+    "cw-b15df6ac-9069-4f16-bd19-e11c6aaa3911": {
+      "content": "thumbnail_navigation",
+      "default": true,
+      "id": "cw-b15df6ac-9069-4f16-bd19-e11c6aaa3911",
+      "position": "far-bottom"
+    },
+    "cw-c4934b3c-2411-40b1-9088-5e066276620f": {
+      "content": "info",
+      "default": true,
+      "id": "cw-c4934b3c-2411-40b1-9088-5e066276620f",
+      "position": "left"
+    },
+    "cw-76580e14-4d7a-4ea5-84a6-5de052941a3d": {
+      "content": "thumbnail_navigation",
+      "default": true,
+      "id": "cw-76580e14-4d7a-4ea5-84a6-5de052941a3d",
+      "position": "far-bottom"
+    }
+  },
+  "config": {
+    "canvasNavigation": {
+      "height": 50,
+      "width": 50
+    },
+    "theme": {
+      "palette": {
+        "type": "light",
+        "primary": {
+          "main": "#f5f5f5",
+          "light": "#ffffff",
+          "dark": "#eeeeee",
+          "contrastText": "rgba(0, 0, 0, 0.87)"
+        },
+        "secondary": {
+          "main": "#1967d2",
+          "light": "#64b5f6",
+          "dark": "#0d47a1",
+          "contrastText": "#fff"
+        },
+        "error": {
+          "main": "#b00020",
+          "light": "rgb(191, 51, 76)",
+          "dark": "rgb(123, 0, 22)",
+          "contrastText": "#fff"
+        }
+      },
+      "typography": {
+        "fontSize": 16,
+        "body1": {
+          "fontSize": "1rem",
+          "letterSpacing": "0em",
+          "lineHeight": "1.6em"
+        },
+        "body2": {
+          "fontSize": "0.878rem",
+          "letterSpacing": "0.015em",
+          "lineHeight": "1.6em"
+        },
+        "button": {
+          "fontSize": "0.878rem",
+          "letterSpacing": "0.09em",
+          "lineHeight": "2.25rem",
+          "textTransform": "uppercase"
+        },
+        "caption": {
+          "fontSize": "0.772rem",
+          "letterSpacing": "0.033em",
+          "lineHeight": "1.6rem"
+        },
+        "body1Next": {
+          "fontSize": "1rem",
+          "letterSpacing": "0em",
+          "lineHeight": "1.6em"
+        },
+        "body2Next": {
+          "fontSize": "0.878rem",
+          "letterSpacing": "0.015em",
+          "lineHeight": "1.6em"
+        },
+        "buttonNext": {
+          "fontSize": "0.878rem",
+          "letterSpacing": "0.09em",
+          "lineHeight": "2.25rem"
+        },
+        "captionNext": {
+          "fontSize": "0.772rem",
+          "letterSpacing": "0.33em",
+          "lineHeight": "1.6rem"
+        },
+        "overline": {
+          "fontSize": "0.678rem",
+          "fontWeight": 500,
+          "letterSpacing": "0.166em",
+          "lineHeight": "2em",
+          "textTransform": "uppercase"
+        },
+        "h1": {
+          "fontSize": "2.822rem",
+          "letterSpacing": "-0.015em",
+          "lineHeight": "1.2em"
+        },
+        "h2": {
+          "fontSize": "1.575rem",
+          "letterSpacing": "0em",
+          "lineHeight": "1.33em"
+        },
+        "h3": {
+          "fontSize": "1.383rem",
+          "fontWeight": 300,
+          "letterSpacing": "0em",
+          "lineHeight": "1.33em"
+        },
+        "h4": {
+          "fontSize": "1.215rem",
+          "letterSpacing": "0.007em",
+          "lineHeight": "1.45em"
+        },
+        "h5": {
+          "fontSize": "1.138rem",
+          "letterSpacing": "0.005em",
+          "lineHeight": "1.55em"
+        },
+        "h6": {
+          "fontSize": "1.067rem",
+          "fontWeight": 400,
+          "letterSpacing": "0.01em",
+          "lineHeight": "1.6em"
+        },
+        "subtitle1": {
+          "fontSize": "0.937rem",
+          "letterSpacing": "0.015em",
+          "lineHeight": "1.6em",
+          "fontWeight": 300
+        },
+        "subtitle2": {
+          "fontSize": "0.878rem",
+          "fontWeight": 500,
+          "letterSpacing": "0.02em",
+          "lineHeight": "1.75em"
+        },
+        "useNextVariants": true
+      },
+      "props": {
+        "MuiButtonBase": {
+          "disableTouchRipple": true
+        }
+      }
+    },
+    "language": "en",
+    "availableLanguages": {
+      "de": "Deutsch",
+      "en": "English"
+    },
+    "displayAllAnnotations": false,
+    "translations": {},
+    "window": {
+      "allowClose": true,
+      "allowMaximize": true,
+      "defaultView": "single"
+    },
+    "windows": [
+      {
+        "loadedManifest": "https://iiif.harvardartmuseums.org/manifests/object/299843",
+        "canvasIndex": 2
+      },
+      {
+        "loadedManifest": "https://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json",
+        "thumbnailNavigationPosition": "off"
+      }
+    ],
+    "thumbnailNavigation": {
+      "defaultPosition": "far-bottom",
+      "height": 150,
+      "width": 100
+    },
+    "workspace": {
+      "type": "mosaic"
+    },
+    "workspaceControlPanel": {
+      "enabled": true
+    },
+    "id": "mirador",
+    "manifests": {
+      "https://media.nga.gov/public/manifests/nga_highlights.json": {
+        "provider": "National Gallery of Art"
+      },
+      "https://data.ucd.ie/api/img/manifests/ucdlib:33064": {
+        "provider": "Irish Architectural Archive"
+      },
+      "https://wellcomelibrary.org/iiif/b18035723/manifest": {
+        "provider": "Wellcome Library"
+      },
+      "https://demos.biblissima.fr/iiif/metadata/florus-dispersus/manifest.json": {
+        "provider": "Biblissima"
+      },
+      "https://www.e-codices.unifr.ch/metadata/iiif/gau-Fragment/manifest.json": {
+        "provider": "e-codices - Virtual Manuscript Library of Switzerland"
+      },
+      "https://wellcomelibrary.org/iiif/collection/b18031511": {
+        "provider": "Wellcome Library"
+      },
+      "https://gallica.bnf.fr/iiif/ark:/12148/btv1b10022508f/manifest.json": {
+        "provider": "Bibliothèque nationale de France"
+      },
+      "https://manifests.britishart.yale.edu/Osbornfa1": {
+        "provider": "Beinecke Rare Book and Manuscript Library, Yale University"
+      },
+      "https://iiif.biblissima.fr/chateauroux/B360446201_MS0005/manifest.json": {
+        "provider": "Biblissima"
+      },
+      "https://iiif.durham.ac.uk/manifests/trifle/32150/t1/m4/q7/t1m4q77fr328/manifest": {
+        "provider": "Durham University Library"
+      }
+    }
+  },
+  "viewers": {
+    "window-404c667d-e1e0-4ae7-aaf2-98e08bb627bd": {
+      "x": 1205.5,
+      "y": 1686,
+      "zoom": 0.00021117049395471312
+    },
+    "window-f48761a4-4388-4ddd-aff6-9a331410aad3": {
+      "x": 2217.999999999988,
+      "y": 3193.5865262629163,
+      "zoom": 0.00010301562691749936
+    }
+  },
+  "windows": {
+    "window-404c667d-e1e0-4ae7-aaf2-98e08bb627bd": {
+      "canvasIndex": 4,
+      "collectionIndex": 0,
+      "companionWindowIds": [
+        "cw-b86f0558-6f04-4b56-ac9b-34b7e0769db3",
+        "cw-b15df6ac-9069-4f16-bd19-e11c6aaa3911"
+      ],
+      "displayAllAnnotations": false,
+      "height": 400,
+      "id": "window-404c667d-e1e0-4ae7-aaf2-98e08bb627bd",
+      "manifestId": "https://wellcomelibrary.org/iiif/b18035723/manifest",
+      "maximized": false,
+      "rangeId": null,
+      "rotation": null,
+      "selectedAnnotations": {},
+      "sideBarPanel": "info",
+      "thumbnailNavigationId": "cw-b15df6ac-9069-4f16-bd19-e11c6aaa3911",
+      "view": "single",
+      "width": 400,
+      "x": 200,
+      "y": 200
+    },
+    "window-f48761a4-4388-4ddd-aff6-9a331410aad3": {
+      "canvasIndex": 1,
+      "collectionIndex": 0,
+      "companionWindowIds": [
+        "cw-c4934b3c-2411-40b1-9088-5e066276620f",
+        "cw-76580e14-4d7a-4ea5-84a6-5de052941a3d"
+      ],
+      "displayAllAnnotations": false,
+      "height": 400,
+      "id": "window-f48761a4-4388-4ddd-aff6-9a331410aad3",
+      "manifestId": "https://demos.biblissima.fr/iiif/metadata/florus-dispersus/manifest.json",
+      "maximized": false,
+      "rangeId": null,
+      "rotation": null,
+      "selectedAnnotations": {},
+      "sideBarPanel": "info",
+      "thumbnailNavigationId": "cw-76580e14-4d7a-4ea5-84a6-5de052941a3d",
+      "view": "single",
+      "width": 400,
+      "x": 230,
+      "y": 250
+    }
+  },
+  "workspace": {
+    "exposeModeOn": false,
+    "height": 5000,
+    "viewportPosition": {
+      "x": 0,
+      "y": 0
+    },
+    "width": 5000,
+    "layout": {
+      "direction": "row",
+      "first": "window-404c667d-e1e0-4ae7-aaf2-98e08bb627bd",
+      "second": "window-f48761a4-4388-4ddd-aff6-9a331410aad3"
+    },
+    "focusedWindowId": "window-f48761a4-4388-4ddd-aff6-9a331410aad3",
+    "isWorkspaceAddVisible": false
+  }
+}
\ No newline at end of file
diff --git a/__tests__/src/actions/config.test.js b/__tests__/src/actions/config.test.js
index f75d604d7a2ba9a0a3b832eb3c0948ffc205c857..aa2f94c57363478321e0fef48c38e6c2ae876cbf 100644
--- a/__tests__/src/actions/config.test.js
+++ b/__tests__/src/actions/config.test.js
@@ -1,5 +1,6 @@
 import * as actions from '../../../src/state/actions';
 import ActionTypes from '../../../src/state/actions/action-types';
+import configFixture from '../../fixtures/config/export.example.json';
 
 describe('config actions', () => {
   describe('setConfig', () => {
@@ -22,4 +23,15 @@ describe('config actions', () => {
       expect(actions.updateConfig(config)).toEqual(expectedAction);
     });
   });
+
+  describe('importConfig', () => {
+    it('imports the config', () => {
+      const config = configFixture;
+      const expectedAction = {
+        config,
+        type: ActionTypes.IMPORT_CONFIG,
+      };
+      expect(actions.importConfig(config)).toEqual(expectedAction);
+    });
+  });
 });
diff --git a/__tests__/src/actions/erros.test.js b/__tests__/src/actions/erros.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..b38e5b47546791f0568156779c344a24fd795543
--- /dev/null
+++ b/__tests__/src/actions/erros.test.js
@@ -0,0 +1,27 @@
+import * as actions from '../../../src/state/actions';
+import ActionTypes from '../../../src/state/actions/action-types';
+
+describe('errors actions', () => {
+  describe('addError', () => {
+    it('adds an error', () => {
+      const errorMessage = 'errorMessage';
+      const createdAction = actions.addError(errorMessage);
+
+      expect(createdAction).toHaveProperty('message', errorMessage);
+      expect(createdAction).toHaveProperty('id');
+      expect(createdAction.id).toBeDefined();
+    });
+  });
+
+  describe('removeError', () => {
+    it('removes an existing error', () => {
+      const errorId = 'testId123';
+      const expectedAction = {
+        id: errorId,
+        type: ActionTypes.REMOVE_ERROR,
+      };
+
+      expect(actions.removeError(errorId)).toEqual(expectedAction);
+    });
+  });
+});
diff --git a/__tests__/src/components/ErrorDialog.test.js b/__tests__/src/components/ErrorDialog.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..109187269e2245289d63b30b19d512771e01e86d
--- /dev/null
+++ b/__tests__/src/components/ErrorDialog.test.js
@@ -0,0 +1,43 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { ErrorDialog } from '../../../src/components/ErrorDialog';
+
+/**
+ * Helper function to create a shallow wrapper around ErrorDialog
+ */
+function createWrapper(props) {
+  return shallow(
+    <ErrorDialog
+      t={key => key}
+      {...props}
+    />,
+  );
+}
+
+describe('ErrorDialog', () => {
+  let wrapper;
+
+  it('renders properly', () => {
+    const errors = { testid123: { id: 'testid123', message: '' } };
+
+    wrapper = createWrapper({ errors });
+    expect(wrapper.find('WithStyles(Dialog)').length).toBe(1);
+  });
+
+  it('shows up error message correctly', () => {
+    const errorMessage = 'error testMessage 123';
+    const errors = { testid123: { id: 'testid123', message: errorMessage } };
+
+    wrapper = createWrapper({ errors });
+    expect(wrapper.find('WithStyles(Typography)[variant="body2"]').render().text()).toBe(errorMessage);
+  });
+
+  it('triggers the handleClick prop when clicking the ok button', () => {
+    const errors = { testid123: { id: 'testid123', message: '' } };
+    const mockHandleClick = jest.fn();
+
+    wrapper = createWrapper({ errors, removeError: mockHandleClick });
+    wrapper.find('WithStyles(Button)').simulate('click');
+    expect(mockHandleClick).toHaveBeenCalledTimes(1);
+  });
+});
diff --git a/__tests__/src/components/WorkspaceArea.test.js b/__tests__/src/components/WorkspaceArea.test.js
index be8d0fc0725b05c9ac2f90e1ba194753e7460649..e03f8fe6d2af2cec851c1f2c7d7fb81ff9fe7d68 100644
--- a/__tests__/src/components/WorkspaceArea.test.js
+++ b/__tests__/src/components/WorkspaceArea.test.js
@@ -3,6 +3,7 @@ import { shallow } from 'enzyme';
 import WorkspaceControlPanel from '../../../src/containers/WorkspaceControlPanel';
 import Workspace from '../../../src/containers/Workspace';
 import WorkspaceAdd from '../../../src/containers/WorkspaceAdd';
+import ErrorDialog from '../../../src/containers/ErrorDialog';
 import { WorkspaceArea } from '../../../src/components/WorkspaceArea';
 
 /** */
@@ -29,6 +30,7 @@ describe('WorkspaceArea', () => {
       <main>
         <WorkspaceControlPanel />
         <Workspace />
+        <ErrorDialog />
       </main>,
     )).toBeTruthy();
   });
diff --git a/__tests__/src/reducers/config.test.js b/__tests__/src/reducers/config.test.js
index 9c53c62eea778dfa844f1c393d0c4fd8533ed18a..e451169ffa8e582e23b8fd46608243e1c8f352e0 100644
--- a/__tests__/src/reducers/config.test.js
+++ b/__tests__/src/reducers/config.test.js
@@ -1,5 +1,6 @@
 import { configReducer } from '../../../src/state/reducers/config';
 import ActionTypes from '../../../src/state/actions/action-types';
+import configFixture from '../../fixtures/config/export.example.json';
 
 describe('config reducer', () => {
   describe('SET_CONFIG', () => {
@@ -42,4 +43,12 @@ describe('config reducer', () => {
       });
     });
   });
+  describe('IMPORT_CONFIG', () => {
+    it('should handle IMPORT_CONFIG', () => {
+      expect(configReducer([], {
+        config: configFixture,
+        type: ActionTypes.IMPORT_CONFIG,
+      })).toEqual(configFixture);
+    });
+  });
 });
diff --git a/__tests__/src/reducers/errors.test.js b/__tests__/src/reducers/errors.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..3a3923eaa4d1f40d3cc6a46a236b254769e422cd
--- /dev/null
+++ b/__tests__/src/reducers/errors.test.js
@@ -0,0 +1,42 @@
+
+import { errorsReducer } from '../../../src/state/reducers/errors';
+import ActionTypes from '../../../src/state/actions/action-types';
+
+describe('ADD_ERROR', () => {
+  const errorMessage = 'testErrorMessage';
+  const errorId = 'errorId123';
+
+  it('should handle ADD_ERROR', () => {
+    const error = {
+      id: errorId,
+      message: errorMessage,
+    };
+    const ret = errorsReducer(undefined, {
+      type: ActionTypes.ADD_ERROR,
+      ...error,
+
+    });
+    expect(ret.items).toEqual([error.id]);
+    expect(ret).toHaveProperty(error.id);
+    expect(ret[error.id]).toEqual(error);
+  });
+
+  it('should handle REMOVE_ERROR', () => {
+    const stateBefore = {
+      errorId: {
+        id: errorId,
+        message: errorMessage,
+      },
+      items: [errorId],
+    };
+
+    /*
+      Only the id is removed from the 'items' array. The error itself remains part of the state,
+      so we are able to provide an error history or some kind of logs later on
+    */
+    expect(errorsReducer(stateBefore, {
+      id: errorId,
+      type: ActionTypes.REMOVE_ERROR,
+    })).toHaveProperty('items', []);
+  });
+});
diff --git a/package.json b/package.json
index f8874daaba988e15c01f7a3eacebf55c86aae10b..7e3d3f7141fc7d9e23035de012817cd4bec0b4d8 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
   "repository": "https://github.com/ProjectMirador/mirador",
   "size-limit": [
     {
-      "limit": "360 KB",
+      "limit": "390 KB",
       "path": "dist/mirador.min.js"
     }
   ],
diff --git a/src/components/ErrorDialog.js b/src/components/ErrorDialog.js
new file mode 100644
index 0000000000000000000000000000000000000000..d2d6eff2565bbeb4ef4bb3d6003dfa77b427af43
--- /dev/null
+++ b/src/components/ErrorDialog.js
@@ -0,0 +1,63 @@
+import React, { Component } from 'react';
+import Dialog from '@material-ui/core/Dialog';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import PropTypes from 'prop-types';
+import { Typography } from '@material-ui/core';
+import Button from '@material-ui/core/Button';
+import {
+  first,
+  isUndefined,
+  omit,
+  values,
+} from 'lodash';
+
+/**
+ */
+export class ErrorDialog extends Component {
+  /**
+   * render
+   * @return
+   */
+  render() {
+    const {
+      errors, removeError, t,
+    } = this.props;
+
+    /* extract 'items' value and get first key-value-pair (an error) */
+    const error = first(values(omit(errors, 'items')));
+    const hasError = !isUndefined(error);
+
+    return (
+      <div>
+        { hasError && (
+          <Dialog onClose={() => removeError(error.id)} open={hasError}>
+            <DialogTitle>{t('errorDialogTitle')}</DialogTitle>
+            <DialogContent>
+              <Typography variant="body2" noWrap color="inherit">
+                {error.message}
+              </Typography>
+              <div>
+                <Button onClick={() => removeError(error.id)}>
+                  {t('errorDialogConfirm')}
+                </Button>
+              </div>
+            </DialogContent>
+          </Dialog>
+        )}
+      </div>
+    );
+  }
+}
+
+ErrorDialog.propTypes = {
+  errors: PropTypes.object, // eslint-disable-line react/forbid-prop-types
+  removeError: PropTypes.func,
+  t: PropTypes.func,
+};
+
+ErrorDialog.defaultProps = {
+  errors: null,
+  removeError: () => {},
+  t: key => key,
+};
diff --git a/src/components/WorkspaceArea.js b/src/components/WorkspaceArea.js
index 045b5fe7b6b57e20068ac3ca0ed7e2ae4440cdf2..4bff978fa9c90aa56c2d51c880614db3df9fd53d 100644
--- a/src/components/WorkspaceArea.js
+++ b/src/components/WorkspaceArea.js
@@ -1,6 +1,7 @@
 import React, { Component } from 'react';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
+import ErrorDialog from '../containers/ErrorDialog';
 import WorkspaceControlPanel from '../containers/WorkspaceControlPanel';
 import Workspace from '../containers/Workspace';
 import WorkspaceAdd from '../containers/WorkspaceAdd';
@@ -30,7 +31,8 @@ export class WorkspaceArea extends Component {
           isWorkspaceAddVisible
             ? <WorkspaceAdd />
             : <Workspace />
-         }
+        }
+        <ErrorDialog />
       </main>
     );
   }
diff --git a/src/components/WorkspaceExport.js b/src/components/WorkspaceExport.js
index 1bc968fe519b937640fd0085501f633bbb178768..c4143585eb569aecf54525798dfe6476260f25cd 100644
--- a/src/components/WorkspaceExport.js
+++ b/src/components/WorkspaceExport.js
@@ -13,11 +13,20 @@ export class WorkspaceExport extends Component {
    */
   exportableState() {
     const { state } = this.props;
-    const { config, windows } = state;
+    const {
+      companionWindows,
+      config,
+      viewers,
+      windows,
+      workspace,
+    } = state;
 
     return JSON.stringify({
+      companionWindows,
       config,
+      viewers,
       windows,
+      workspace,
     }, null, 2);
   }
 
diff --git a/src/components/WorkspaceImport.js b/src/components/WorkspaceImport.js
new file mode 100644
index 0000000000000000000000000000000000000000..3f6d6dd8fd3bd223c5887823dd20224bf9c1856a
--- /dev/null
+++ b/src/components/WorkspaceImport.js
@@ -0,0 +1,88 @@
+import React, { Component } from 'react';
+import Dialog from '@material-ui/core/Dialog';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import PropTypes from 'prop-types';
+import { Input } from '@material-ui/core';
+import Button from '@material-ui/core/Button';
+
+/**
+ */
+export class WorkspaceImport extends Component {
+  /**
+   *
+   * constructor
+   */
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      configImportValue: '',
+    };
+
+    this.handleClick = this.handleClick.bind(this);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  /**
+   * @private
+   */
+  handleChange(event) {
+    event.preventDefault();
+    this.setState({
+      configImportValue: event.target.value,
+    });
+  }
+
+  /**
+   * @private
+   */
+  handleClick(event) {
+    const { importConfig } = this.props;
+    const { configImportValue } = this.state;
+    event.preventDefault();
+    try {
+      const configJSON = JSON.parse(configImportValue);
+      importConfig(configJSON);
+    } catch (ex) {
+      const { addError } = this.props;
+      addError(ex.toString());
+    }
+  }
+
+  /**
+   * render
+   * @return
+   */
+  render() {
+    const {
+      handleClose, open, t,
+    } = this.props;
+    return (
+      <Dialog id="workspace-import" open={open} onClose={handleClose}>
+        <DialogTitle id="workspace-import-title">{t('import')}</DialogTitle>
+        <DialogContent>
+          <Input id="workspace-import-input" rows="15" multiline variant="filled" onChange={this.handleChange} />
+          <div>
+            <Button onClick={this.handleClick}>
+              {t('importWorkspace')}
+            </Button>
+          </div>
+        </DialogContent>
+      </Dialog>
+    );
+  }
+}
+
+WorkspaceImport.propTypes = {
+  addError: PropTypes.func.isRequired,
+  handleClose: PropTypes.func.isRequired,
+  importConfig: PropTypes.func.isRequired, // eslint-disable-line react/forbid-prop-types
+  open: PropTypes.bool, // eslint-disable-line react/forbid-prop-types
+  t: PropTypes.func,
+};
+
+WorkspaceImport.defaultProps = {
+  open: false,
+  t: key => key,
+};
diff --git a/src/components/WorkspaceMenu.js b/src/components/WorkspaceMenu.js
index 535cdf244899979eb00324d12d08f211153e25bf..daf3f9cde15ec6acbb7059117ad074f82be4193d 100644
--- a/src/components/WorkspaceMenu.js
+++ b/src/components/WorkspaceMenu.js
@@ -1,5 +1,6 @@
 import React, { Component } from 'react';
 import Menu from '@material-ui/core/Menu';
+import ImportIcon from '@material-ui/icons/Input';
 import ListItemIcon from '@material-ui/core/ListItemIcon';
 import MenuItem from '@material-ui/core/MenuItem';
 import Typography from '@material-ui/core/Typography';
@@ -12,6 +13,7 @@ import WindowList from '../containers/WindowList';
 import WorkspaceSettings from '../containers/WorkspaceSettings';
 import WorkspaceSelectionDialog from '../containers/WorkspaceSelectionDialog';
 import WorkspaceExport from '../containers/WorkspaceExport';
+import WorkspaceImport from '../containers/WorkspaceImport';
 import ns from '../config/css-ns';
 
 /**
@@ -24,6 +26,7 @@ export class WorkspaceMenu extends Component {
     super(props);
     this.state = {
       exportWorkspace: {},
+      importWorkspace: {},
       settings: {},
       toggleZoom: {},
       windowList: {},
@@ -79,6 +82,7 @@ export class WorkspaceMenu extends Component {
     } = this.props;
 
     const {
+      importWorkspace,
       windowList,
       toggleZoom,
       settings,
@@ -155,6 +159,17 @@ export class WorkspaceMenu extends Component {
             </ListItemIcon>
             <Typography variant="body1">{t('downloadExportWorkspace')}</Typography>
           </MenuItem>
+          <MenuItem
+            aria-haspopup="true"
+            id="workspace-menu-import"
+            onClick={(e) => { this.handleMenuItemClick('importWorkspace', e); handleClose(e); }}
+            aria-owns={exportWorkspace.AnchorEl ? 'workspace-import' : undefined}
+          >
+            <ListItemIcon>
+              <ImportIcon />
+            </ListItemIcon>
+            <Typography variant="body1">{t('importWorkspace')}</Typography>
+          </MenuItem>
         </Menu>
         <WindowList
           anchorEl={windowList.anchorEl}
@@ -180,6 +195,11 @@ export class WorkspaceMenu extends Component {
           container={container}
           handleClose={this.handleMenuItemClose('exportWorkspace')}
         />
+        <WorkspaceImport
+          open={Boolean(importWorkspace.open)}
+          container={container}
+          handleClose={this.handleMenuItemClose('importWorkspace')}
+        />
       </>
     );
   }
diff --git a/src/components/index.js b/src/components/index.js
index f9a96ce3a5274885ef34cba969637b6563bdb1b7..884ea2a8c43f62e145c3fad4e9340574d90e1891 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -1,6 +1,7 @@
 export * from './App';
 export * from './CanvasThumbnail';
 export * from './CompanionWindow';
+export * from './ErrorDialog';
 export * from './LabelValueMetadata';
 export * from './LanguageSettings';
 export * from './ManifestForm';
@@ -33,6 +34,7 @@ export * from './WorkspaceControlPanel';
 export * from './WorkspaceControlPanelButtons';
 export * from './WorkspaceExport';
 export * from './WorkspaceFullScreenButton';
+export * from './WorkspaceImport';
 export * from './WorkspaceMenu';
 export * from './WorkspaceMenuButton';
 export * from './WorkspaceMosaic';
diff --git a/src/containers/CompanionArea.js b/src/containers/CompanionArea.js
index 11d8a12cb5a1356e49f64281f3cea7998b21ff25..8b30b05f486be83770255eee007b03e2ec21bb7f 100644
--- a/src/containers/CompanionArea.js
+++ b/src/containers/CompanionArea.js
@@ -11,7 +11,7 @@ import { CompanionArea } from '../components/CompanionArea';
 const mapStateToProps = (state, { windowId, position }) => ({
   companionAreaOpen: getCompanionAreaVisibility(state, { position, windowId }),
   companionWindows: getCompanionWindowsOfWindow(state, { windowId })
-    .filter(cw => cw.position === position),
+    .filter(cw => cw && cw.position === position),
   sideBarOpen: getWindow(state, { windowId }).sideBarOpen,
 });
 
diff --git a/src/containers/ErrorDialog.js b/src/containers/ErrorDialog.js
new file mode 100644
index 0000000000000000000000000000000000000000..b2993b8f451c2747d799fe08acc279ccd5e6d125
--- /dev/null
+++ b/src/containers/ErrorDialog.js
@@ -0,0 +1,32 @@
+import { compose } from 'redux';
+import { connect } from 'react-redux';
+import { withTranslation } from 'react-i18next';
+import { withPlugins } from '../extend';
+import { ErrorDialog } from '../components/ErrorDialog';
+import * as actions from '../state/actions';
+
+/**
+ * mapStateToProps - to hook up connect
+ * @memberof ErrorDialog
+ * @private
+ */
+const mapStateToProps = state => ({
+  errors: state.errors,
+});
+
+/**
+ * mapDispatchToProps - used to hook up connect to action creators
+ * @memberof App
+ * @private
+ */
+const mapDispatchToProps = {
+  removeError: actions.removeError,
+};
+
+const enhance = compose(
+  withTranslation(),
+  connect(mapStateToProps, mapDispatchToProps),
+  withPlugins('ErrorDialog'),
+);
+
+export default enhance(ErrorDialog);
diff --git a/src/containers/ThumbnailNavigation.js b/src/containers/ThumbnailNavigation.js
index c570e094d59741bc2aa02781e7618020c4229c40..d87b0a39fa7aa644e30d971f1bd5959c98fd78e2 100644
--- a/src/containers/ThumbnailNavigation.js
+++ b/src/containers/ThumbnailNavigation.js
@@ -6,7 +6,9 @@ import { withPlugins } from '../extend';
 import CanvasGroupings from '../lib/CanvasGroupings';
 import * as actions from '../state/actions';
 import { ThumbnailNavigation } from '../components/ThumbnailNavigation';
-import { getWindow, getManifestCanvases } from '../state/selectors';
+import { getWindow } from '../state/selectors/windows';
+import { getManifestCanvases } from '../state/selectors/manifests';
+
 /**
  * mapStateToProps - used to hook up state to props
  * @memberof ThumbnailNavigation
diff --git a/src/containers/WorkspaceImport.js b/src/containers/WorkspaceImport.js
new file mode 100644
index 0000000000000000000000000000000000000000..8386f733233752fe1de5184c6909932345a37eea
--- /dev/null
+++ b/src/containers/WorkspaceImport.js
@@ -0,0 +1,24 @@
+import { compose } from 'redux';
+import { connect } from 'react-redux';
+import { withTranslation } from 'react-i18next';
+import { withPlugins } from '../extend';
+import { WorkspaceImport } from '../components/WorkspaceImport';
+import * as actions from '../state/actions';
+
+/**
+ * mapDispatchToProps - used to hook up connect to action creators
+ * @memberof App
+ * @private
+ */
+const mapDispatchToProps = {
+  addError: actions.addError,
+  importConfig: actions.importWorkspace,
+};
+
+const enhance = compose(
+  withTranslation(),
+  connect(null, mapDispatchToProps),
+  withPlugins('WorkspaceImport'),
+);
+
+export default enhance(WorkspaceImport);
diff --git a/src/containers/WorkspaceMenu.js b/src/containers/WorkspaceMenu.js
index 6ca930ec3e43593e36b0614245282ce2c2954240..d3c1353c77ef475f3ad72fdda043806a9c9b3c00 100644
--- a/src/containers/WorkspaceMenu.js
+++ b/src/containers/WorkspaceMenu.js
@@ -8,7 +8,7 @@ import { WorkspaceMenu } from '../components/WorkspaceMenu';
 
 /**
  * mapDispatchToProps - used to hook up connect to action creators
- * @memberof ManifestListItem
+ * @memberof WorkspaceMenu
  * @private
  */
 const mapDispatchToProps = {
diff --git a/src/locales/de/translation.json b/src/locales/de/translation.json
index 5e54b271541ad590c8643e15a6c65eae9585a8aa..86804652308df1cd5cf2134bb442160474d9f1b9 100644
--- a/src/locales/de/translation.json
+++ b/src/locales/de/translation.json
@@ -21,11 +21,15 @@
     "downloadExport": "Download/Export Arbeitsfläche",
     "downloadExportWorkspace": "Download/Export Arbeitsfläche",
     "elastic": "Elastisch",
+    "errorDialogTitle": "Es ist ein Fehler aufgetreten",
+    "errorDialogConfirm": "OK",
     "exitFullScreen": "Vollbildmodus verlassen",
     "expandSidePanel": "Seitenleiste aufklappen",
     "fetchManifest": "Hinzufügen",
     "gallery": "Galerie",
     "hideZoomControls": "Zoomsteuerung verbergen",
+    "import" : "Import",
+    "importWorkspace": "Import Arbeitsfläche",
     "item": "Objekt: {{label}}",
     "language": "Sprache",
     "light": "Hell",
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index 109791ee5fc09fe3fb407c8d00db64815cf7485b..1c5cb4e5feb71b3436ee69fc999455d54f3bd3a0 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -23,11 +23,16 @@
     "downloadExport": "Download/Export workspace",
     "downloadExportWorkspace": "Download/Export workspace",
     "elastic": "Elastic",
+    "errorDialogConfirm": "OK",
+    "errorDialogTitle": "An error occurred",
     "exitFullScreen": "Exit full screen",
     "expandSidePanel": "Expand sidebar",
     "fetchManifest": "Add",
     "gallery": "Gallery",
+    "fullScreen": "Full Screen",
     "hideZoomControls": "Hide zoom controls",
+    "import" : "Import",
+    "importWorkspace": "Import workspace",
     "item": "Item: {{label}}",
     "language": "Language",
     "light": "Light theme",
diff --git a/src/state/actions/action-types.js b/src/state/actions/action-types.js
index 65170e606c8a8744480580726528edf31801791a..1d33453a6fccce38706d739ed3ded3dfcfca4b3e 100644
--- a/src/state/actions/action-types.js
+++ b/src/state/actions/action-types.js
@@ -18,6 +18,8 @@ const ActionTypes = {
   TOGGLE_WORKSPACE_EXPOSE_MODE: 'TOGGLE_WORKSPACE_EXPOSE_MODE',
   ADD_MANIFEST: 'ADD_MANIFEST',
   ADD_WINDOW: 'ADD_WINDOW',
+  ADD_ERROR: 'ADD_ERROR',
+  IMPORT_CONFIG: 'IMPORT_CONFIG',
   SET_CANVAS: 'SET_CANVAS',
   MAXIMIZE_WINDOW: 'MAXIMIZE_WINDOW',
   MINIMIZE_WINDOW: 'MINIMIZE_WINDOW',
@@ -28,6 +30,7 @@ const ActionTypes = {
   REQUEST_MANIFEST: 'REQUEST_MANIFEST',
   RECEIVE_MANIFEST: 'RECEIVE_MANIFEST',
   RECEIVE_MANIFEST_FAILURE: 'RECEIVE_MANIFEST_FAILURE',
+  REMOVE_ERROR: 'REMOVE_ERROR',
   SET_CONFIG: 'SET_CONFIG',
   SET_WINDOW_THUMBNAIL_POSITION: 'SET_WINDOW_THUMBNAIL_POSITION',
   SET_WINDOW_VIEW_TYPE: 'SET_WINDOW_VIEW_TYPE',
diff --git a/src/state/actions/config.js b/src/state/actions/config.js
index 5bbbd335ac5c4ab8f016973d531b6772135c7642..827a48497649b72cb3b80f791573c2b51d1eea67 100644
--- a/src/state/actions/config.js
+++ b/src/state/actions/config.js
@@ -1,10 +1,20 @@
 import ActionTypes from './action-types';
 
+/**
+ * importConfig - action creator
+ *
+ * @param  {Object} config
+ * @memberof ActionCreators
+ */
+export function importConfig(config) {
+  return { config, type: ActionTypes.IMPORT_CONFIG };
+}
+
 /**
  * setConfig - action creator
  *
  * @param  {Object} config
-* @memberof ActionCreators
+ * @memberof ActionCreators
  */
 export function setConfig(config) {
   return { config, type: ActionTypes.SET_CONFIG };
@@ -14,7 +24,7 @@ export function setConfig(config) {
  * updateConfig - action creator
  *
  * @param  {Object} config
-* @memberof ActionCreators
+ * @memberof ActionCreators
  */
 export function updateConfig(config) {
   return { config, type: ActionTypes.UPDATE_CONFIG };
diff --git a/src/state/actions/errors.js b/src/state/actions/errors.js
new file mode 100644
index 0000000000000000000000000000000000000000..5c1ee22f238379b3163812e56e2c2bafef791397
--- /dev/null
+++ b/src/state/actions/errors.js
@@ -0,0 +1,22 @@
+import uuid from 'uuid/v4';
+import ActionTypes from './action-types';
+
+/**
+ * addError - action creator
+ * @param {string} error
+ */
+export function addError(error) {
+  return {
+    id: `error-${uuid()}`,
+    message: error,
+    type: ActionTypes.ADD_ERROR,
+  };
+}
+
+/**
+ * removeError - action creator
+ * @param {string} id
+ */
+export function removeError(id) {
+  return { id, type: ActionTypes.REMOVE_ERROR };
+}
diff --git a/src/state/actions/index.js b/src/state/actions/index.js
index 9465bc715a3c952c12b4ac7a98b8f0daa232e9db..7e792ec59e36944e38050bfe81894f37258c515f 100644
--- a/src/state/actions/index.js
+++ b/src/state/actions/index.js
@@ -4,6 +4,7 @@
  */
 export * from './companionWindow';
 export * from './config';
+export * from './errors';
 export * from './window';
 export * from './manifest';
 export * from './infoResponse';
diff --git a/src/state/actions/window.js b/src/state/actions/window.js
index e925af90750b16925f0752407f8576af1a37cbea..6acea0fe1767d589a96e0b28da6938636184296c 100644
--- a/src/state/actions/window.js
+++ b/src/state/actions/window.js
@@ -69,11 +69,13 @@ export function addWindow(options) {
       companionWindows: [
         {
           content: 'info',
+          default: true,
           id: cwDefault,
           position: 'left',
         },
         {
           content: 'thumbnail_navigation',
+          default: true,
           id: cwThumbs,
           position: options.thumbnailNavigationPosition
             || config.thumbnailNavigation.defaultPosition,
diff --git a/src/state/actions/workspace.js b/src/state/actions/workspace.js
index 783ab5bdb14f680e85b20fd7d75bcdb436e2dd3b..b7f0cc5a3b4683c375680be46110cc28e3027eea 100644
--- a/src/state/actions/workspace.js
+++ b/src/state/actions/workspace.js
@@ -1,4 +1,16 @@
+import {
+  difference,
+  keys,
+  omit,
+  slice,
+  values,
+} from 'lodash';
 import ActionTypes from './action-types';
+import { importConfig } from './config';
+import { addWindow, removeWindow, updateWindow } from './window';
+import { addCompanionWindow, removeCompanionWindow, updateCompanionWindow } from './companionWindow';
+import { updateViewport } from './canvas';
+import { fetchManifest } from './manifest';
 
 /**
  * setWorkspaceFullscreen - action creator
@@ -85,3 +97,95 @@ export function toggleWorkspaceExposeMode() {
     type: ActionTypes.TOGGLE_WORKSPACE_EXPOSE_MODE,
   };
 }
+
+/**
+ * importWorkspace - action creator
+ */
+export function importWorkspace(stateExport) {
+  return (dispatch, getState) => {
+    const { viewers } = stateExport || {};
+    const { companionWindows } = stateExport || {};
+    const {
+      exposeModeOn,
+      height,
+      viewportPosition,
+      width,
+    } = stateExport.workspace;
+
+    const imWins = values(stateExport.windows);
+    const exWins = values(getState().windows);
+    const exWinCnt = exWins.length > imWins.length ? imWins.length : exWins.length;
+
+    /* do window independent stuff at first */
+    dispatch(importConfig(stateExport.config));
+    getState().workspace.exposeModeOn !== exposeModeOn && dispatch(toggleWorkspaceExposeMode());
+    dispatch(setWorkspaceViewportDimensions({ height, width }));
+    dispatch(setWorkspaceViewportPosition(viewportPosition));
+
+    /* now import the windows */
+
+    /*
+      If the existing workspace already contains windows (exWins),
+      we can re-use them in order to optimize the performance.
+      As we only can only re-use the amount of windows to be imported maximally,
+      slice all additional windows before
+    */
+    const exIds = slice(exWins, 0, exWinCnt).map((exWin) => {
+      const imWin = imWins.shift();
+      const viewer = viewers[imWin.id];
+      dispatch(fetchManifest(imWin.manifestId));
+      /* remove exisiting companionWindows, except the ones marked as default */
+      exWin.companionWindowIds
+        .filter(cwId1 => !getState().companionWindows[cwId1].default)
+        .map(cwId2 => dispatch(removeCompanionWindow(exWin.id, cwId2)));
+
+      /* update window */
+      dispatch(updateWindow(exWin.id, omit(imWin, 'id', 'companionWindowIds', 'thumbnailNavigationId')));
+
+      /* update default companionWindows */
+      exWin.companionWindowIds
+        // eslint-disable-next-line max-len
+        .filter(cwId => getState().companionWindows[cwId] && getState().companionWindows[cwId].default)
+        .map((cwId) => {
+          const newCw = values(companionWindows)
+            .find(cw => cw.default && cw.content === getState().companionWindows[cwId].content);
+          return dispatch(updateCompanionWindow(exWin.id, cwId, omit(newCw, 'id')));
+        });
+
+      /* create non-default companion windows */
+      imWin.companionWindowIds
+        .filter(cwId => !companionWindows[cwId].default)
+        .map(cwId => dispatch(addCompanionWindow(exWin.id, omit(companionWindows[cwId], 'id'))));
+      dispatch(updateViewport(exWin.id, viewer));
+      return exWin.id;
+    });
+
+    /* create new windows for additionally imported ones */
+    const imIds = imWins.map((imWin) => {
+      const viewer = viewers[imWin.id];
+
+      dispatch(fetchManifest(imWin.manifestId));
+      dispatch(addWindow(omit(imWin, ['companionWindowIds', 'thumbnailNavigationId'])));
+      dispatch(updateViewport(imWin.id, viewer));
+
+      /* create non-default companion windows */
+      values(companionWindows)
+        .filter(cw => !cw.default)
+        .map(cw => dispatch(addCompanionWindow(imWin.id, { ...omit(cw, 'id') }, {})));
+
+      /* update default companion windows */
+      values(companionWindows)
+        .filter(cw => cw.default)
+        .map((cwNew) => {
+          const cwOld = values(getState().companionWindows)
+            .find(el => el.content === cwNew.content);
+          return dispatch(updateCompanionWindow(imWin.id, cwOld.id, omit(cwNew, 'id')));
+        });
+      return imWin.id;
+    });
+
+    /* close surplus windows */
+    difference(keys(getState().windows), exIds.concat(imIds))
+      .map(winId => dispatch(removeWindow(winId)));
+  };
+}
diff --git a/src/state/reducers/config.js b/src/state/reducers/config.js
index 4663b187b4d8e5ad82ad431391d9db65cb7e7c36..f1eecea23dc3dd0039f6bdf6041e9971e7a42957 100644
--- a/src/state/reducers/config.js
+++ b/src/state/reducers/config.js
@@ -7,6 +7,7 @@ import ActionTypes from '../actions/action-types';
 export const configReducer = (state = {}, action) => {
   switch (action.type) {
     case ActionTypes.UPDATE_CONFIG:
+    case ActionTypes.IMPORT_CONFIG:
       return deepmerge(state, action.config);
     case ActionTypes.SET_CONFIG:
       return action.config;
diff --git a/src/state/reducers/errors.js b/src/state/reducers/errors.js
new file mode 100644
index 0000000000000000000000000000000000000000..7cbbd50a4b3f37ef7bd519c50a864a9459088dd3
--- /dev/null
+++ b/src/state/reducers/errors.js
@@ -0,0 +1,26 @@
+import without from 'lodash/without';
+import ActionTypes from '../actions/action-types';
+
+const defaultState = { items: [] };
+
+/**
+ * errorsReducer
+ */
+export const errorsReducer = (state = defaultState, action) => {
+  let ret;
+  switch (action.type) {
+    case ActionTypes.ADD_ERROR:
+      return { ...state, [action.id]: { id: action.id, message: action.message }, items: [...state.items, action.id] }; // eslint-disable-line max-len
+    case ActionTypes.REMOVE_ERROR:
+      ret = Object.keys(state).reduce((object, key) => {
+        if (key !== action.id) {
+          object[key] = state[key]; // eslint-disable-line no-param-reassign
+        }
+        return object;
+      }, {});
+      ret.items = without(ret.items, action.id);
+      return ret;
+    default:
+      return state;
+  }
+};
diff --git a/src/state/reducers/index.js b/src/state/reducers/index.js
index 481f808243359fe4fe7b9d1038e7e2c26e5eb3de..66a5ad6ea91152e0042320972d01e8ca139975a8 100644
--- a/src/state/reducers/index.js
+++ b/src/state/reducers/index.js
@@ -1,4 +1,5 @@
 export * from './companionWindows';
+export * from './errors';
 export * from './workspace';
 export * from './windows';
 export * from './manifests';
diff --git a/src/state/reducers/rootReducer.js b/src/state/reducers/rootReducer.js
index 49c3ec0f3bd1314c34d54ef17e29b4ba65d18116..f458e1bc683aaa27b849c3b3bad72a2b0151336c 100644
--- a/src/state/reducers/rootReducer.js
+++ b/src/state/reducers/rootReducer.js
@@ -2,6 +2,7 @@ import { combineReducers } from 'redux';
 import {
   companionWindowsReducer,
   configReducer,
+  errorsReducer,
   infoResponsesReducer,
   manifestsReducer,
   viewersReducer,
@@ -20,6 +21,7 @@ export default function createRootReducer(pluginReducers) {
     annotations: annotationsReducer,
     companionWindows: companionWindowsReducer,
     config: configReducer,
+    errors: errorsReducer,
     infoResponses: infoResponsesReducer,
     manifests: manifestsReducer,
     viewers: viewersReducer,
diff --git a/src/state/selectors/workspace.js b/src/state/selectors/workspace.js
index c07011a8891290975e027d83f63d40d10eb768ee..a52fc9d6048af6305dc72af7f2d512f2a273df91 100644
--- a/src/state/selectors/workspace.js
+++ b/src/state/selectors/workspace.js
@@ -9,3 +9,10 @@ export const getFullScreenEnabled = createSelector(
   [getWorkspace],
   workspace => workspace.isFullscreenEnabled,
 );
+
+/** Returns the latest error from the state
+ * @param {object} state
+ */
+export function getLatestError(state) {
+  return state.errors.items[0] && state.errors[state.errors.items[0]];
+}