
Open a handful of browser tabs on wp-admin, walk away for coffee, and come back to find your server quietly grinding through hundreds of requests to admin-ajax.php. That is the Heartbeat API doing its job, just not the job you thought you signed up for. It is one of the most common, and most fixable, causes of CPU pressure on busy WordPress installs.
What the Heartbeat API Actually Does
WordPress core ships with a JavaScript-based pulse that runs in the browser whenever an admin screen (and, in some themes, the front end) is open. Every few seconds it fires an AJAX call to admin-ajax.php, which WordPress uses for things like:
- Post locking, so two editors do not overwrite each other’s work
- Autosave, which quietly saves drafts while you type
- Live session checks, such as warning you when you have been logged out
- Plugin and theme dashboard widgets that poll for updates
By default the interval is 15 seconds on most admin screens, sometimes faster on the post editor. That is reasonable for one editor. It stops being reasonable when a dozen staff members leave the dashboard open in a tab all day, or when a plugin adds its own heartbeat-driven polling on top of core’s.
Why It Hammers Your Server
Every heartbeat tick is a full PHP request. Unlike a page view, admin-ajax.php is not served by full-page cache, LiteSpeed or otherwise, because it is a dynamic, logged-in, POST-based endpoint. Each call still bootstraps WordPress, runs any hooked callbacks, and often touches the database for post locks or transients. Multiply that by every open admin tab, every few seconds, all day, and you have a steady background drone of PHP-FPM workers being consumed by a feature nobody is actively watching.
This matters more on shared or resource-capped hosting where PHP worker slots are finite. If Heartbeat is quietly consuming several workers at once, real visitor traffic and legitimate admin actions start queuing behind it. On a well-tuned stack running PHP 8.3 with OPcache, each individual heartbeat request is cheap to execute, but cheap times thousands adds up. Persistent object caching via Redis also helps here, since post-lock and transient lookups that would otherwise round-trip to MySQL on every tick can be served from memory instead. Tuning the interval reduces the number of round trips in the first place, which is the bigger lever.
Diagnosing Heartbeat Load
Before changing anything, confirm Heartbeat is actually your problem. A few reliable signals:
- Check your server access logs (or your host’s request log) for a high volume of POST requests to
admin-ajax.phpwithaction=heartbeatin the payload. - Use a browser’s network tab while sitting on an admin screen. If you see recurring calls to
admin-ajax.phpevery 15 to 60 seconds, that is Heartbeat. - Check
wp-clifor active plugins that might be adding their own polling logic on top of core’s heartbeat, since some page builders and analytics dashboards do this:
wp plugin list --status=activeIf the volume correlates with the number of logged-in editors and their open tabs, you have found your culprit.
Safe Ways to Tune the Interval
WordPress exposes a filter specifically for this. The cleanest approach is a small must-use plugin, since it survives theme changes and does not get disabled by accident:
<?php
/**
* Slow down the Heartbeat API on admin screens.
*/
add_filter( 'heartbeat_settings', function ( $settings ) {
$settings['interval'] = 60; // seconds
return $settings;
} );Save that as a file in wp-content/mu-plugins/ and it applies immediately, no activation step required. An interval of 45 to 60 seconds is a reasonable default for most sites. It keeps post locking and autosave functional while cutting request volume by a factor of three or four compared to the 15-second default.
If you need finer control, target specific screens using the $_POST['screen_id'] value passed into the filter, so the post editor keeps a tighter interval for autosave while other admin pages back off further:
add_filter( 'heartbeat_settings', function ( $settings ) {
if ( isset( $_POST['screen_id'] ) && 'edit-post' !== $_POST['screen_id'] ) {
$settings['interval'] = 60;
}
return $settings;
} );Disabling Heartbeat Where It Doesn’t Belong
Some themes and plugins load the Heartbeat script on the front end for logged-in visitors, typically to support live notifications or session checks that most sites do not need. If you do not rely on front-end features that depend on it, deregister it there entirely:
add_action( 'init', function () {
if ( ! is_admin() ) {
wp_deregister_script( 'heartbeat' );
}
} );You can also disable Heartbeat entirely on the WordPress dashboard home screen, since the dashboard widgets that use it (activity feeds, site health checks) are the least critical consumers:
add_filter( 'heartbeat_settings', function ( $settings ) {
global $pagenow;
if ( 'index.php' === $pagenow ) {
$settings['interval'] = 60;
}
return $settings;
} );If you would rather not manage code snippets by hand, several well-maintained plugins expose these same controls through a settings screen. That is a fine choice for teams without a developer on call, as long as you pick one that is actively maintained and only touches the documented heartbeat_settings filter rather than hacking the script directly.
When to Leave It Alone
Do not disable Heartbeat outright on the post editor screen if multiple people co-author content. Post locking depends on it, and turning it off entirely means two editors can silently overwrite each other’s drafts, which is a worse outcome than a bit of extra CPU load. The goal is slowing the pulse, not stopping the heart.
Takeaway
The Heartbeat API is a genuinely useful feature that just defaults to a pace built for occasional single-editor use, not a busy multi-author dashboard left open in ten browser tabs. A short mu-plugin that widens the interval to 45 to 60 seconds, combined with disabling it on screens and front-end contexts that do not need it, typically cuts admin-ajax load dramatically without giving up autosave or post locking. Pair that with a persistent object cache like Redis to keep the remaining lock and transient lookups fast, and Heartbeat goes back to being invisible infrastructure instead of a CPU line item.