diff --git a/core/variable_events.js b/core/variable_events.js
index 8e39ead8..0dcabce7 100644
--- a/core/variable_events.js
+++ b/core/variable_events.js
@@ -89,6 +89,7 @@ Blockly.Events.VarCreate = function(variable) {
   this.varType = variable.type;
   this.varName = variable.name;
   this.isLocal = variable.isLocal;
+  this.isCloud = variable.isCloud;
 };
 goog.inherits(Blockly.Events.VarCreate, Blockly.Events.VarBase);
 
@@ -107,6 +108,7 @@ Blockly.Events.VarCreate.prototype.toJson = function() {
   json['varType'] = this.varType;
   json['varName'] = this.varName;
   json['isLocal'] = this.isLocal;
+  json['isCloud'] = this.isCloud;
   return json;
 };
 
@@ -119,6 +121,7 @@ Blockly.Events.VarCreate.prototype.fromJson = function(json) {
   this.varType = json['varType'];
   this.varName = json['varName'];
   this.isLocal = json['isLocal'];
+  this.isCloud = json['isCloud'];
 };
 
 /**
@@ -128,7 +131,7 @@ Blockly.Events.VarCreate.prototype.fromJson = function(json) {
 Blockly.Events.VarCreate.prototype.run = function(forward) {
   var workspace = this.getEventWorkspace_();
   if (forward) {
-    workspace.createVariable(this.varName, this.varType, this.varId, this.isLocal);
+    workspace.createVariable(this.varName, this.varType, this.varId, this.isLocal, this.isCloud);
   } else {
     workspace.deleteVariableById(this.varId);
   }
@@ -149,6 +152,7 @@ Blockly.Events.VarDelete = function(variable) {
   this.varType = variable.type;
   this.varName = variable.name;
   this.isLocal = variable.isLocal;
+  this.isCloud = variable.isCloud;
 };
 goog.inherits(Blockly.Events.VarDelete, Blockly.Events.VarBase);
 
@@ -167,6 +171,7 @@ Blockly.Events.VarDelete.prototype.toJson = function() {
   json['varType'] = this.varType;
   json['varName'] = this.varName;
   json['isLocal'] = this.isLocal;
+  json['isCloud'] = this.isCloud;
   return json;
 };
 
@@ -179,6 +184,7 @@ Blockly.Events.VarDelete.prototype.fromJson = function(json) {
   this.varType = json['varType'];
   this.varName = json['varName'];
   this.isLocal = json['isLocal'];
+  this.isCloud = json['isCloud'];
 };
 
 /**
@@ -190,7 +196,7 @@ Blockly.Events.VarDelete.prototype.run = function(forward) {
   if (forward) {
     workspace.deleteVariableById(this.varId);
   } else {
-    workspace.createVariable(this.varName, this.varType, this.varId, this.isLocal);
+    workspace.createVariable(this.varName, this.varType, this.varId, this.isLocal, this.isCloud);
   }
 };
 
diff --git a/core/variable_map.js b/core/variable_map.js
index d706ca10..f391c093 100644
--- a/core/variable_map.js
+++ b/core/variable_map.js
@@ -175,10 +175,11 @@ Blockly.VariableMap.prototype.renameVariableWithConflict_ = function(variable,
  * @param {string=} opt_id The unique ID of the variable. This will default to
  *     a UUID.
  * @param {boolean=} opt_isLocal Whether the variable is locally scoped.
+ * @param {boolean=} opt_isCloud Whether the variable is a cloud variable.
  * @return {?Blockly.VariableModel} The newly created variable.
  */
 Blockly.VariableMap.prototype.createVariable = function(name,
-    opt_type, opt_id, opt_isLocal) {
+    opt_type, opt_id, opt_isLocal, opt_isCloud) {
   var variable = this.getVariable(name, opt_type);
   if (variable) {
     if (opt_id && variable.getId() != opt_id) {
@@ -203,7 +204,7 @@ Blockly.VariableMap.prototype.createVariable = function(name,
   opt_type = opt_type || '';
 
   variable = new Blockly.VariableModel(this.workspace, name, opt_type, opt_id,
-      opt_isLocal);
+      opt_isLocal, opt_isCloud);
   // If opt_type is not a key, create a new list.
   if (!this.variableMap_[opt_type]) {
     this.variableMap_[opt_type] = [variable];
diff --git a/core/variable_model.js b/core/variable_model.js
index f4a972b8..4c62d8c6 100644
--- a/core/variable_model.js
+++ b/core/variable_model.js
@@ -43,10 +43,12 @@ goog.require('goog.string');
  * @param {string=} opt_id The unique ID of the variable. This will default to
  *     a UUID.
  * @param {boolean=} opt_isLocal Whether the variable is locally scoped.
+ * @param {boolean=} opt_isCloud Whether the variable is a cloud variable.
  * @see {Blockly.FieldVariable}
  * @constructor
  */
-Blockly.VariableModel = function(workspace, name, opt_type, opt_id, opt_isLocal) {
+Blockly.VariableModel = function(workspace, name, opt_type, opt_id,
+    opt_isLocal, opt_isCloud) {
   /**
    * The workspace the variable is in.
    * @type {!Blockly.Workspace}
@@ -85,6 +87,12 @@ Blockly.VariableModel = function(workspace, name, opt_type, opt_id, opt_isLocal)
    */
   this.isLocal = opt_isLocal || false;
 
+  /**
+   * Whether the variable is a cloud variable.
+   * @package
+   */
+  this.isCloud = opt_isCloud || false;
+
   Blockly.Events.fire(new Blockly.Events.VarCreate(this));
 };
 
diff --git a/core/variables.js b/core/variables.js
index 1ed21ad1..9728ed14 100644
--- a/core/variables.js
+++ b/core/variables.js
@@ -44,6 +44,15 @@ goog.require('goog.string');
  */
 Blockly.Variables.NAME_TYPE = Blockly.VARIABLE_CATEGORY_NAME;
 
+/**
+ * Constant prefix to differentiate cloud variable names from other types
+ * of variables.
+ * This is the \u2601 cloud unicode character followed by a space.
+ * @type {string}
+ * @package
+ */
+Blockly.Variables.CLOUD_PREFIX = '☁ ';
+
 /**
  * Find all user-created variables that are in use in the workspace.
  * For use by generators.
@@ -289,14 +298,16 @@ Blockly.Variables.createVariable = function(workspace, opt_callback, opt_type) {
 
   // Prompt the user to enter a name for the variable
   Blockly.prompt(newMsg, '',
-      function(text, additionalVars, scope) {
+      function(text, additionalVars, variableOptions) {
+        var scope = variableOptions.scope;
         var isLocal = (scope === 'local') || false;
+        var isCloud = variableOptions.isCloud || false;
         // Default to [] if additionalVars is not provided
         additionalVars = additionalVars || [];
         // Only use additionalVars for global variable creation.
         var additionalVarNames = isLocal ? [] : additionalVars;
 
-        var validatedText = validate(text, workspace, additionalVarNames, opt_callback);
+        var validatedText = validate(text, workspace, additionalVarNames, isCloud, opt_callback);
         if (validatedText) {
           // The name is valid according to the type, create the variable
           var potentialVarMap = workspace.getPotentialVariableMap();
@@ -311,7 +322,7 @@ Blockly.Variables.createVariable = function(workspace, opt_callback, opt_type) {
                 opt_type, workspace, false);
           }
           if (!variable) {
-            variable = workspace.createVariable(validatedText, opt_type, null, isLocal);
+            variable = workspace.createVariable(validatedText, opt_type, null, isLocal, isCloud);
           }
 
           var flyout = workspace.isFlyout ? workspace : workspace.getFlyout();
@@ -346,6 +357,7 @@ Blockly.Variables.createVariable = function(workspace, opt_callback, opt_type) {
  *     already exists.
  * @param {Array<string>} additionalVars A list of additional var names to check
  *     for conflicts against.
+ * @param {boolean} isCloud Whether the variable is a cloud variable.
  * @param {function(?string=)=} opt_callback An optional function to be called on
  *     a pre-existing variable of the user-provided name. This function is currently
  *     only used for broadcast messages.
@@ -355,7 +367,8 @@ Blockly.Variables.createVariable = function(workspace, opt_callback, opt_type) {
  *     proceed with creating or renaming the variable.
  * @private
  */
-Blockly.Variables.nameValidator_ = function(type, text, workspace, additionalVars, opt_callback) {
+Blockly.Variables.nameValidator_ = function(type, text, workspace, additionalVars,
+    isCloud, opt_callback) {
   // The validators for the different variable types require slightly different arguments.
   // For broadcast messages, if a broadcast message of the provided name already exists,
   // the validator needs to call a function that updates the selected
@@ -367,10 +380,10 @@ Blockly.Variables.nameValidator_ = function(type, text, workspace, additionalVar
   if (type == Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE) {
     return Blockly.Variables.validateBroadcastMessageName_(text, workspace, opt_callback);
   } else if (type == Blockly.LIST_VARIABLE_TYPE) {
-    return Blockly.Variables.validateScalarVarOrListName_(text, workspace, additionalVars, type,
+    return Blockly.Variables.validateScalarVarOrListName_(text, workspace, additionalVars, false, type,
         Blockly.Msg.LIST_ALREADY_EXISTS);
   } else {
-    return Blockly.Variables.validateScalarVarOrListName_(text, workspace, additionalVars, type,
+    return Blockly.Variables.validateScalarVarOrListName_(text, workspace, additionalVars, isCloud, type,
         Blockly.Msg.VARIABLE_ALREADY_EXISTS);
   }
 };
@@ -417,6 +430,7 @@ Blockly.Variables.validateBroadcastMessageName_ = function(name, workspace, opt_
  *     against.
  * @param {Array<string>} additionalVars A list of additional variable names to check
  *     for conflicts against.
+ * @param {boolean} isCloud Whether the variable is a cloud variable.
  * @param {string} type The type to validate the variable as. This should be one of
  *     Blockly.SCALAR_VARIABLE_TYPE or Blockly.LIST_VARIABLE_TYPE.
  * @param {string} errorMsg The type-specific error message the user should see
@@ -425,12 +439,15 @@ Blockly.Variables.validateBroadcastMessageName_ = function(name, workspace, opt_
  * @private
  */
 Blockly.Variables.validateScalarVarOrListName_ = function(name, workspace, additionalVars,
-    type, errorMsg) {
+    isCloud, type, errorMsg) {
   // For scalar variables, we don't want leading or trailing white space
   name = Blockly.Variables.trimName_(name);
   if (!name) {
     return null;
   }
+  if (isCloud) {
+    name = Blockly.Variables.CLOUD_PREFIX + name;
+  }
   if (workspace.getVariable(name, type) || additionalVars.indexOf(name) >= 0) {
     // error
     Blockly.alert(errorMsg.replace('%1', name));
@@ -472,9 +489,13 @@ Blockly.Variables.renameVariable = function(workspace, variable,
   var promptText = promptMsg.replace('%1', variable.name);
   Blockly.prompt(promptText, '',
       function(newName, additionalVars) {
+        if (variable.isCloud &&
+            newName.length > 0 && newName.indexOf(Blockly.Variables.CLOUD_PREFIX) == 0 ) {
+          newName = newName.substring(2); // The name validator will add the prefix back
+        }
         additionalVars = additionalVars || [];
         var additionalVarNames = variable.isLocal ? [] : additionalVars;
-        var validatedText = validate(newName, workspace, additionalVarNames);
+        var validatedText = validate(newName, workspace, additionalVarNames, variable.isCloud);
         if (validatedText) {
           workspace.renameVariableById(variable.getId(), validatedText);
           if (opt_callback) {
diff --git a/core/workspace.js b/core/workspace.js
index c6ee5725..904315dc 100644
--- a/core/workspace.js
+++ b/core/workspace.js
@@ -341,10 +341,12 @@ Blockly.Workspace.prototype.renameVariableById = function(id, newName) {
  * @param {string=} opt_id The unique ID of the variable. This will default to
  *     a UUID.
  * @param {boolean=} opt_isLocal Whether the variable to create is locally scoped.
+ * @param {boolean=} opt_isCloud Whether the variable to create is locally scoped.
  * @return {?Blockly.VariableModel} The newly created variable.
  */
-Blockly.Workspace.prototype.createVariable = function(name, opt_type, opt_id, opt_isLocal) {
-  return this.variableMap_.createVariable(name, opt_type, opt_id, opt_isLocal);
+Blockly.Workspace.prototype.createVariable = function(name, opt_type, opt_id,
+    opt_isLocal, opt_isCloud) {
+  return this.variableMap_.createVariable(name, opt_type, opt_id, opt_isLocal, opt_isCloud);
 };
 
 /**
diff --git a/core/workspace_svg.js b/core/workspace_svg.js
index e2674458..f270ac1f 100644
--- a/core/workspace_svg.js
+++ b/core/workspace_svg.js
@@ -1161,14 +1161,15 @@ Blockly.WorkspaceSvg.prototype.deleteVariableById = function(id) {
  * @param {string=} opt_id The unique ID of the variable. This will default to
  *     a UUID.
  * @param {boolean=} opt_isLocal Whether the variable is locally scoped.
+ * @param {boolean=} opt_isCloud Whether the variable is a cloud variable.
  * @return {?Blockly.VariableModel} The newly created variable.
  * @package
  */
 Blockly.WorkspaceSvg.prototype.createVariable = function(name, opt_type, opt_id,
-    opt_isLocal) {
+    opt_isLocal, opt_isCloud) {
   var variableInMap = (this.getVariable(name, opt_type) != null);
   var newVar = Blockly.WorkspaceSvg.superClass_.createVariable.call(
-      this, name, opt_type, opt_id, opt_isLocal);
+      this, name, opt_type, opt_id, opt_isLocal, opt_isCloud);
   // For performance reasons, only refresh the the toolbox for new variables.
   // Variables that already exist should already be there.
   if (!variableInMap && (opt_type != Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE)) {
diff --git a/core/xml.js b/core/xml.js
index 13433706..1b52d4c3 100644
--- a/core/xml.js
+++ b/core/xml.js
@@ -72,6 +72,7 @@ Blockly.Xml.variablesToDom = function(variableList) {
     element.setAttribute('type', variable.type);
     element.setAttribute('id', variable.getId());
     element.setAttribute('islocal', variable.isLocal);
+    element.setAttribute('isCloud', variable.isCloud);
     variables.appendChild(element);
   }
   return variables;
@@ -638,12 +639,13 @@ Blockly.Xml.domToVariables = function(xmlVariables, workspace) {
     var type = xmlChild.getAttribute('type');
     var id = xmlChild.getAttribute('id');
     var isLocal = xmlChild.getAttribute('islocal') == 'true';
+    var isCloud = xmlChild.getAttribute('isCloud') == 'true';
     var name = xmlChild.textContent;
 
     if (typeof(type) === undefined || type === null) {
       throw Error('Variable with id, ' + id + ' is without a type');
     }
-    workspace.createVariable(name, type, id, isLocal);
+    workspace.createVariable(name, type, id, isLocal, isCloud);
   }
 };