diff --git a/Nibriboard/Client/NibriClient.cs b/Nibriboard/Client/NibriClient.cs
index 7fc669f..8e53ca5 100644
--- a/Nibriboard/Client/NibriClient.cs
+++ b/Nibriboard/Client/NibriClient.cs
@@ -42,7 +42,8 @@ namespace Nibriboard.Client
 
 		private static readonly Dictionary<string, Type> messageEventTypes = new Dictionary<string, Type>()
 		{
-			["handshakeRequest"] = typeof(HandshakeRequestMessage)
+			["HandshakeRequest"] = typeof(HandshakeRequestMessage),
+			["CursorPosition"] = typeof(CursorPositionMessage)
 		};
 
 		/// <summary>
@@ -92,7 +93,10 @@ namespace Nibriboard.Client
 				//Task.Run(async () => await onMessage(frame)).Wait();
 			};
 			// Store whether this NibriClient is still connected or not
-			client.ConnectionClosed += (WebSocket socket) => Connected = false;
+			client.ConnectionClosed += (WebSocket socket) => {
+				Connected = false;
+				Disconnected(this);
+			};
 		}
 
 		private async Task handleMessage(string frame)
diff --git a/Nibriboard/ClientFiles/BoardWindow.js b/Nibriboard/ClientFiles/BoardWindow.js
index 5a4754f..9ed3a84 100644
--- a/Nibriboard/ClientFiles/BoardWindow.js
+++ b/Nibriboard/ClientFiles/BoardWindow.js
@@ -7,6 +7,7 @@ window.panzoom = require("pan-zoom");
 
 // Our files
 import RippleLink from './RippleLink';
+import CursorSyncer from './CursorSyncer';
 import { get } from './Utilities';
 
 class BoardWindow extends EventEmitter
@@ -17,7 +18,9 @@ class BoardWindow extends EventEmitter
 		
 		// The maximum target fps.
 		this.maxFps = 60;
-		// Setup the fps indicator in the corner
+		// The target fps at which we should send sursor updates.
+		this.cursorUpdateFrequency = 5;
+		// Setup the fps indicator in the top right corner
 		this.renderTimeIndicator = document.createElement("span");
 		this.renderTimeIndicator.innerHTML = "0ms";
 		document.querySelector(".fps").appendChild(this.renderTimeIndicator);
@@ -50,8 +53,6 @@ class BoardWindow extends EventEmitter
 		
 		// Make the canvas track the window size
 		this.trackWindowSize();
