diff --git a/applications/gui/src/screen.cpp b/applications/gui/src/screen.cpp
index 71dc9e38a1e1a55b2c4bbe8ba7590ae3a635c7dc..4a65046aa5262c0cccc5946779d264b72588b6f6 100644
--- a/applications/gui/src/screen.cpp
+++ b/applications/gui/src/screen.cpp
@@ -81,6 +81,7 @@ ftl::gui::Screen::Screen(ftl::Configurable *proot, ftl::net::Universe *pnet, ftl
 	ctrl_ = controller;
 	root_ = proot;
 	camera_ = nullptr;
+	last_stats_count_ = 0;
 
 	#ifdef HAVE_OPENVR
 	HMD_ = nullptr;
@@ -590,15 +591,14 @@ void ftl::gui::Screen::draw(NVGcontext *ctx) {
 	if (root()->value("show_information", true)) {
 		string msg;
 
-		// FIXME: Do not do this every frame, or cache the results every N frames...
+		auto &stats = getStatistics();
 
-		auto [fps,latency] = ftl::rgbd::Builder::getStatistics();
-		msg = string("Frame rate: ") + std::to_string((int)fps);
+		msg = string("Frame rate: ") + std::to_string((int)stats.fps);
 		nvgText(ctx, screenSize[0]-10, 20, msg.c_str(), NULL);
-		msg = string("Latency: ") + std::to_string((int)latency) + string("ms");
+		msg = string("Latency: ") + std::to_string((int)stats.latency) + string("ms");
 		nvgText(ctx, screenSize[0]-10, 40, msg.c_str(), NULL);	
 
-		msg = string("Bitrate: ") + to_string_with_precision(ftl::stream::Net::getRequiredBitrate(), 2) + string("Mbps");
+		msg = string("Bitrate: ") + to_string_with_precision(stats.bitrate, 2) + string("Mbps");
 		nvgText(ctx, screenSize[0]-10, 60, msg.c_str(), NULL);
 
 		if (camera_) {
@@ -617,6 +617,17 @@ void ftl::gui::Screen::draw(NVGcontext *ctx) {
 	nanogui::Screen::draw(ctx);
 }
 
+const ftl::gui::Statistics &ftl::gui::Screen::getStatistics() {
+	if (--last_stats_count_ <= 0) {
+		auto [fps,latency] = ftl::rgbd::Builder::getStatistics();
+		stats_.fps = fps;
+		stats_.latency = latency;
+		stats_.bitrate = ftl::stream::Net::getRequiredBitrate();
+		last_stats_count_ = 20;
+	}
+	return stats_;
+}
+
 void ftl::gui::Screen::drawFast() {
 	if (camera_) {
 		camera_->captureFrame();
diff --git a/applications/gui/src/screen.hpp b/applications/gui/src/screen.hpp
index c87ff2ff9ab3ee8780ba991a4d09b325c9225364..4f683bef4173d266838dff82ecca6b44bcab282f 100644
--- a/applications/gui/src/screen.hpp
+++ b/applications/gui/src/screen.hpp
@@ -23,6 +23,12 @@ namespace gui {
 class Camera;
 class MediaPanel;
 
+struct Statistics {
+	float fps;
+	float latency;
+	float bitrate;
+};
+
 class Screen : public nanogui::Screen {
 	public:
 	explicit Screen(ftl::Configurable *root, ftl::net::Universe *net, ftl::ctrl::Master *controller);
@@ -46,6 +52,8 @@ class Screen : public nanogui::Screen {
 	void setActiveCamera(ftl::gui::Camera*);
 	ftl::gui::Camera *activeCamera() { return camera_; }
 
+	const ftl::gui::Statistics &getStatistics();
+
 #ifdef HAVE_OPENVR
 	// initialize OpenVR
 	bool initVR();
@@ -108,6 +116,9 @@ class Screen : public nanogui::Screen {
 	#ifdef HAVE_OPENVR
 	vr::IVRSystem *HMD_;
 	#endif
+
+	ftl::gui::Statistics stats_;
+	int last_stats_count_;
 };
 
 }
diff --git a/applications/vision/src/main.cpp b/applications/vision/src/main.cpp
index 3f8dca5abd7fa299d903f0c2cf4969b1c5dda4f6..07e6b4ae547bf7ec960d0d01ac74285f840d4595 100644
--- a/applications/vision/src/main.cpp
+++ b/applications/vision/src/main.cpp
@@ -75,9 +75,17 @@ static void run(ftl::Configurable *root) {
 	source->setChannel(Channel::Depth);
 	grp->addSource(source);
 
-	grp->onFrameSet([sender](ftl::rgbd::FrameSet &fs) {
+	int stats_count = 0;
+
+	grp->onFrameSet([sender,&stats_count](ftl::rgbd::FrameSet &fs) {
 		fs.id = 0;
 		sender->post(fs);
+
+		if (--stats_count <= 0) {
+			auto [fps,latency] = ftl::rgbd::Builder::getStatistics();
+			LOG(INFO) << "Frame rate: " << fps << ", Latency: " << latency;
+			stats_count = 20;
+		}
 		return true;
 	});
 
diff --git a/components/streams/src/parsers.cpp b/components/streams/src/parsers.cpp
index 9a5f1ee29dd6b3fc8193b5a1bc33dc98f0198e38..95c521da670eaead6ac6723e4636e9b1440d8b2e 100644
--- a/components/streams/src/parsers.cpp
+++ b/components/streams/src/parsers.cpp
@@ -10,11 +10,11 @@ ftl::rgbd::Camera ftl::stream::parseCalibration(const ftl::codecs::Packet &pkt)
 	auto unpacked = msgpack::unpack((const char*)pkt.data.data(), pkt.data.size());
 	unpacked.get().convert(params);
 
-	LOG(INFO) << "Got Calibration: "
-			  << std::get<0>(params).width << "x" << std::get<0>(params).height
-			  << ", fx: " << std::get<0>(params).fx
-			  << ", cx: " << std::get<0>(params).cx
-			  << ", cy: " << std::get<0>(params).cy;
+	//LOG(INFO) << "Got Calibration: "
+	//		  << std::get<0>(params).width << "x" << std::get<0>(params).height
+	//		  << ", fx: " << std::get<0>(params).fx
+	//		  << ", cx: " << std::get<0>(params).cx
+	//		  << ", cy: " << std::get<0>(params).cy;
 	
 	return std::get<0>(params);
 }
@@ -40,6 +40,6 @@ std::string ftl::stream::parseConfig(const ftl::codecs::Packet &pkt) {
 	auto unpacked = msgpack::unpack((const char*)pkt.data.data(), pkt.data.size());
 	unpacked.get().convert(cfg);
 
-	LOG(INFO) << "Config Received: " << cfg;
+	//LOG(INFO) << "Config Received: " << cfg;
 	return cfg;
 }