diff --git a/scripts/bot/run-bot.js b/scripts/bot/run-bot.js
index d6851f97292f1cd978f9b3c72ad7d559dfccc0ee..44c1a8ef0e05332eca8fc8469712a8785be6489e 100644
--- a/scripts/bot/run-bot.js
+++ b/scripts/bot/run-bot.js
@@ -6,7 +6,7 @@ Usage:
 Options:
     -u --url=<url>    URL
     -o --host=<host>  Hubs host if URL is not specified [default: localhost:8080]
-    -r --room=<room>  Room id
+    -r --room=<room>  Room id [default: 234234]
     -h --help         Show this screen
 `;
 
@@ -20,8 +20,8 @@ const querystring = require("query-string");
   const browser = await puppeteer.launch({ ignoreHTTPSErrors: true });
   const page = await browser.newPage();
   page.on("console", msg => console.log("PAGE: ", msg.text()));
-  page.on("error", err => console.error("ERROR: ", err));
-  page.on("pageerror", err => console.error("PAGE ERROR: ", err));
+  page.on("error", err => console.error("ERROR: ", err.toString().split("\n")[0]));
+  page.on("pageerror", err => console.error("PAGE ERROR: ", err.toString().split("\n")[0]));
 
   const baseUrl = options["--url"] || `https://${options["--host"]}/hub.html`;
 
@@ -39,22 +39,36 @@ const querystring = require("query-string");
 
   const navigate = async () => {
     try {
+      console.log("Spawning bot...");
       await page.goto(url);
-      await page.evaluate(() => {
-        console.log(navigator.userAgent);
-      });
-      // Interact with the page so that audio can play.
-      await page.mouse.click(100, 100);
-      // Signal that the page has been interacted with.
-      // If the interacted function has not been defined yet, this will error and restart the process with the
-      // setTimeout below.
-      await page.evaluate(() => window.interacted());
+      await page.evaluate(() => console.log(navigator.userAgent));
+      let retryCount = 5;
+      let backoff = 1000;
+      const interact = async () => {
+        try {
+          // Interact with the page so that audio can play.
+          await page.mouse.click(100, 100);
+          // Signal that the page has been interacted with.
+          await page.evaluate(() => window.interacted());
+          console.log("Interacted.");
+        } catch (e) {
+          console.log("Interaction error", e.message);
+          if (retryCount-- < 0) {
+            // If retries failed, throw and restart navigation.
+            throw new Error("Retries failed");
+          }
+          console.log("Retrying...");
+          backoff *= 2;
+          // Retry interaction to start audio playback
+          setTimeout(interact, backoff);
+        }
+      };
+      await interact();
     } catch (e) {
-      console.log("Navigation error", e.toString());
+      console.log("Navigation error", e.message);
       setTimeout(navigate, 1000);
     }
   };
 
-  console.log("Spawning bot...");
   navigate();
 })();
diff --git a/src/hub.js b/src/hub.js
index da390d985ebe8204892f55b7379719a8b19d26e6..a9f63cc3c7f72d02f38ca2fd7b424a1759a14508 100644
--- a/src/hub.js
+++ b/src/hub.js
@@ -336,7 +336,7 @@ const onReady = async () => {
         });
         const audio = document.getElementById("bot-recording");
         mediaStream.addTrack(audio.captureStream().getAudioTracks()[0]);
-        // wait for runner script to interact with the page so that we can play audio.
+        // Wait for runner script to interact with the page so that we can play audio.
         await new Promise(resolve => {
           window.interacted = resolve;
         });
@@ -400,6 +400,11 @@ const onReady = async () => {
       // Stop rendering while the UI is up. We restart the render loop in enterScene.
       // Wait a tick plus some margin so that the environments actually render.
       setTimeout(() => scene.renderer.animate(null), 100);
+    } else {
+      const noop = () => {};
+      // Replace renderer with a noop renderer to reduce bot resource usage.
+      scene.renderer = { animate: noop, render: noop };
+      document.body.style.display = "none";
     }
   });
   environmentRoot.appendChild(initialEnvironmentEl);