diff --git a/__tests__/src/components/CaptionedCanvasThumbnail.test.js b/__tests__/src/components/CaptionedCanvasThumbnail.test.js
index fc97e2d1614d6f56e0ce4e64bc9b41933fbafd13..82d2c7411ff9249993191b4190e7fb9c67ec0317 100644
--- a/__tests__/src/components/CaptionedCanvasThumbnail.test.js
+++ b/__tests__/src/components/CaptionedCanvasThumbnail.test.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import { shallow } from 'enzyme';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import Typography from '@material-ui/core/Typography';
 import { CaptionedCanvasThumbnail } from '../../../src/components/CaptionedCanvasThumbnail';
 import manifestJson from '../../fixtures/version-2/019.json';
@@ -9,7 +9,7 @@ import manifestJson from '../../fixtures/version-2/019.json';
 function createWrapper(props) {
   return shallow(
     <CaptionedCanvasThumbnail
-      canvas={manifesto.create(manifestJson).getSequences()[0].getCanvases()[0]}
+      canvas={Utils.parseManifest(manifestJson).getSequences()[0].getCanvases()[0]}
       classes={{}}
       height={100}
       {...props}
diff --git a/__tests__/src/components/GalleryView.test.js b/__tests__/src/components/GalleryView.test.js
index 84a2c03b976bcb70edc3698c30af368f19ccfe1d..ba03ef2c10805ee236f43faffb7ff0d4ad38abe6 100644
--- a/__tests__/src/components/GalleryView.test.js
+++ b/__tests__/src/components/GalleryView.test.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import { shallow } from 'enzyme';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import Paper from '@material-ui/core/Paper';
 import manifestJson from '../../fixtures/version-2/019.json';
 import { GalleryView } from '../../../src/components/GalleryView';
@@ -10,7 +10,7 @@ import GalleryViewThumbnail from '../../../src/containers/GalleryViewThumbnail';
 function createWrapper(props) {
   return shallow(
     <GalleryView
-      canvases={manifesto.create(manifestJson).getSequences()[0].getCanvases()}
+      canvases={Utils.parseManifest(manifestJson).getSequences()[0].getCanvases()}
       windowId="1234"
       selectedCanvasIndex={0}
       {...props}
diff --git a/__tests__/src/components/GalleryViewThumbnail.test.js b/__tests__/src/components/GalleryViewThumbnail.test.js
index 9c895fdbf2643e3bf68a1144c47ae4a202d6f45c..8001e201d4e09a62890bba48cf66f12802ec0c09 100644
--- a/__tests__/src/components/GalleryViewThumbnail.test.js
+++ b/__tests__/src/components/GalleryViewThumbnail.test.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import { shallow } from 'enzyme';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import Chip from '@material-ui/core/Chip';
 import Typography from '@material-ui/core/Typography';
 import manifestJson from '../../fixtures/version-2/019.json';
@@ -11,7 +11,7 @@ import { CanvasThumbnail } from '../../../src/components/CanvasThumbnail';
 function createWrapper(props) {
   return shallow(
     <GalleryViewThumbnail
-      canvas={manifesto.create(manifestJson).getSequences()[0].getCanvases()[0]}
+      canvas={Utils.parseManifest(manifestJson).getSequences()[0].getCanvases()[0]}
       classes={{ selected: 'selected' }}
       focusOnCanvas={() => {}}
       setCanvas={() => {}}
diff --git a/__tests__/src/components/OpenSeadragonViewer.test.js b/__tests__/src/components/OpenSeadragonViewer.test.js
index 95e57905fa24a39028cbe0659b26e8604a7c0a57..b63427b1723e0c4f96f2aed31dedecc63a285cc6 100644
--- a/__tests__/src/components/OpenSeadragonViewer.test.js
+++ b/__tests__/src/components/OpenSeadragonViewer.test.js
@@ -1,14 +1,14 @@
 import React from 'react';
 import { shallow } from 'enzyme';
 import OpenSeadragon from 'openseadragon';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import { OpenSeadragonViewer } from '../../../src/components/OpenSeadragonViewer';
 import OpenSeadragonCanvasOverlay from '../../../src/lib/OpenSeadragonCanvasOverlay';
 import AnnotationList from '../../../src/lib/AnnotationList';
 import CanvasWorld from '../../../src/lib/CanvasWorld';
 import fixture from '../../fixtures/version-2/019.json';
 
-const canvases = manifesto.create(fixture).getSequences()[0].getCanvases();
+const canvases = Utils.parseManifest(fixture).getSequences()[0].getCanvases();
 
 jest.mock('openseadragon');
 jest.mock('../../../src/lib/OpenSeadragonCanvasOverlay');
diff --git a/__tests__/src/components/SidebarIndexList.test.js b/__tests__/src/components/SidebarIndexList.test.js
index e03d5e02000edbf9200fb6a8c1960274e15b6d77..e9dc5968654ed64f8618c9f988872aa47f2f4ecf 100644
--- a/__tests__/src/components/SidebarIndexList.test.js
+++ b/__tests__/src/components/SidebarIndexList.test.js
@@ -2,7 +2,7 @@ import React from 'react';
 import { shallow } from 'enzyme';
 import List from '@material-ui/core/List';
 import ListItem from '@material-ui/core/ListItem';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import { SidebarIndexList } from '../../../src/components/SidebarIndexList';
 import SidebarIndexThumbnail from '../../../src/containers/SidebarIndexThumbnail';
 import SidebarIndexCompact from '../../../src/containers/SidebarIndexCompact';
@@ -12,7 +12,7 @@ import manifestJson from '../../fixtures/version-2/019.json';
  * Helper function to create a shallow wrapper around SidebarIndexList
  */
 function createWrapper(props) {
-  const canvases = manifesto.create(manifestJson).getSequences()[0].getCanvases();
+  const canvases = Utils.parseManifest(manifestJson).getSequences()[0].getCanvases();
 
   return shallow(
     <SidebarIndexList
@@ -62,8 +62,8 @@ describe('SidebarIndexList', () => {
 
   describe('getIdAndLabelOfCanvases', () => {
     it('should return id and label of each canvas in manifest', () => {
-      const canvases = manifesto
-        .create(manifestJson)
+      const canvases = Utils
+        .parseManifest(manifestJson)
         .getSequences()[0]
         .getCanvases();
       const wrapper = createWrapper({ canvases });
diff --git a/__tests__/src/components/SidebarIndexThumbnail.test.js b/__tests__/src/components/SidebarIndexThumbnail.test.js
index e6316d504259acda21c1f7dfe647b0f9496fc68d..0d5226a5e05b1bf7bb433ee3d8508c604ddef8f9 100644
--- a/__tests__/src/components/SidebarIndexThumbnail.test.js
+++ b/__tests__/src/components/SidebarIndexThumbnail.test.js
@@ -1,7 +1,7 @@
 import React from 'react';
 import { shallow } from 'enzyme';
 import Typography from '@material-ui/core/Typography';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import fixture from '../../fixtures/version-2/019.json';
 import { SidebarIndexThumbnail } from '../../../src/components/SidebarIndexThumbnail';
 import { CanvasThumbnail } from '../../../src/components/CanvasThumbnail';
@@ -11,7 +11,7 @@ function createWrapper(props) {
   return shallow(
     <SidebarIndexThumbnail
       canvas={{ label: 'yolo' }}
-      otherCanvas={manifesto.create(fixture).getSequences()[0].getCanvases()[1]}
+      otherCanvas={Utils.parseManifest(fixture).getSequences()[0].getCanvases()[1]}
       classes={{}}
       config={{ canvasNavigation: { height: 200, width: 100 } }}
       {...props}
diff --git a/__tests__/src/components/ThumbnailCanvasGrouping.test.js b/__tests__/src/components/ThumbnailCanvasGrouping.test.js
index fbb4f0b039b172e369de7e2fc2d5615533caf7ee..8bf9cb635bcdbbd83f565f608b5cc96dee7e39e8 100644
--- a/__tests__/src/components/ThumbnailCanvasGrouping.test.js
+++ b/__tests__/src/components/ThumbnailCanvasGrouping.test.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import { shallow } from 'enzyme';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import { ThumbnailCanvasGrouping } from '../../../src/components/ThumbnailCanvasGrouping';
 import CaptionedCanvasThumbnail from '../../../src/containers/CaptionedCanvasThumbnail';
 import CanvasGroupings from '../../../src/lib/CanvasGroupings';
@@ -27,7 +27,7 @@ describe('ThumbnailCanvasGrouping', () => {
   let rightWrapper;
   let setCanvas;
   const data = {
-    canvasGroupings: new CanvasGroupings(manifesto.create(manifestJson)
+    canvasGroupings: new CanvasGroupings(Utils.parseManifest(manifestJson)
       .getSequences()[0].getCanvases()),
     height: 131,
     position: 'far-bottom',
diff --git a/__tests__/src/components/ThumbnailNavigation.test.js b/__tests__/src/components/ThumbnailNavigation.test.js
index 647055868bc4b200aa66a6c4f863530d0bc765ae..e95e81f05a943f7a9cd9870a2af4e8825bf78579 100644
--- a/__tests__/src/components/ThumbnailNavigation.test.js
+++ b/__tests__/src/components/ThumbnailNavigation.test.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import { shallow } from 'enzyme';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import { ThumbnailNavigation } from '../../../src/components/ThumbnailNavigation';
 import ThumbnailCanvasGrouping from '../../../src/containers/ThumbnailCanvasGrouping';
 import CanvasGroupings from '../../../src/lib/CanvasGroupings';
@@ -12,7 +12,7 @@ function createWrapper(props, fixture = manifestJson) {
   return shallow(
     <ThumbnailNavigation
       canvasGroupings={
-        new CanvasGroupings(manifesto.create(fixture).getSequences()[0].getCanvases())
+        new CanvasGroupings(Utils.parseManifest(fixture).getSequences()[0].getCanvases())
       }
       canvasIndex={1}
       classes={{}}
diff --git a/__tests__/src/components/WindowAuthenticationControl.test.js b/__tests__/src/components/WindowAuthenticationControl.test.js
index 0a33754371079ca8eb291b6d3b01acefe92d49a8..c7f0fb66e8f96b0ef8e197fcb1aa7f8b22d1c247 100644
--- a/__tests__/src/components/WindowAuthenticationControl.test.js
+++ b/__tests__/src/components/WindowAuthenticationControl.test.js
@@ -18,7 +18,7 @@ function createWrapper(props) {
       handleAuthInteraction={() => {}}
       label="authenticate"
       windowId="w"
-      profile={{ value: 'http://iiif.io/api/auth/1/login' }}
+      profile="http://iiif.io/api/auth/1/login"
       {...props}
     />,
   );
@@ -38,7 +38,7 @@ describe('WindowAuthenticationControl', () => {
         degraded: true,
         failureDescription: 'failure description',
         failureHeader: 'failure header',
-        profile: { value: 'http://iiif.io/api/auth/1/external' },
+        profile: 'http://iiif.io/api/auth/1/external',
         status: 'failed',
       });
       expect(wrapper.find(SanitizedHtml).at(0).props().htmlString).toEqual('failure header');
diff --git a/__tests__/src/components/WindowSideBarCanvasPanel.test.js b/__tests__/src/components/WindowSideBarCanvasPanel.test.js
index 5f6cf795dae618fe313376aee80c827e2418b920..5ab95b6397d6363f309e7c3b322356688324dfa2 100644
--- a/__tests__/src/components/WindowSideBarCanvasPanel.test.js
+++ b/__tests__/src/components/WindowSideBarCanvasPanel.test.js
@@ -2,7 +2,7 @@ import React from 'react';
 import { shallow } from 'enzyme';
 import List from '@material-ui/core/List';
 import ListItem from '@material-ui/core/ListItem';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import { WindowSideBarCanvasPanel } from '../../../src/components/WindowSideBarCanvasPanel';
 import SidebarIndexList from '../../../src/containers/SidebarIndexList';
 import CompanionWindow from '../../../src/containers/CompanionWindow';
@@ -12,7 +12,7 @@ import manifestJson from '../../fixtures/version-2/019.json';
  * Helper function to create a shallow wrapper around WindowSideBarCanvasPanel
  */
 function createWrapper(props) {
-  const canvases = manifesto.create(manifestJson).getSequences()[0].getCanvases();
+  const canvases = Utils.parseManifest(manifestJson).getSequences()[0].getCanvases();
 
   return shallow(
     <WindowSideBarCanvasPanel
diff --git a/__tests__/src/components/WindowViewer.test.js b/__tests__/src/components/WindowViewer.test.js
index df2cd1165cf8525c17d9f66c8f704c46a822bd0d..ba266aaa84c9b219a1e41d06ed427a6cef912139 100644
--- a/__tests__/src/components/WindowViewer.test.js
+++ b/__tests__/src/components/WindowViewer.test.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import { shallow } from 'enzyme';
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import { WindowViewer } from '../../../src/components/WindowViewer';
 import OSDViewer from '../../../src/containers/OpenSeadragonViewer';
 import WindowCanvasNavigationControls from '../../../src/containers/WindowCanvasNavigationControls';
@@ -8,7 +8,7 @@ import fixture from '../../fixtures/version-2/019.json';
 import emptyCanvasFixture from '../../fixtures/version-2/emptyCanvas.json';
 import otherContentFixture from '../../fixtures/version-2/299843.json';
 
-let currentCanvases = manifesto.create(fixture).getSequences()[0].getCanvases();
+let currentCanvases = Utils.parseManifest(fixture).getSequences()[0].getCanvases();
 
 /** create wrapper */
 function createWrapper(props) {
@@ -98,7 +98,7 @@ describe('WindowViewer', () => {
     it('does not call fetchInfoResponse for a canvas that has no images', () => {
       const mockFnCanvas0 = jest.fn();
       const mockFnCanvas2 = jest.fn();
-      const canvases = manifesto.create(emptyCanvasFixture).getSequences()[0].getCanvases();
+      const canvases = Utils.parseManifest(emptyCanvasFixture).getSequences()[0].getCanvases();
 
       currentCanvases = [canvases[0]];
 
@@ -125,7 +125,7 @@ describe('WindowViewer', () => {
     });
     it('calls fetchAnnotation when otherContent is present', () => {
       const mockFnAnno = jest.fn();
-      const canvases = manifesto.create(otherContentFixture).getSequences()[0].getCanvases();
+      const canvases = Utils.parseManifest(otherContentFixture).getSequences()[0].getCanvases();
       currentCanvases = [canvases[0]];
 
       wrapper = createWrapper(
@@ -138,7 +138,7 @@ describe('WindowViewer', () => {
   describe('componentDidUpdate', () => {
     it('does not call fetchInfoResponse for a canvas that has no images', () => {
       const mockFn = jest.fn();
-      const canvases = manifesto.create(emptyCanvasFixture).getSequences()[0].getCanvases();
+      const canvases = Utils.parseManifest(emptyCanvasFixture).getSequences()[0].getCanvases();
       currentCanvases = [canvases[2]];
       wrapper = createWrapper(
         {
diff --git a/__tests__/src/lib/CanvasWorld.test.js b/__tests__/src/lib/CanvasWorld.test.js
index 9433c87736435e82c37a5165c2e3a47807a4e901..921fcc785e4b0d80bde720bc54573576b60ee751 100644
--- a/__tests__/src/lib/CanvasWorld.test.js
+++ b/__tests__/src/lib/CanvasWorld.test.js
@@ -1,8 +1,8 @@
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import fixture from '../../fixtures/version-2/019.json';
 import CanvasWorld from '../../../src/lib/CanvasWorld';
 
-const canvases = manifesto.create(fixture).getSequences()[0].getCanvases();
+const canvases = Utils.parseManifest(fixture).getSequences()[0].getCanvases();
 const canvasSubset = [canvases[1], canvases[2]];
 
 describe('CanvasWorld', () => {
diff --git a/__tests__/src/lib/ManifestoCanvas.test.js b/__tests__/src/lib/ManifestoCanvas.test.js
index 77f4ad15e7d6f6bf2295ab27f8866a594a176118..afc991146488896eb2bde052cd21ccdb6c628b03 100644
--- a/__tests__/src/lib/ManifestoCanvas.test.js
+++ b/__tests__/src/lib/ManifestoCanvas.test.js
@@ -1,4 +1,4 @@
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import ManifestoCanvas from '../../../src/lib/ManifestoCanvas';
 import fixture from '../../fixtures/version-2/019.json';
 import v3fixture from '../../fixtures/version-3/001.json';
@@ -13,10 +13,10 @@ describe('ManifestoCanvas', () => {
   let v3Instance;
   beforeAll(() => {
     instance = new ManifestoCanvas(
-      manifesto.create(fixture).getSequences()[0].getCanvases()[0],
+      Utils.parseManifest(fixture).getSequences()[0].getCanvases()[0],
     );
     v3Instance = new ManifestoCanvas(
-      manifesto.create(v3fixture).getSequences()[0].getCanvases()[0],
+      Utils.parseManifest(v3fixture).getSequences()[0].getCanvases()[0],
     );
   });
   describe('annotationListUris', () => {
@@ -29,7 +29,7 @@ describe('ManifestoCanvas', () => {
       describe('with items as objects', () => {
         it('returns an array of uris', () => {
           const otherContentInstance = new ManifestoCanvas(
-            manifesto.create(otherContentFixture).getSequences()[0].getCanvases()[0],
+            Utils.parseManifest(otherContentFixture).getSequences()[0].getCanvases()[0],
           );
           expect(otherContentInstance.annotationListUris.length).toEqual(1);
           expect(otherContentInstance.annotationListUris).toEqual([
@@ -40,7 +40,7 @@ describe('ManifestoCanvas', () => {
       describe('with items as strings', () => {
         it('returns an array of uris', () => {
           const otherContentInstance = new ManifestoCanvas(
-            manifesto.create(otherContentStringsFixture).getSequences()[0].getCanvases()[0],
+            Utils.parseManifest(otherContentStringsFixture).getSequences()[0].getCanvases()[0],
           );
           expect(otherContentInstance.annotationListUris.length).toEqual(1);
           expect(otherContentInstance.annotationListUris).toEqual([
@@ -66,7 +66,7 @@ describe('ManifestoCanvas', () => {
     describe('v2', () => {
       it('fetches annotations for each annotationList', () => {
         const otherContentInstance = new ManifestoCanvas(
-          manifesto.create(otherContentFixture).getSequences()[0].getCanvases()[0],
+          Utils.parseManifest(otherContentFixture).getSequences()[0].getCanvases()[0],
         );
         const fetchMock = jest.fn();
         otherContentInstance.processAnnotations(fetchMock);
@@ -89,14 +89,14 @@ describe('ManifestoCanvas', () => {
     });
     it('correctly returns an image information url for a v1 Image API', () => {
       const imagev1Instance = new ManifestoCanvas(
-        manifesto.create(imagev1Fixture).getSequences()[0].getCanvases()[0],
+        Utils.parseManifest(imagev1Fixture).getSequences()[0].getCanvases()[0],
       );
       expect(imagev1Instance.imageInformationUri).toEqual('https://images.britishart.yale.edu/iiif/b38081da-8991-4464-a71e-d9891226a35f/info.json');
     });
 
     it('is undefined if a canvas is empty (e.g. has no images)', () => {
       const emptyCanvasInstance = new ManifestoCanvas(
-        manifesto.create(emptyCanvasFixture).getSequences()[0].getCanvases()[3],
+        Utils.parseManifest(emptyCanvasFixture).getSequences()[0].getCanvases()[3],
       );
 
       expect(emptyCanvasInstance.imageInformationUri).toBeUndefined();
@@ -135,7 +135,7 @@ describe('ManifestoCanvas', () => {
 
     it('returns undefined if there are no images to generate a thumbnail from', () => {
       const emptyCanvasInstance = new ManifestoCanvas(
-        manifesto.create(emptyCanvasFixture).getSequences()[0].getCanvases()[3],
+        Utils.parseManifest(emptyCanvasFixture).getSequences()[0].getCanvases()[3],
       );
 
       expect(emptyCanvasInstance.thumbnail()).toBeUndefined();
@@ -144,7 +144,7 @@ describe('ManifestoCanvas', () => {
   describe('service', () => {
     it('correctly returns the service information for the given canvas', () => {
       const serviceInstance = new ManifestoCanvas(
-        manifesto.create(serviceFixture).getSequences()[0].getCanvases()[0],
+        Utils.parseManifest(serviceFixture).getSequences()[0].getCanvases()[0],
       );
 
       expect(serviceInstance.service).toBeDefined();
diff --git a/__tests__/src/lib/MiradorViewer.test.js b/__tests__/src/lib/MiradorViewer.test.js
index 3cef28918d223d1a5abbd575ba78ce5a4fc10361..9fc323aa175430c622076fb35970c78c10d7f6aa 100644
--- a/__tests__/src/lib/MiradorViewer.test.js
+++ b/__tests__/src/lib/MiradorViewer.test.js
@@ -3,7 +3,7 @@ import MiradorViewer from '../../../src/lib/MiradorViewer';
 
 jest.unmock('react-i18next');
 jest.mock('react-dom');
-jest.mock('node-fetch', () => jest.fn(() => Promise.resolve({ json: () => ({}) })));
+jest.mock('isomorphic-unfetch', () => jest.fn(() => Promise.resolve({ json: () => ({}) })));
 
 jest.mock('../../../src/state/selectors', () => ({
   getCompanionWindowIdsForPosition: () => ['cwid'],
diff --git a/__tests__/src/reducers/auth.test.js b/__tests__/src/reducers/auth.test.js
index 62e3fd62841832771de679ceaf35cbba7881726a..151db1096fcc933050ef1506e2c9108034a2ba87 100644
--- a/__tests__/src/reducers/auth.test.js
+++ b/__tests__/src/reducers/auth.test.js
@@ -64,7 +64,7 @@ describe('auth response reducer', () => {
           id: 'auth',
           infoId: ['http://example.com'],
           isFetching: true,
-          profile: { value: 'http://iiif.io/api/auth/1/kiosk' },
+          profile: 'http://iiif.io/api/auth/1/kiosk',
         },
       });
     });
diff --git a/__tests__/src/selectors/manifests.test.js b/__tests__/src/selectors/manifests.test.js
index a27bc2fd8a3dd538e21d60d1ff8deee219834238..d12e32e92cad668c23ce0a979a4016269b9328d0 100644
--- a/__tests__/src/selectors/manifests.test.js
+++ b/__tests__/src/selectors/manifests.test.js
@@ -1,4 +1,4 @@
-import manifesto from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import manifestFixture001 from '../../fixtures/version-2/001.json';
 import manifestFixture002 from '../../fixtures/version-2/002.json';
 import manifestFixture015 from '../../fixtures/version-2/015.json';
@@ -286,7 +286,7 @@ describe('getManifestUrl', () => {
 
 describe('getDestructuredMetadata', () => {
   it('should return the first value of label/value attributes for each object in the array ', () => {
-    const iiifResource = manifesto.create(manifestFixture002);
+    const iiifResource = Utils.parseManifest(manifestFixture002);
     const received = getDestructuredMetadata(iiifResource);
     const expected = [{
       label: 'date',
@@ -297,7 +297,7 @@ describe('getDestructuredMetadata', () => {
   });
 
   it('returns an empty array if there is no metadata', () => {
-    const iiifResource = manifesto.create(manifestFixture019);
+    const iiifResource = Utils.parseManifest(manifestFixture019);
     const received = getDestructuredMetadata(iiifResource);
 
     expect(received).toEqual([]);
@@ -317,7 +317,7 @@ describe('getManifestMetadata', () => {
   });
 
   it('returns an empty array if there is no metadata', () => {
-    const iiifResource = manifesto.create(manifestFixture019);
+    const iiifResource = Utils.parseManifest(manifestFixture019);
     const received = getDestructuredMetadata(iiifResource);
 
     expect(received).toEqual([]);
diff --git a/jest.json b/jest.json
index d635140982349d0f2b6e906c1b113cdc4ab04b88..fd8cf635a7e1b28ed051bcdc24850581f52e12cd 100644
--- a/jest.json
+++ b/jest.json
@@ -17,5 +17,8 @@
     "<rootDir>/**/__tests__/**/*.{js,jsx}",
     "<rootDir>/src/**/?(*.)(spec|test|unit).{js,jsx}"
   ],
+  "transformIgnorePatterns": [
+    "<rootDir>/node_modules/(?!manifesto.js)"
+  ],
   "preset": "jest-puppeteer"
 }
diff --git a/package.json b/package.json
index 166bf4ab163b43e14bcf3d03a840e266a0df4c90..dc84c25567c0ca8e1b3702a64a35f316b958dd30 100644
--- a/package.json
+++ b/package.json
@@ -45,9 +45,9 @@
     "i18next": "^17.0.6",
     "immutable": "^4.0.0-rc.12",
     "intersection-observer": "^0.7.0",
+    "isomorphic-unfetch": "^3.0.0",
     "lodash": "^4.17.11",
-    "manifesto.js": "^3.0.11",
-    "node-fetch": "^2.6.0",
+    "manifesto.js": "^4.0.1",
     "normalize-url": "^4.2.0",
     "openseadragon": "^2.4.2",
     "prop-types": "^15.6.2",
diff --git a/setupJest.js b/setupJest.js
index ce72c8eed614f82b17bee5f0aa8df6235d6eda20..6ccce82a5733d3d111de160410d7c706a129da0a 100644
--- a/setupJest.js
+++ b/setupJest.js
@@ -12,7 +12,7 @@ const { window } = jsdom;
 jest.setTimeout(10000);
 
 window.HTMLCanvasElement.prototype.getContext = () => {};
-jest.setMock('node-fetch', fetch);
+jest.setMock('isomorphic-unfetch', fetch);
 global.fetch = require('jest-fetch-mock'); // eslint-disable-line import/no-extraneous-dependencies
 
 global.window = window;
diff --git a/src/components/WindowAuthenticationControl.js b/src/components/WindowAuthenticationControl.js
index 87f70ab727708b9cc8f5300c29c5e81f5956bf91..97c33a4596e5735b557e1a7d8eee2646db9d535d 100644
--- a/src/components/WindowAuthenticationControl.js
+++ b/src/components/WindowAuthenticationControl.js
@@ -50,7 +50,7 @@ export class WindowAuthenticationControl extends Component {
       profile,
     } = this.props;
 
-    return profile.value === 'http://iiif.io/api/auth/1/clickthrough' || profile.value === 'http://iiif.io/api/auth/1/login';
+    return profile === 'http://iiif.io/api/auth/1/clickthrough' || profile === 'http://iiif.io/api/auth/1/login';
   }
 
   /** */
@@ -149,7 +149,7 @@ WindowAuthenticationControl.propTypes = {
   header: PropTypes.string,
   infoId: PropTypes.string,
   label: PropTypes.string,
-  profile: PropTypes.shape({ value: PropTypes.string }),
+  profile: PropTypes.string,
   serviceId: PropTypes.string,
   status: PropTypes.oneOf(['ok', 'fetching', 'failed', null]),
   t: PropTypes.func,
diff --git a/src/lib/ManifestoCanvas.js b/src/lib/ManifestoCanvas.js
index 70f8786e6e28b9a80c67f24eee64da43cd484e6c..b4653e52f287c04f49ad0e0654eb4eece9c7e965 100644
--- a/src/lib/ManifestoCanvas.js
+++ b/src/lib/ManifestoCanvas.js
@@ -1,5 +1,5 @@
 import flatten from 'lodash/flatten';
-import { Utils } from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 /**
  * ManifestoCanvas - adds additional, testable logic around Manifesto's Canvas
  * https://iiif-commons.github.io/manifesto/classes/_canvas_.manifesto.canvas.html
diff --git a/src/state/actions/annotation.js b/src/state/actions/annotation.js
index ec03963ce8ec525f1592f311ec9c4738b10aac4e..c940ea76c22c8c6e5b4aa9a17631b361072dc475 100644
--- a/src/state/actions/annotation.js
+++ b/src/state/actions/annotation.js
@@ -1,4 +1,4 @@
-import fetch from 'node-fetch';
+import fetch from 'isomorphic-unfetch';
 import ActionTypes from './action-types';
 
 /**
diff --git a/src/state/actions/auth.js b/src/state/actions/auth.js
index 72b1e2316adb0236eb853b91e25b716e6366d870..7421e173d1603f3fa717fb5fcfa50eb778701a89 100644
--- a/src/state/actions/auth.js
+++ b/src/state/actions/auth.js
@@ -1,4 +1,4 @@
-import { Utils } from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import ActionTypes from './action-types';
 import { fetchInfoResponse } from './infoResponse';
 
diff --git a/src/state/actions/infoResponse.js b/src/state/actions/infoResponse.js
index 8bbb0977c144cc7c458171e0ca7510b5676ba317..ded5c9f67031d4003d653f6976aec8cd0ac7b817 100644
--- a/src/state/actions/infoResponse.js
+++ b/src/state/actions/infoResponse.js
@@ -1,5 +1,5 @@
-import fetch from 'node-fetch';
-import { Utils } from 'manifesto.js';
+import fetch from 'isomorphic-unfetch';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import ActionTypes from './action-types';
 
 /**
@@ -49,7 +49,7 @@ export function receiveInfoResponseFailure(infoId, error) {
 function getAccessToken({ accessTokens }, iiifService) {
   if (!iiifService) return undefined;
 
-  const services = Utils.getServices(iiifService).filter(s => s.getProfile().value.match(/http:\/\/iiif.io\/api\/auth\/1\//));
+  const services = Utils.getServices(iiifService).filter(s => s.getProfile().match(/http:\/\/iiif.io\/api\/auth\/1\//));
 
   for (let i = 0; i < services.length; i += 1) {
     const authService = services[i];
diff --git a/src/state/actions/manifest.js b/src/state/actions/manifest.js
index 577a8e4e60376a9262e4c3110b0c299aafe619c0..b8a8b280c507936448cdcb325fc933b00e9c9ef1 100644
--- a/src/state/actions/manifest.js
+++ b/src/state/actions/manifest.js
@@ -1,4 +1,4 @@
-import fetch from 'node-fetch';
+import fetch from 'isomorphic-unfetch';
 import ActionTypes from './action-types';
 
 /**
diff --git a/src/state/actions/search.js b/src/state/actions/search.js
index e60b19f4ae1e4e7391774ff4aaf7c8461c9b8b0f..470f563e8762ab32b3738201919ac829740b9fd5 100644
--- a/src/state/actions/search.js
+++ b/src/state/actions/search.js
@@ -1,4 +1,4 @@
-import fetch from 'node-fetch';
+import fetch from 'isomorphic-unfetch';
 import {
   getCanvasForAnnotation,
   getCanvas,
diff --git a/src/state/reducers/accessTokens.js b/src/state/reducers/accessTokens.js
index 03ee2bed7957de9622d77701f09a33d227e01536..18199d404c4eda2d24ffcff2a95564e598a4ba73 100644
--- a/src/state/reducers/accessTokens.js
+++ b/src/state/reducers/accessTokens.js
@@ -1,6 +1,6 @@
 import normalizeUrl from 'normalize-url';
 
-import { Utils } from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import ActionTypes from '../actions/action-types';
 
 /** */
diff --git a/src/state/selectors/canvases.js b/src/state/selectors/canvases.js
index 62536af904b73206793be7a1abd57864557f5811..60c01bc9389bb13579ca58efa692f9634ca4b3ec 100644
--- a/src/state/selectors/canvases.js
+++ b/src/state/selectors/canvases.js
@@ -1,5 +1,5 @@
 import { createSelector } from 'reselect';
-import { Utils } from 'manifesto.js';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import CanvasGroupings from '../../lib/CanvasGroupings';
 import { getManifestoInstance } from './manifests';
 import { getWindow, getWindowViewType } from './windows';
diff --git a/src/state/selectors/manifests.js b/src/state/selectors/manifests.js
index 8e45104ffe0e246cf36ded4cbd838e8e7495d86a..ea58aaaeb4a7691b9877cdef92d6d0921eea47a2 100644
--- a/src/state/selectors/manifests.js
+++ b/src/state/selectors/manifests.js
@@ -1,12 +1,13 @@
 import { createSelector } from 'reselect';
 import createCachedSelector from 're-reselect';
-import manifesto, { LanguageMap } from 'manifesto.js';
+import { LanguageMap } from 'manifesto.js/dist-esmodule/LanguageMap';
+import { Utils } from 'manifesto.js/dist-esmodule/Utils';
 import ManifestoCanvas from '../../lib/ManifestoCanvas';
 
 /** */
 function createManifestoInstance(json, locale) {
   if (!json) return undefined;
-  return manifesto.create(json, locale ? { locale } : undefined);
+  return Utils.parseManifest(json, locale ? { locale } : undefined);
 }
 
 
@@ -412,7 +413,7 @@ export const getManifestViewingHint = createSelector(
     if (!manifest) return null;
     const viewingHint = (manifest.getSequences()[0] && manifest.getSequences()[0].getViewingHint())
       || manifest.getViewingHint();
-    if (viewingHint) return viewingHint.value;
+    if (viewingHint) return viewingHint;
     return null;
   },
 );
@@ -423,7 +424,7 @@ export const getManifestViewingDirection = createSelector(
     if (!manifest) return null;
     const viewingDirection = manifest.getSequences()[0].getViewingDirection()
       || manifest.getViewingDirection();
-    if (viewingDirection) return viewingDirection.value;
+    if (viewingDirection) return viewingDirection;
     return null;
   },
 );
diff --git a/src/state/selectors/searches.js b/src/state/selectors/searches.js
index f0b7f107da2c793c54f6beaaf044d6053944b9bc..f7188f58df4fdb5534b0440523e5b51c95fac877 100644
--- a/src/state/selectors/searches.js
+++ b/src/state/selectors/searches.js
@@ -1,5 +1,5 @@
 import { createSelector } from 'reselect';
-import { LanguageMap } from 'manifesto.js';
+import { LanguageMap } from 'manifesto.js/dist-esmodule/LanguageMap';
 import flatten from 'lodash/flatten';
 import AnnotationList from '../../lib/AnnotationList';
 import { getCanvas, getCanvases } from './canvases';