diff --git a/package.json b/package.json
index 04e0f6dac88cde6fe20307f862462c495498fa55..f60913a708682b400039336c9fedaf19f08bf238 100644
--- a/package.json
+++ b/package.json
@@ -105,7 +105,7 @@
     "scratch-render": "0.1.0-prerelease.20181029125804",
     "scratch-storage": "1.1.0",
     "scratch-svg-renderer": "0.2.0-prerelease.20181024192149",
-    "scratch-vm": "0.2.0-prerelease.20181025092837",
+    "scratch-vm": "0.2.0-prerelease.20181030160328",
     "selenium-webdriver": "3.6.0",
     "startaudiocontext": "1.2.1",
     "style-loader": "^0.23.0",
diff --git a/src/containers/gui.jsx b/src/containers/gui.jsx
index 3146e55a55aadfd1d72e935e37e2397a83deda6d..88344203a72c714592e75fbc090fbb3032326fb7 100644
--- a/src/containers/gui.jsx
+++ b/src/containers/gui.jsx
@@ -73,6 +73,7 @@ class GUI extends React.Component {
         const {
             /* eslint-disable no-unused-vars */
             assetHost,
+            cloudHost,
             error,
             hideIntro,
             isError,
@@ -104,6 +105,7 @@ class GUI extends React.Component {
 GUI.propTypes = {
     assetHost: PropTypes.string,
     children: PropTypes.node,
+    cloudHost: PropTypes.string,
     error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
     fetchingProject: PropTypes.bool,
     hideIntro: PropTypes.bool,
diff --git a/src/lib/cloud-provider.js b/src/lib/cloud-provider.js
new file mode 100644
index 0000000000000000000000000000000000000000..ff3d34c40bc8472e4652d037fa09e82bb211bb73
--- /dev/null
+++ b/src/lib/cloud-provider.js
@@ -0,0 +1,132 @@
+import log from './log.js';
+
+
+class CloudProvider {
+    /**
+     * A cloud data provider which creates and manages a web socket connection
+     * to the Scratch cloud data server. This provider is responsible for
+     * interfacing with the VM's cloud io device.
+     * @param {string} cloudHost The url for the cloud data server
+     * @param {VirtualMachine} vm The Scratch virtual machine to interface with
+     * @param {string} username The username to associate cloud data updates with
+     * @param {string} projectId The id associated with the project containing
+     * cloud data.
+     */
+    constructor (cloudHost, vm, username, projectId) {
+        this.vm = vm;
+        this.username = username;
+        this.projectId = projectId;
+
+        // Open a websocket connection to the clouddata server
+        this.openConnection(cloudHost);
+    }
+
+    /**
+     * Open a new websocket connection to the clouddata server.
+     * @param {string} cloudHost The cloud data server to connect to.
+     */
+    openConnection (cloudHost) {
+        if (window.WebSocket === null) {
+            log.warn('Websocket support is not available in this browser');
+            this.connection = null;
+            return;
+        }
+
+        this.connection = new WebSocket((location.protocol === 'http:' ? 'ws://' : 'wss://') + cloudHost);
+
+        this.connection.onerror = e => {
+            log.error(`Websocket connection error: ${JSON.stringify(e)}`);
+
+            // TODO Add re-connection attempt logic here
+        };
+
+        this.connection.onmessage = event => {
+            const messageString = event.data;
+            log.info(`Received websocket message: ${messageString}`);
+            const message = JSON.parse(messageString);
+            if (message.method === 'set') {
+                const varData = {
+                    varUpdate: {
+                        name: message.name,
+                        value: message.value
+                    }
+                };
+                this.vm.postIOData('cloud', varData);
+            }
+        };
+
+        this.connection.onopen = () => {
+            this.writeToServer('handshake');
+            log.info(`Successfully connected to clouddata server.`);
+        };
+
+        this.connection.onclose = () => {
+            log.info(`Closed connection to websocket`);
+        };
+    }
+
+    /**
+     * Format and send a message to the cloud data server.
+     * @param {string} methodName The message method, indicating the action to perform.
+     * @param {string} dataName The name of the cloud variable this message pertains to
+     * @param {string | number} dataValue The value to set the cloud variable to
+     * @param {number} dataIndex The index of the item to update (for cloud lists)
+     * @param {string} dataNewName The new name for the cloud variable (if renaming)
+     */
+    writeToServer (methodName, dataName, dataValue, dataIndex, dataNewName) {
+        const msg = {};
+        msg.method = methodName;
+        msg.user = this.username;
+        msg.project_id = this.projectId;
+
+        if (dataName) msg.name = dataName;
+        if (dataValue) msg.value = dataValue;
+        if (dataIndex) msg.index = dataIndex;
+        if (dataNewName) msg.new_name = dataNewName;
+
+        const dataToWrite = JSON.stringify(msg);
+        this.sendCloudData(dataToWrite);
+    }
+
+    /**
+     * Send a formatted message to the cloud data server.
+     * @param {string} data The formatted message to send.
+     */
+    sendCloudData (data) {
+        this.connection.send(`${data}\n`);
+        log.info(`Sent message to clouddata server: ${data}`);
+    }
+
+    /**
+     * Provides an API for the VM's cloud IO device to update
+     * a cloud variable on the server.
+     * @param {string} name The name of the variable to update
+     * @param {string | number} value The new value for the variable
+     */
+    updateVariable (name, value) {
+        this.writeToServer('set', name, value);
+    }
+
+    /**
+     * Closes the connection to the web socket and clears the cloud
+     * provider of references related to the cloud data project.
+     */
+    requestCloseConnection () {
+        this.connection.close();
+        this.clear();
+    }
+
+    /**
+     * Clear this provider of references related to the project
+     * and current state.
+     */
+    clear () {
+        this.connection = null;
+        this.vm = null;
+        this.username = null;
+        this.projectId = null;
+    }
+
+}
+
+export default CloudProvider;
diff --git a/src/lib/vm-listener-hoc.jsx b/src/lib/vm-listener-hoc.jsx
index 5e18cdaf1ec42a76509fc3ab05ab3994e5b77c66..d130cfcddda609f7b5a99b301d4a67da34b9aeff 100644
--- a/src/lib/vm-listener-hoc.jsx
+++ b/src/lib/vm-listener-hoc.jsx
@@ -102,7 +102,6 @@ const vmListenerHOC = function (WrappedComponent) {
                 /* eslint-disable no-unused-vars */
                 attachKeyboardEvents,
                 shouldEmitTargetsUpdate,
-                username,
                 onBlockDragUpdate,
                 onKeyDown,
                 onKeyUp,
diff --git a/src/lib/vm-manager-hoc.jsx b/src/lib/vm-manager-hoc.jsx
index b8e3c2cd0a0d3d1e9d549414107b50d0e31f9f02..3d7e9a2e92cc1a629da00ee48368997ecf7f878c 100644
--- a/src/lib/vm-manager-hoc.jsx
+++ b/src/lib/vm-manager-hoc.jsx
@@ -5,6 +5,7 @@ import {connect} from 'react-redux';
 
 import VM from 'scratch-vm';
 import AudioEngine from 'scratch-audio';
+import CloudProvider from '../lib/cloud-provider';
 
 import {
     LoadingStates,
@@ -46,6 +47,18 @@ const vmManagerHOC = function (WrappedComponent) {
             return this.props.vm.loadProject(this.props.projectData)
                 .then(() => {
                     this.props.onLoadedProject(this.props.loadingState, this.props.canSave);
+                    // If the cloud host exists, open a cloud connection and
+                    // set the vm's cloud provider.
+                    if (this.props.cloudHost) {
+                        // TODO check if we should actually
+                        // connect to cloud data based on info from the loaded project and
+                        // info about the user (e.g. scratcher status)
+                        this.props.vm.setCloudProvider(new CloudProvider(
+                            this.props.cloudHost,
+                            this.props.vm,
+                            this.props.username,
+                            this.props.projectId));
+                    }
                 })
                 .catch(e => {
                     this.props.onError(e);
@@ -54,12 +67,14 @@ const vmManagerHOC = function (WrappedComponent) {
         render () {
             const {
                 /* eslint-disable no-unused-vars */
+                cloudHost,
                 fontsLoaded,
                 loadingState,
                 onError: onErrorProp,
                 onLoadedProject: onLoadedProjectProp,
                 projectData,
                 projectId,
+                username,
                 /* eslint-enable no-unused-vars */
                 isLoadingWithId: isLoadingWithIdProp,
                 vm,
@@ -77,6 +92,7 @@ const vmManagerHOC = function (WrappedComponent) {
 
     VMManager.propTypes = {
         canSave: PropTypes.bool,
+        cloudHost: PropTypes.string,
         fontsLoaded: PropTypes.bool,
         isLoadingWithId: PropTypes.bool,
         loadingState: PropTypes.oneOf(LoadingStates),
@@ -84,6 +100,7 @@ const vmManagerHOC = function (WrappedComponent) {
         onLoadedProject: PropTypes.func,
         projectData: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
         projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+        username: PropTypes.string,
         vm: PropTypes.instanceOf(VM).isRequired
     };