diff --git a/core/js/js.js b/core/js/js.js
index ac1d582a9f894e164a47b8b69db7fdf76a1ec8ce..1d3ec6ec778a731a5af89601bf52b9dcb01ec1fe 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -1499,9 +1499,15 @@ function initCore() {
 			interval = maxInterval;
 		}
 		var url = OC.generateUrl('/heartbeat');
-		setInterval(function(){
-			$.post(url);
-		}, interval * 1000);
+		var heartBeatTimeout = null;
+		var heartBeat = function() {
+			clearTimeout(heartBeatTimeout);
+			heartBeatTimeout = setInterval(function() {
+				$.post(url);
+			}, interval * 1000);
+		};
+		$(document).ajaxComplete(heartBeat);
+		heartBeat();
 	}
 
 	// session heartbeat (defaults to enabled)
diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js
index 83441104289a10cebf1b65cf00ea1abad6e43a69..02eb1b95c1d3e2b2ae87466d7cb6f9320318dad9 100644
--- a/core/js/tests/specs/coreSpec.js
+++ b/core/js/tests/specs/coreSpec.js
@@ -305,6 +305,7 @@ describe('Core base tests', function() {
 				counter++;
 				xhr.respond(200, {'Content-Type': 'application/json'}, '{}');
 			});
+			$(document).off('ajaxComplete'); // ignore previously registered heartbeats
 		});
 		afterEach(function() {
 			clock.restore();
@@ -312,6 +313,7 @@ describe('Core base tests', function() {
 			window.oc_config = oldConfig;
 			routeStub.restore();
 			$(document).off('ajaxError');
+			$(document).off('ajaxComplete');
 		});
 		it('sends heartbeat half the session lifetime when heartbeat enabled', function() {
 			/* jshint camelcase: false */
@@ -340,7 +342,7 @@ describe('Core base tests', function() {
 			clock.tick(20 * 1000);
 			expect(counter).toEqual(2);
 		});
-		it('does no send heartbeat when heartbeat disabled', function() {
+		it('does not send heartbeat when heartbeat disabled', function() {
 			/* jshint camelcase: false */
 			window.oc_config = {
 				session_keepalive: false,