-		// Track the mouse position
-		this.trackMousePosition();
 	}
 	
 	/**
@@ -63,7 +64,7 @@ class BoardWindow extends EventEmitter
 		this.rippleLink.on("connect", (function(event) {
 			// Send the handshake request
 			this.rippleLink.send({
-				event: "handshakeRequest",
+				event: "HandshakeRequest",
 				InitialViewport: { // TODO: Add support for persisting this between sessions
 					X: 0,
 					Y: 0,
@@ -74,6 +75,9 @@ class BoardWindow extends EventEmitter
 			});
 		}).bind(this));
 		
+		// Track the mouse position
+		this.cursorSyncer = new CursorSyncer(this.rippleLink, this.cursorUpdateFrequency)
+		
 		// RippleLink message bindings
 		
 	}
@@ -140,15 +144,6 @@ class BoardWindow extends EventEmitter
 		window.addEventListener("resize", this.matchWindowSize.bind(this));
 	}
 	
-	trackMousePosition() {
-		document.addEventListener("mousemove", (function(event) {
-			this.cursorPosition = {
-				X: event.clientX,
-				Y: event.clientY
-			};
-		}).bind(this));
-	}
-	
 	/**
 	 * Handles events generated by pan-zoom, the package that handles the
 	 * dragging and zooming of the whiteboard.
diff --git a/Nibriboard/ClientFiles/CursorSyncer.js b/Nibriboard/ClientFiles/CursorSyncer.js
new file mode 100644
index 0000000..4ceea18
--- /dev/null
+++ b/Nibriboard/ClientFiles/CursorSyncer.js
@@ -0,0 +1,56 @@
+"use strict";
+
+class CursorSyncer
+{
+	constructor(inRippleLink, syncFrequency)
+	{
+		// The ripple link we should send the cursor updates down
+		this.rippleLink = inRippleLink;
+		// The target frequency in fps at we should send sursor updates.
+		this.cursorUpdateFrequency = syncFrequency;
+		
+		// Register ourselves to start sending cursor updates once the ripple
+		// link connects
+		this.rippleLink.on("connect", this.setup.bind(this));
+	}
+	
+	setup()
+	{
+		// The last time we sent a cursor update to the server.
+		this.lastCursorUpdate = 0;
+		
+		document.addEventListener("mousemove", (function(event) {
+			this.cursorPosition = {
+				X: event.clientX,
+				Y: event.clientY
+			};
+			
+			setTimeout((function() {
+			    // Throttle the cursor updates we send to the server - a high
+			    // update frequency here will just consume bandwidth and is only
+			    // noticable if you have a good connection
+				if(+new Date() - this.lastCursorUpdate < 1 / this.cursorUpdateFrequency)
+					return false;
+					
+				// Update the server on the mouse's position
+				this.sendCursorUpdate();
+				
+				this.lastFrameStart = +new Date();
+			}).bind(this), 1 / this.cursorUpdateFrequency);
+			
+		}).bind(this));
+		
+		this.sendCursorUpdate();
+	}
+	
+	sendCursorUpdate()
+	{
+		// Update the server on the mouse's position
+		this.rippleLink.send({
+			"event": "CursorPosition",
+			"AbsCursorPosition": this.cursorPosition
+		});
+	}
+}
+
+export default CursorSyncer;
diff --git a/Nibriboard/ClientFiles/NibriClient.js b/Nibriboard/ClientFiles/NibriClient.js
index 65985c5..0c68dcd 100644
--- a/Nibriboard/ClientFiles/NibriClient.js
+++ b/Nibriboard/ClientFiles/NibriClient.js
@@ -87,6 +87,59 @@ class RippleLink extends EventEmitter$1
 	}
 }
 
+class CursorSyncer
+{
+	constructor(inRippleLink, syncFrequency)
+	{
+		// The ripple link we should send the cursor updates down
+		this.rippleLink = inRippleLink;
+		// The target frequency in fps at we should send sursor updates.
+		this.cursorUpdateFrequency = syncFrequency;
+		
+		// Register ourselves to start sending cursor updates once the ripple
+		// link connects
+		this.rippleLink.on("connect", this.setup.bind(this));
+	}
+	
+	setup()
+	{
+		// The last time we sent a cursor update to the server.
+		this.lastCursorUpdate = 0;
+		
+		document.addEventListener("mousemove", (function(event) {
+			this.cursorPosition = {
+				X: event.clientX,
+				Y: event.clientY
+			};
+			
+			setTimeout((function() {
+			    // Throttle the cursor updates we send to the server - a high
+			    // update frequency here will just consume bandwidth and is only
+			    // noticable if you have a good connection
+				if(+new Date() - this.lastCursorUpdate < 1 / this.cursorUpdateFrequency)
+					return false;
+					
+				// Update the server on the mouse's position
+				this.sendCursorUpdate();
+				
+				this.lastFrameStart = +new Date();
+			}).bind(this), 1 / this.cursorUpdateFrequency);
+			
+		}).bind(this));
+		
+		this.sendCursorUpdate();
+	}
+	
+	sendCursorUpdate()
+	{
+		// Update the server on the mouse's position
+		this.rippleLink.send({
+			"event": "CursorPosition",
+			"AbsCursorPosition": this.cursorPosition
+		});
+	}
+}
+
 function get(u){return new Promise(function(r,t,a){a=new XMLHttpRequest();a.onload=function(b,c){b=a.status;c=a.response;if(b>199&&b<300){r(c);}else{t(c);}};a.open("GET",u,true);a.send(null);})}
 
 // npm modules
@@ -103,7 +156,9 @@ class BoardWindow extends EventEmitter
 		
 		// The maximum target fps.
 		this.maxFps = 60;
-		// Setup the fps indicator in the corner
+		// The target fps at which we should send sursor updates.
+		this.cursorUpdateFrequency = 5;
+		// Setup the fps indicator in the top right corner
 		this.renderTimeIndicator = document.createElement("span");
 		this.renderTimeIndicator.innerHTML = "0ms";
 		document.querySelector(".fps").appendChild(this.renderTimeIndicator);
@@ -136,8 +191,6 @@ class BoardWindow extends EventEmitter
 		
 		// Make the canvas track the window size
 		this.trackWindowSize();
-		// Track the mouse position
-		this.trackMousePosition();
 	}
 	
 	/**
@@ -149,7 +202,7 @@ class BoardWindow extends EventEmitter
 		this.rippleLink.on("connect", (function(event) {
 			// Send the handshake request
 			this.rippleLink.send({
-				event: "handshakeRequest",
+				event: "HandshakeRequest",
 				InitialViewport: { // TODO: Add support for persisting this between sessions
 					X: 0,
 					Y: 0,
@@ -160,6 +213,9 @@ class BoardWindow extends EventEmitter
 			});
 		}).bind(this));
 		
+		// Track the mouse position
+		this.cursorSyncer = new CursorSyncer(this.rippleLink, this.cursorUpdateFrequency);
+		
 		// RippleLink message bindings
 		
 	}
@@ -226,15 +282,6 @@ class BoardWindow extends EventEmitter
 		window.addEventListener("resize", this.matchWindowSize.bind(this));
 	}
 	
-	trackMousePosition() {
-		document.addEventListener("mousemove", (function(event) {
-			this.cursorPosition = {
-				X: event.clientX,
-				Y: event.clientY
-			};
-		}).bind(this));
-	}
-	
 	/**
 	 * Handles events generated by pan-zoom, the package that handles the
 	 * dragging and zooming of the whiteboard.
