If your server’s access log is full of POST /wp-admin/admin-ajax.php requests, or your hosting resources spike whenever editors have the dashboard open, the WordPress Heartbeat API is a likely cause. Heartbeat is useful, but it’s chatty by default. Here’s what it does and how to tune it.
What Heartbeat does
Heartbeat is a JavaScript timer in the browser that sends a request to admin-ajax.php (action heartbeat) every 15–60 seconds while a WordPress page is open. It powers:
- Autosave and revisions while editing posts;
- Post locking: “This post is being edited by another user”;
- Session expiry warnings (the login pop-up when your session expires);
- real-time notifications from plugins (WooCommerce, page builders, form plugins, and more).
Why it can hurt performance
Each heartbeat is a full WordPress PHP request: it loads WordPress and all active plugins. That’s not cached, and it’s not cheap. Examples:
- Five editors with 3 tabs open each, every 15 seconds → 60 PHP requests per minute with no visitors at all.
- An admin tab left open overnight keeps pinging.
- On small servers, these requests take PHP-FPM workers away from real visitors, and push CPU up.
Check for yourself:
grep 'admin-ajax.php' /var/log/nginx/access.log | wc -l
grep 'admin-ajax.php' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head
Some admin-ajax traffic comes from plugins (front-end AJAX), not Heartbeat. The Query Monitor plugin, or browser DevTools, shows the action parameter. See Nginx access logs.
Option 1: slow it down (recommended)
Increase the interval to 60 seconds (or up to 120) in a small site-specific plugin, or in the theme’s functions.php:
add_filter( 'heartbeat_settings', function ( $settings ) {
$settings['interval'] = 60; // seconds (15–120)
return $settings;
} );
Autosave and post locking keep working, just less frequently.
Option 2: disable it where it isn’t needed
Heartbeat is mostly needed in the post editor. Disable it on the front end and the dashboard, and keep it in the editor:
add_action( 'init', function () {
global $pagenow;
if ( is_admin() && in_array( $pagenow, [ 'post.php', 'post-new.php' ], true ) ) {
return; // keep in the editor
}
wp_deregister_script( 'heartbeat' );
}, 1 );
Test your site afterwards, because some plugins rely on Heartbeat in other screens.
Option 3: plugins
- Heartbeat Control (by WP Rocket): set the frequency or disable it per location (dashboard, front end, editor), without code.
- Many performance plugins (WP Rocket, Perfmatters, LiteSpeed Cache) include Heartbeat settings.
What breaks if you disable it completely
- No autosave while editing (you can lose work).
- No warning when two people edit the same post.
- Session-expired pop-ups won’t appear (you lose unsaved work on submit).
- Some plugin features (live notifications, WooCommerce admin updates, page builder autosave) stop working.
Usually it’s better to slow it down than to turn it off.
Other admin-ajax load: check plugins too
If admin-ajax traffic stays high after taming Heartbeat:
- Find the
actionvalues (DevTools Network tab, or temporary logging). - Front-end AJAX from plugins (live search, cart fragments, counters, chat widgets) can be heavy. WooCommerce cart fragments is a classic. Disable it on pages that don’t need it, or use a plugin setting.
- Use a page cache and object cache to make each PHP request cheaper. See Redis object cache.
Server-side tuning
Make sure PHP-FPM has enough workers for admin traffic plus visitors, and that a few slow admin requests can’t starve the site. See PHP-FPM tuning and WordPress performance tuning.
Quick reference
| Goal | How |
|---|---|
| Slow it down | heartbeat_settings filter → interval 60 |
| Keep only in editor | deregister heartbeat outside post.php |
| No-code option | Heartbeat Control plugin |
| Find admin-ajax sources | access log + action parameter |
| Don’t | disable it completely without testing |
Related: WordPress cron jobs and WordPress VPS hosting.