diff --git a/applications/gui2/src/modules/camera.cpp b/applications/gui2/src/modules/camera.cpp
index f0c2b77046bc94ca981949972a30c52f6e7f79e6..5d019915249c5860f5d3ca60b5a21cdd599e81d4 100644
--- a/applications/gui2/src/modules/camera.cpp
+++ b/applications/gui2/src/modules/camera.cpp
@@ -73,8 +73,13 @@ void Camera::update(double delta) {
 				auto &jmeta = mod->getJSON(StatisticsPanel::MEDIA_META);
 
 				if (caps.count(Capability::TOUCH)) jmeta["Touch"] = nlohmann::json{{"icon", ENTYPO_ICON_MOUSE_POINTER},{"value", true}};
+				else jmeta.erase("Touch");
+
 				if (caps.count(Capability::MOVABLE)) jmeta["Movable"] = nlohmann::json{{"icon", ENTYPO_ICON_COMPASS},{"value", true}};
+				else jmeta.erase("Movable");
+
 				if (caps.count(Capability::VR)) jmeta["VR"] = nlohmann::json{{"value", true}};
+				else jmeta.erase("VR");
 			}
 
 			std::list<ftl::data::Message> messages;
@@ -105,6 +110,27 @@ void Camera::update(double delta) {
 	}
 }
 
+void Camera::_updateCapabilities(ftl::data::Frame &frame) {
+	if (frame.has(Channel::Capabilities)) {
+		live_ = false;
+		touch_ = false;
+		movable_ = false;
+		vr_ = false;
+
+		const auto &cap = frame.get<std::unordered_set<Capability>>(Channel::Capabilities);
+
+		for (auto c : cap) {
+			switch (c) {
+			case Capability::LIVE		: live_ = true; break;
+			case Capability::TOUCH		: touch_ = true; break;
+			case Capability::MOVABLE	: movable_ = true; break;
+			case Capability::VR			: vr_ = true; break;
+			default: break;
+			}
+		}
+	}
+}
+
 void Camera::initiate_(ftl::data::Frame &frame) {
 	if (frame.has(Channel::Capabilities)) {
 		const auto &cap = frame.get<std::unordered_set<Capability>>(Channel::Capabilities);
@@ -148,12 +174,9 @@ void Camera::initiate_(ftl::data::Frame &frame) {
 		auto *mod = this->screen->getModule<ftl::gui2::Statistics>();
 		
 		mod->getJSON(StatisticsPanel::PERFORMANCE_INFO).erase("FPS");
-		mod->getJSON(StatisticsPanel::MEDIA_STATUS).erase("LIVE");
-		mod->getJSON(StatisticsPanel::MEDIA_META).erase("Device");
-		mod->getJSON(StatisticsPanel::MEDIA_META).erase("Serial");
-		mod->getJSON(StatisticsPanel::CAMERA_DETAILS).erase("Focal");
-		mod->getJSON(StatisticsPanel::CAMERA_DETAILS).erase("Resolution");
-		mod->getJSON(StatisticsPanel::CAMERA_DETAILS).erase("Principle");
+		mod->getJSON(StatisticsPanel::MEDIA_STATUS).clear();
+		mod->getJSON(StatisticsPanel::MEDIA_META).clear();
+		mod->getJSON(StatisticsPanel::CAMERA_DETAILS).clear();
 	});
 
 	setChannel(channel);
@@ -219,6 +242,7 @@ void Camera::activate(ftl::data::FrameID id) {
 				//cv.notify_one();
 			}
 
+			// Extract and record any frame messages
 			auto &frame = fs->frames[frame_idx];
 			if (frame.has(Channel::Messages)) {
 				const auto &msgs = frame.get<std::list<ftl::data::Message>>(Channel::Messages);
@@ -228,6 +252,11 @@ void Camera::activate(ftl::data::FrameID id) {
 				messages_.insert(messages_.end(), msgs.begin(), msgs.end());
 			}
 
+			// Some capabilities can change over time
+			if (frame.changed(Channel::Capabilities)) {
+				_updateCapabilities(frame);
+			}
+
 			if (!view) return true;
 
 			if (live_ && touch_) {
@@ -308,7 +337,7 @@ ftl::cuda::TextureObject<uchar4>& Camera::getFrame() {
 		if (frame.hasChannel(channel)) {
 			current_frame_ = colouriser_->colourise(frame, channel, 0);
 		} else {
-			LOG(WARNING) << "Channel missing: " << int(channel) << " - " << frame.timestamp();
+			throw FTL_Error("Channel missing for frame " << frame.timestamp() << ": '" << ftl::codecs::name(channel) << "'");
 		}
 		std::atomic_store(&current_fs_, {});
 	}
diff --git a/applications/gui2/src/modules/camera.hpp b/applications/gui2/src/modules/camera.hpp
index 0b18f33ee545de28ee8cea21b0155365b6b14905..a33a1950c3ca762874cdb6fb2a1002902d5bbdff 100644
--- a/applications/gui2/src/modules/camera.hpp
+++ b/applications/gui2/src/modules/camera.hpp
@@ -86,6 +86,7 @@ private:
 	MUTEX mtx_;
 
 	void initiate_(ftl::data::Frame &frame);
+	void _updateCapabilities(ftl::data::Frame &frame);
 };
 
 }
diff --git a/components/rgbd-sources/src/sources/screencapture/screencapture.cpp b/components/rgbd-sources/src/sources/screencapture/screencapture.cpp
index 42c4da7f94c0219d2235078c1dccaca5f769501e..b893cd049ba854cfd410a80858b03e5d6a8f333f 100644
--- a/components/rgbd-sources/src/sources/screencapture/screencapture.cpp
+++ b/components/rgbd-sources/src/sources/screencapture/screencapture.cpp
@@ -205,7 +205,7 @@ ScreenCapture::ScreenCapture(ftl::rgbd::Source *host)
 	});
 
 	host_->on("enable_touch", [this](const ftl::config::Event &e) {
-		do_update_params_;
+		do_update_params_ = true;
 	});
 }
 
@@ -348,13 +348,13 @@ bool ScreenCapture::retrieve(ftl::rgbd::Frame &frame) {
 		meta["uri"] = host_->value("uri", std::string(""));
 		meta["device"] = std::string("X11 Screen Capture");
 
-		if (!frame.has(Channel::Capabilities)) {
+		//if (!frame.has(Channel::Capabilities)) {
 			auto &cap = frame.create<std::unordered_set<Capability>>(Channel::Capabilities);
+			cap.clear();
 			cap.emplace(Capability::VIDEO);
 			cap.emplace(Capability::LIVE);
-			//if (host_->value("enable_touch", false))
-			cap.emplace(Capability::TOUCH);
-		}
+			if (host_->value("enable_touch", false)) cap.emplace(Capability::TOUCH);
+		//}
 
 		do_update_params_ = false;
 	}