diff --git a/core/js/js.js b/core/js/js.js
index 598e0dcd185ec1cb53148a6e68528b92900e6809..802b5de7e186f38f299ef219eee0bca771fef17a 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -1498,9 +1498,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 f18ecbc1a448cf6e3eea3e50f94f4a2b0dfbb97c..09271f1ab9aaa17a2c0bfcfa1e5f323314359c6b 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,