diff --git a/src/hub.js b/src/hub.js
index 8bd8e2a29f9dbe957b0c20cd2798c160fbe7ede0..4a19c796d2377f797eda59a30bb6fdd8fb7b5dca 100644
--- a/src/hub.js
+++ b/src/hub.js
@@ -6,6 +6,7 @@ import { patchWebGLRenderingContext } from "./utils/webgl";
 patchWebGLRenderingContext();
 
 import "aframe-xr";
+import debug from "debug";
 import "./vendor/GLTFLoader";
 import "networked-aframe/src/index";
 import "naf-janus-adapter";
@@ -129,11 +130,19 @@ function qsTruthy(param) {
 }
 
 const isBotMode = qsTruthy("bot");
+const isTelemetryDisabled = qsTruthy("disable_telemetry");
+const isDebug = qsTruthy("debug");
+const logFilter = qs["log_filter"] || (isDebug && "naf-janus-adapter:*");
 
-if (!isBotMode) {
+if (!isBotMode && !isTelemetryDisabled) {
   registerTelemetry();
 }
 
+// NOTE: this needs to happen after a-frame's `utils/debug.js` file has been eval'ed because it overwrites any prior debug settings :/
+if (logFilter) {
+  debug.enable(logFilter);
+}
+
 disableiOSZoom();
 
 AFRAME.registerInputBehaviour("trackpad_dpad4", trackpad_dpad4);
@@ -237,7 +246,8 @@ const onReady = async () => {
 
     scene.setAttribute("networked-scene", {
       room: hubId,
-      serverURL: process.env.JANUS_SERVER
+      serverURL: process.env.JANUS_SERVER,
+      debug: isDebug
     });
 
     scene.setAttribute("stats-plus", false);
@@ -310,12 +320,17 @@ const onReady = async () => {
       scene.components["networked-scene"].connect().catch(connectError => {
         // hacky until we get return codes
         const isFull = connectError.error && connectError.error.msg.match(/\bfull\b/i);
+        console.error(connectError);
         remountUI({ roomUnavailableReason: isFull ? "full" : "connect_error" });
         exitScene();
 
         return;
       });
 
+      if (isDebug) {
+        NAF.connection.adapter.session.options.verbose = true;
+      }
+
       if (isBotMode) {
         playerRig.setAttribute("avatar-replay", {
           camera: "#player-camera",