diff --git a/scripts/bot/run-bot.js b/scripts/bot/run-bot.js
index 2e37ccc3d62a5d6bea59efa64a8b11d9984ee1e0..d6851f97292f1cd978f9b3c72ad7d559dfccc0ee 100644
--- a/scripts/bot/run-bot.js
+++ b/scripts/bot/run-bot.js
@@ -4,9 +4,10 @@ Usage:
     ./run-bot.js [options]
 
 Options:
-    -h --host=<host>  Hubs host [default: localhost:8080]
-    -r --room=<room>  Room id [default: 234234].
-    -h --help         Show this screen.
+    -u --url=<url>    URL
+    -o --host=<host>  Hubs host if URL is not specified [default: localhost:8080]
+    -r --room=<room>  Room id
+    -h --help         Show this screen
 `;
 
 const docopt = require("docopt").docopt;
@@ -22,12 +23,19 @@ const querystring = require("query-string");
   page.on("error", err => console.error("ERROR: ", err));
   page.on("pageerror", err => console.error("PAGE ERROR: ", err));
 
+  const baseUrl = options["--url"] || `https://${options["--host"]}/hub.html`;
+
   const params = {
-    room: options["--room"],
-    bot: true
+    bot: true,
+    allow_multi: true
   };
-  console.log(params);
-  const url = `https://${options["--host"]}/hub.html?${querystring.stringify(params)}`;
+  const roomOption = options["--room"];
+  if (roomOption) {
+    params.room = roomOption;
+  }
+
+  const url = `${baseUrl}?${querystring.stringify(params)}`;
+  console.log(url);
 
   const navigate = async () => {
     try {
diff --git a/scripts/bot/run-bot.sh b/scripts/bot/run-bot.sh
index 7bd9b986a2463a2864403b81599a0e161206d58e..aa693b25a11eca48bb83d4cc51115fdf6138f2eb 100755
--- a/scripts/bot/run-bot.sh
+++ b/scripts/bot/run-bot.sh
@@ -9,7 +9,6 @@ yarn
 echo 'Building Hubs'
 yarn build > /dev/null
 
-# install run-bot.js dependencies
 cd $script_directory
 echo 'Installing bot dependencies'
 yarn 
diff --git a/src/behaviours/msft-mr-axis-with-deadzone.js b/src/behaviours/msft-mr-axis-with-deadzone.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2b86fe8b5a0b645572a6bf27a2dfceb0449187b
--- /dev/null
+++ b/src/behaviours/msft-mr-axis-with-deadzone.js
@@ -0,0 +1,26 @@
+function msft_mr_axis_with_deadzone(el, outputPrefix) {
+  this.el = el;
+  this.outputPrefix = outputPrefix;
+  this.deadzone = 0.1;
+  this.emitAxisMoveWithDeadzone = this.emitAxisMoveWithDeadzone.bind(this);
+}
+
+msft_mr_axis_with_deadzone.prototype = {
+  addEventListeners: function() {
+    this.el.addEventListener("axismove", this.emitAxisMoveWithDeadzone);
+  },
+  removeEventListeners: function() {
+    this.el.removeEventListener("axismove", this.emitAxisMoveWithDeadzone);
+  },
+  emitAxisMoveWithDeadzone: function(event) {
+    const axis = event.detail.axis;
+    if (Math.abs(axis[0]) < this.deadzone && Math.abs(axis[1]) < this.deadzone) {
+      return;
+    }
+    // Reverse y
+    axis[1] = -axis[1];
+    this.el.emit("axisMoveWithDeadzone", event.detail);
+  }
+};
+
+export default msft_mr_axis_with_deadzone;
diff --git a/src/components/character-controller.js b/src/components/character-controller.js
index 174148d9c0109bde06e52f4cd68a89c798331208..2b86ff0a353b406d073238c8aca664197ff7084d 100644
--- a/src/components/character-controller.js
+++ b/src/components/character-controller.js
@@ -184,7 +184,15 @@ AFRAME.registerComponent("character-controller", {
       velocity.y -= velocity.y * data.easing * dt;
     }
 
-    // Clamp velocity easing.
+    const dvx = data.groundAcc * dt * this.accelerationInput.x;
+    const dvz = data.groundAcc * dt * -this.accelerationInput.z;
+    velocity.x += dvx;
+    velocity.z += dvz;
+
+    const decay = 0.7;
+    this.accelerationInput.x = this.accelerationInput.x * decay;
+    this.accelerationInput.z = this.accelerationInput.z * decay;
+
     if (Math.abs(velocity.x) < CLAMP_VELOCITY) {
       velocity.x = 0;
     }
@@ -194,14 +202,5 @@ AFRAME.registerComponent("character-controller", {
     if (Math.abs(velocity.z) < CLAMP_VELOCITY) {
       velocity.z = 0;
     }
-
-    const dvx = data.groundAcc * dt * this.accelerationInput.x;
-    const dvz = data.groundAcc * dt * -this.accelerationInput.z;
-    velocity.x += dvx;
-    velocity.z += dvz;
-
-    const decay = 0.7;
-    this.accelerationInput.x = this.accelerationInput.x * decay;
-    this.accelerationInput.z = this.accelerationInput.z * decay;
   }
 });
diff --git a/src/hub.js b/src/hub.js
index 20aecc2a9c3dceebe7b2825655e9258961d14ab2..35258cd35f7d907bdeb1fd8c59d90f72334d2449 100644
--- a/src/hub.js
+++ b/src/hub.js
@@ -22,6 +22,7 @@ import "./utils/audio-context-fix";
 
 import trackpad_dpad4 from "./behaviours/trackpad-dpad4";
 import joystick_dpad4 from "./behaviours/joystick-dpad4";
+import msft_mr_axis_with_deadzone from "./behaviours/msft-mr-axis-with-deadzone";
 import { PressedMove } from "./activators/pressedmove";
 import { ReverseY } from "./activators/reversey";
 import "./activators/shortpress";
@@ -130,15 +131,19 @@ function qsTruthy(param) {
   return val === null || /1|on|true/i.test(val);
 }
 
-registerTelemetry();
+const isBotMode = qsTruthy("bot");
+
+if (!isBotMode) {
+  registerTelemetry();
+}
 
 AFRAME.registerInputBehaviour("trackpad_dpad4", trackpad_dpad4);
 AFRAME.registerInputBehaviour("joystick_dpad4", joystick_dpad4);
+AFRAME.registerInputBehaviour("msft_mr_axis_with_deadzone", msft_mr_axis_with_deadzone);
 AFRAME.registerInputActivator("pressedmove", PressedMove);
 AFRAME.registerInputActivator("reverseY", ReverseY);
 AFRAME.registerInputMappings(inputConfig, true);
 
-const isBotMode = qsTruthy("bot");
 const concurrentLoadDetector = new ConcurrentLoadDetector();
 
 concurrentLoadDetector.start();
@@ -293,9 +298,11 @@ const onReady = async () => {
 
     if (!qsTruthy("offline")) {
       document.body.addEventListener("connected", () => {
-        hubChannel.sendEntryEvent().then(() => {
-          store.update({ activity: { lastEnteredAt: moment().toJSON() } });
-        });
+        if (!isBotMode) {
+          hubChannel.sendEntryEvent().then(() => {
+            store.update({ activity: { lastEnteredAt: moment().toJSON() } });
+          });
+        }
         remountUI({ occupantCount: NAF.connection.adapter.publisher.initialOccupants.length + 1 });
       });
 
diff --git a/src/input-mappings.js b/src/input-mappings.js
index 5413bbac75868938b92986d40c2e2aa21f0effb2..a1c4c06a2d7cf1f8442b81fee5cfa25821af90b5 100644
--- a/src/input-mappings.js
+++ b/src/input-mappings.js
@@ -27,7 +27,8 @@ const config = {
         trackpad: "trackpad_dpad4"
       },
       "windows-motion-controls": {
-        joystick: "joystick_dpad4"
+        joystick: "joystick_dpad4",
+        axisMoveWithDeadzone: "msft_mr_axis_with_deadzone"
       },
       "daydream-controls": {
         trackpad: "trackpad_dpad4"
@@ -106,7 +107,7 @@ const config = {
         trackpadtouchend: "thumb_up",
         triggerdown: ["action_grab", "index_down"],
         triggerup: ["action_release", "index_up"],
-        "axismove.reverseY": { left: "move" }
+        axisMoveWithDeadzone: { left: "move" }
       },
       "daydream-controls": {
         trackpad_dpad4_pressed_west_down: "snap_rotate_left",
diff --git a/src/network-schemas.js b/src/network-schemas.js
index d30176a299f5ff7fd5336509454910325c116e58..9e20a17ca68bf2d669fbeb68d78f665c94de2ed9 100644
--- a/src/network-schemas.js
+++ b/src/network-schemas.js
@@ -1,30 +1,46 @@
 function registerNetworkSchemas() {
+  const positionRequiresUpdate = (oldData, newData) => {
+    return !NAF.utils.almostEqualVec3(oldData, newData, 0.001);
+  };
+
+  const rotationRequiresUpdate = (oldData, newData) => {
+    return !NAF.utils.almostEqualVec3(oldData, newData, 0.5);
+  };
+
   NAF.schemas.add({
     template: "#remote-avatar-template",
     components: [
-      "position",
+      {
+        component: "position",
+        requiresNetworkUpdate: positionRequiresUpdate
+      },
       {
         component: "rotation",
-        lerp: false
+        lerp: false,
+        requiresNetworkUpdate: rotationRequiresUpdate
       },
       "scale",
       "player-info",
       "networked-avatar",
       {
         selector: ".camera",
-        component: "position"
+        component: "position",
+        requiresNetworkUpdate: positionRequiresUpdate
       },
       {
         selector: ".camera",
-        component: "rotation"
+        component: "rotation",
+        requiresNetworkUpdate: rotationRequiresUpdate
       },
       {
         selector: ".left-controller",
-        component: "position"
+        component: "position",
+        requiresNetworkUpdate: positionRequiresUpdate
       },
       {
         selector: ".left-controller",
-        component: "rotation"
+        component: "rotation",
+        requiresNetworkUpdate: rotationRequiresUpdate
       },
       {
         selector: ".left-controller",
@@ -32,11 +48,13 @@ function registerNetworkSchemas() {
       },
       {
         selector: ".right-controller",
-        component: "position"
+        component: "position",
+        requiresNetworkUpdate: positionRequiresUpdate
       },
       {
         selector: ".right-controller",
-        component: "rotation"
+        component: "rotation",
+        requiresNetworkUpdate: rotationRequiresUpdate
       },
       {
         selector: ".right-controller",
@@ -47,12 +65,30 @@ function registerNetworkSchemas() {
 
   NAF.schemas.add({
     template: "#video-template",
-    components: ["position", "rotation", "visible"]
+    components: [
+      {
+        component: "position"
+      },
+      {
+        component: "rotation"
+      },
+      "visible"
+    ]
   });
 
   NAF.schemas.add({
     template: "#interactable-template",
-    components: ["position", "rotation", "scale"]
+    components: [
+      {
+        component: "position",
+        requiresNetworkUpdate: positionRequiresUpdate
+      },
+      {
+        component: "rotation",
+        requiresNetworkUpdate: rotationRequiresUpdate
+      },
+      "scale"
+    ]
   });
 }
 
diff --git a/yarn.lock b/yarn.lock
index cc1b5ae12aacde99c092845e4ad4a16764c33b83..9f1d228ef4b5405d6abb35b06f0d53511d37171d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2016,8 +2016,8 @@ colormin@^1.0.5:
     has "^1.0.1"
 
 colors@*:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.3.tgz#1b152a9c4f6c9f74bc4bb96233ad0b7983b79744"
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.5.tgz#89c7ad9a374bc030df8013241f68136ed8835afc"
 
 colors@1.0.3:
   version "1.0.3"
@@ -5452,7 +5452,7 @@ neo-async@^2.5.0:
 
 "networked-aframe@https://github.com/mozillareality/networked-aframe#mr-social-client/master":
   version "0.6.1"
-  resolved "https://github.com/mozillareality/networked-aframe#641b5e44b8514d02925e3efb4289ca36a41c1006"
+  resolved "https://github.com/mozillareality/networked-aframe#424b41cfdf53db64033885da411c33685644db97"
   dependencies:
     easyrtc "1.1.0"
     express "^4.10.7"