diff --git a/src/views/studio/debug.jsx b/src/views/studio/debug.jsx
new file mode 100644
index 000000000..4875da6b2
--- /dev/null
+++ b/src/views/studio/debug.jsx
@@ -0,0 +1,12 @@
+import React from 'react';
+
+export default function Debug({label, data}) {
+    return <div style={{padding: '2rem', 'border': '1px solid red', margin: '2rem'}}>
+        <small>{label}</small>
+        <code>
+            <pre style={{fontSize: '0.75rem'}}>
+                {JSON.stringify(data, null, '  ')}
+            </pre>
+        </code>
+    </div>
+}
\ No newline at end of file
diff --git a/src/views/studio/lib/fetchers.js b/src/views/studio/lib/fetchers.js
new file mode 100644
index 000000000..e4fabadb7
--- /dev/null
+++ b/src/views/studio/lib/fetchers.js
@@ -0,0 +1,32 @@
+const ITEM_LIMIT = 4;
+
+const infoFetcher = studioId => fetch(`${process.env.API_HOST}/studios/${studioId}`)
+    .then(d => d.json());
+
+const projectFetcher = (studioId, offset) =>
+    fetch(`${process.env.API_HOST}/studios/${studioId}/projects?limit=${ITEM_LIMIT}&offset=${offset}`)
+        .then(d => d.json())
+        .then(d => ({items: d, moreToLoad: d.length === ITEM_LIMIT}));
+
+const curatorFetcher = (studioId, offset) =>
+    fetch(`${process.env.API_HOST}/studios/${studioId}/curators?limit=${ITEM_LIMIT}&offset=${offset}`)
+        .then(d => d.json())
+        .then(d => ({items: d, moreToLoad: d.length === ITEM_LIMIT}));
+
+const managerFetcher = (studioId, offset) =>
+    fetch(`${process.env.API_HOST}/studios/${studioId}/managers?limit=${ITEM_LIMIT}&offset=${offset}`)
+        .then(d => d.json())
+        .then(d => ({items: d, moreToLoad: d.length === ITEM_LIMIT}));
+
+const activityFetcher = studioId =>
+    fetch(`${process.env.API_HOST}/studios/${studioId}/activity`)
+        .then(d => d.json())
+        .then(d => ({items: d, moreToLoad: false})); // No pagination on the activity feed
+
+export {
+    activityFetcher,
+    infoFetcher,
+    projectFetcher,
+    curatorFetcher,
+    managerFetcher
+};
diff --git a/src/views/studio/studio-info.jsx b/src/views/studio/studio-info.jsx
index 01381340b..5e0ff12e4 100644
--- a/src/views/studio/studio-info.jsx
+++ b/src/views/studio/studio-info.jsx
@@ -1,13 +1,27 @@
-import React from 'react';
+import React, {useState, useEffect} from 'react';
 import {useParams} from 'react-router-dom';
+import {infoFetcher} from './lib/fetchers';
+import Debug from './debug.jsx';
 
 const StudioInfo = () => {
     const {studioId} = useParams();
+    const [state, setState] = useState({loading: false, error: null, data: null});
+    // Since this data is in a component that is always visible, it doesn't necessarily
+    // need to be kept in redux. One alternative is to use the infinite-list redux
+    // module and just treat the studio info as the first and only item in the list.
+    useEffect(() => {
+        if (!studioId) return;
+        infoFetcher(studioId)
+            .then(data => setState({loading: false, error: null, data}))
+            .catch(error => setState({loading: false, error, data: null}))
+    }, [studioId]);
 
     return (
         <div>
             <h2>Studio Info</h2>
-            <p>Studio {studioId}</p>
+            {state.loading && <div>Loading..</div>}
+            {state.error && <Debug label="Error" data={state.error} />}
+            <Debug label="Studio Info" data={state.data} />
         </div>
     );
 };