Written by 2:56 am How To, WordPress Views: 15

How to Reduce External HTTP Requests in WordPress

Learn to cache, block, defer, and tune outgoing WordPress HTTP requests using transients, the pre_http_request filter, timeout configuration, and WP-Cron async patterns.

Reduce External HTTP Requests in WordPress - Cache, Block, Defer & Tune wp_remote_get

Every time WordPress makes an outgoing HTTP request, to fetch a remote API, load a Google Font, check a license server, or ping an analytics endpoint, it blocks. If the remote server is slow, unreachable, or rate-limiting your site, your page waits. Your visitors wait. Your TTFB climbs. This guide covers exactly how WordPress HTTP requests work under the hood, how to find every outgoing request your site makes, and five concrete techniques to cache, block, defer, and tune those requests so they stop adding latency to every page load. For more WordPress performance strategies, explore our dedicated hub.

HTML code on screen representing WordPress HTTP requests and performance optimization.

How WordPress HTTP Requests Work

WordPress has a built-in HTTP API that wraps PHP’s cURL and fsockopen functions into a consistent interface. The primary entry point is wp_remote_get() for GET requests and wp_remote_post() for POST requests. Both are synchronous: execution halts until the remote server responds or the request times out.

The default timeout is 5 seconds. That means a single unresponsive external API can add 5 seconds to every page that triggers that request. If a theme checks a remote license server on init, or a plugin fetches exchange rates on every WooCommerce product page, that delay compounds every time that code path runs.

Internal WordPress processes also use the HTTP API. Automatic update checks, plugin directory pings, and the oEmbed endpoint all make outgoing requests. Most of these are managed carefully by core and typically happen asynchronously. The problem is third-party plugins and themes that make requests on the critical path, during page rendering, not in the background.

The pre_http_request Filter

The pre_http_request filter is the control point for every outgoing HTTP request WordPress makes. If you return anything other than false from this filter, WordPress skips the network request entirely and uses your return value as the response. This makes it the ideal hook for caching, blocking, and monitoring.

The filter receives three arguments:

  • $preempt, Either false (proceed with request) or a pre-empt response array. Return false to let the request through.
  • $parsed_args, The full request arguments array: method, headers, timeout, body, etc.
  • $url, The full URL being requested.

Step 1: Find Every Outgoing HTTP Request

Before you can reduce external requests, you need to know which ones your site is making. The fastest method is a pre_http_request logger. Add it to an mu-plugin, reproduce a page load, and read the log. You will often find requests you did not know existed, Google Fonts API calls, stock image CDN pings, and plugin license checks all show up in the log.

Add this to a file in wp-content/mu-plugins/, load a few pages, then read wp-content/debug-http.log. Group the results by domain. The domains with the most hits, or the ones outside your control, are your optimization targets. Remove this logger before pushing to production; it writes to disk on every request.

An alternative approach for production-safe auditing: use Query Monitor’s HTTP API panel, which logs all WordPress HTTP API calls per request without writing to disk. It shows the URL, method, response code, and duration for each call in the admin toolbar. Our step-by-step guides cover more techniques like this.


Step 2: Cache External Responses with Transients

The single highest-impact change you can make is caching the responses from external APIs in WordPress transients. A transient stores the response in the database (or in an object cache like Redis or Memcached) with a TTL. Subsequent requests within the TTL window never touch the network at all.

The key insight: most external API responses do not need to be fresh on every page load. Currency rates? Cache for 1 hour. Weather data? Cache for 30 minutes. License verification? Cache for 24 hours. RSS feed content? Cache for 6 hours. The data you are fetching is almost never so time-sensitive that it cannot tolerate a few hours of caching.

Replace every direct wp_remote_get() call in your codebase with tweakswp_cached_remote_get(). For third-party plugins you cannot modify, see the blocking technique in the next section, you can intercept their requests via pre_http_request and return a cached version.

Transient vs Object Cache

WordPress transients use the database by default, which adds a database write on cache miss and a database read on cache hit. This is acceptable but not free. If you have a persistent object cache (Redis or Memcached) configured on your server, transients automatically route through the object cache instead of the database. The object cache version is significantly faster, sub-millisecond reads from memory versus a round-trip to MySQL.

If your hosting environment supports Redis, enabling it with a plugin like Redis Object Cache makes transient-based HTTP caching substantially cheaper on your server resources.


Plugins That Generate the Most External Requests

After running the HTTP request logger on dozens of production sites, certain plugin categories consistently generate the most external calls. Knowing which to scrutinize saves audit time.

SEO Plugins

Rank Math and Yoast SEO both make external requests for license verification, content analysis updates, and schema validation. Both cache these calls, but only if the cache has been populated, a fresh installation or cache flush triggers live calls on the next admin page load. Configure each plugin’s remote features carefully and ensure the cache is warm before production deployment.

E-commerce Plugins

WooCommerce makes requests to the WooCommerce.com API for extensions, updates, and license verification. Currency conversion rate checks, tax API lookups, and shipping rate estimates can often be cached for 30-60 minutes without affecting accuracy. The transient wrapper pattern applies directly here: wrap each third-party API call in a cache layer that serves the last-known value if the external API is slow or unavailable. Payment gateway calls on checkout are inherently on the critical path and cannot be deferred, but their supporting data lookups usually can be.

Form and CRM Integration Plugins

Contact Form 7 with Mailchimp integration, Gravity Forms with Constant Contact add-ons, and similar setups fire API calls on form submission, already on the user’s critical path. If a Mailchimp API call takes 3 seconds, the user waits 3 extra seconds for the confirmation. Moving these to WP-Cron (fire the event, return success immediately, handle the API call in the background) eliminates this user-facing latency entirely.

Server-Side Analytics and Tracking

Server-side conversion tracking, fraud detection APIs, and tag management systems that make PHP HTTP calls on page load are invisible in browser-based tools. The pre_http_request logger is the only way to find them. Once identified, these are prime candidates for the async request pattern: queue them via WP-Cron and fire after the page response has been sent.


Step 3: Block Requests You Don’t Need

Some external requests simply should not happen in production. License checks for premium plugins running on a staging server. Google Fonts loaded by themes you have already moved to local hosting. Third-party analytics on a development environment. For these, blocking the request at the filter level is the right solution, cheaper than caching a response you will never use.

WordPress Constants for Environment-Level Blocking

WordPress provides two wp-config.php constants that let you block external requests at the server level, no PHP code required:

  • WP_HTTP_BLOCK_EXTERNAL, Set to true to block all outgoing WordPress HTTP API calls.
  • WP_ACCESSIBLE_HOSTS, A comma-separated list of hostnames that bypass the block. Useful for allowing only specific domains.

Example for a staging environment that should only call the update API:

define( 'WP_HTTP_BLOCK_EXTERNAL', true );
define( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,*.wordpress.org' );

This combination blocks all external calls except to wordpress.org domains. License checks, third-party API calls, and analytics pings all return WP_Error immediately, no network wait, no timeout.


Step 4: Tune Request Timeouts

The default WordPress HTTP timeout is 5 seconds. This means that if you make 3 external requests per page load and all three time out, your visitors wait 15 seconds for a server response. Tuning timeouts per domain gives you control over the failure mode: non-critical requests fail fast; high-value requests get more time.

Use short timeouts (2-3 seconds) for any request where failure should be silent, analytics pings, geolocation APIs, feature flags. Use longer timeouts (15-30 seconds) only for requests that block a user-facing action and where the remote server is known to be slow, payment gateway webhooks, bulk email provider APIs.

A key principle: never put a long-timeout request on the critical path. If a request might take 10 seconds, it has no business running synchronously during page rendering. Move it to a background process.


Step 5: Move Requests Off the Critical Path

The most powerful optimization for non-critical requests is not making them faster, it is making them asynchronous. WP-Cron lets you schedule code to run in the background, completely outside the user-facing request cycle. A page load fires the job and returns immediately; the actual HTTP call happens in the background on the next cron tick.

This pattern works well for: analytics events, webhook notifications, background data sync, activity log submissions, and any “fire and forget” scenario where you need to notify an external service but do not need the response before rendering the page.

One caveat: WP-Cron is visitor-triggered by default. If your site has low traffic, cron jobs may not fire promptly. Configure a real server cron to trigger wp-cron.php on a schedule. The WordPress Cron guide on this site covers the full setup including race condition protection.


Common Offenders: Where External Requests Come From

After auditing hundreds of WordPress sites, the same categories of requests cause the most problems:

Google Fonts

Loading Google Fonts via https://fonts.googleapis.com triggers two or three round trips: a DNS lookup for fonts.googleapis.com, a CSS fetch, then one or more font file fetches from fonts.gstatic.com. Hosting fonts locally eliminates these entirely. Generate the font CSS at google-webfonts-helper, download the WOFF2 files, and load them from your theme with a @font-face rule using font-display: swap.

Gravatar

WordPress loads Gravatars by default for comments, BuddyPress member avatars, and the admin toolbar. Each unique email address triggers a request to secure.gravatar.com. On high-traffic posts with dozens of comments, this can mean dozens of external requests per page load. Disable Gravatars in Settings > Discussion, or preload them during comment rendering and cache the results.

Plugin License Checks

Premium plugins often check their license server on every admin page load. Licensing calls to EDD (Easy Digital Downloads) license APIs, Freemius, or custom endpoints add latency to every wp-admin page. Most of these can be cached via transients, cache the license status for 24 hours. If the check fails due to network issues, return the cached “valid” status rather than blocking the admin.

oEmbed Endpoints

Embedding a YouTube video, Twitter post, or Instagram image in the block editor triggers an oEmbed discovery request. WordPress caches these in the oembed_cache option, but only after the first render. On a new post with multiple embeds, the first load after publishing hits several external servers. Enable WordPress post caching with a full-page caching layer, this ensures the second and subsequent page loads serve from cache.

Update Check Pings

WordPress pings api.wordpress.org to check for plugin, theme, and core updates. By default this happens every 12 hours. These requests are not on the critical path for page rendering, they happen on wp_version_check, which fires on init but only when the transient has expired. You can increase the check interval via a filter:

add_filter( 'wp_update_plugins', function( $transient ) {
    $transient->last_checked = time();
    return $transient;
} );

Gravatar

WordPress loads Gravatars for comments, BuddyPress member avatars, and the admin toolbar. Each unique email address triggers a request to secure.gravatar.com. On high-traffic posts with dozens of comments, this means dozens of external requests per page load. On the front end, these requests happen during PHP rendering if avatars are output in a template loop, each request is synchronous. Disable Gravatars in Settings > Discussion, or serve a local default avatar image instead of fetching from Gravatar’s servers. If you need real Gravatars, implement a caching layer that fetches and stores Gravatar images locally on first use, then serves from your own server on subsequent requests. This converts multiple external HTTP calls into local file reads.

Google Fonts

Loading Google Fonts via the fonts.googleapis.com API triggers two or three round trips per page: a DNS lookup, a CSS fetch, then one or more WOFF2 file fetches from fonts.gstatic.com. Hosting fonts locally eliminates these entirely. Use google-webfonts-helper to generate the font CSS and download the WOFF2 files. Load them from your theme with a @font-face rule using font-display: swap. This is a one-time migration task that permanently removes font-related HTTP requests.

For controlled production environments where you manage updates manually, this prevents the update API from being called on every admin session.


The wp_remote_get Checklist

Before adding any external HTTP call to your WordPress code, run through this checklist:

  1. Does this need to be synchronous? If the result does not affect the current page rendering, use wp_schedule_single_event() to fire it asynchronously.
  2. Can the response be cached? If the data is valid for more than a few seconds, wrap it in a transient with an appropriate TTL.
  3. What happens if it fails? Define the graceful degradation path before writing the request. Never let a failed external call produce a fatal error.
  4. Is the timeout appropriate? Match the timeout to the criticality of the request. Short for non-critical, longer only for blocking user-facing actions.
  5. Are you checking for WP_Error? Always check is_wp_error() before accessing response data. A failed request returns a WP_Error object, not an array.

If your response to question 1 is “it needs to be synchronous and it might take more than 2 seconds”, that is a strong signal to reconsider the architecture, or at minimum to add aggressive transient caching and set a tight timeout with a sensible fallback.

For a complete view of how performance pieces connect, see the WordPress TTFB optimization guide, external request blocking and caching are two of the twelve TTFB-reducing techniques covered there.


Measuring the Impact

After implementing caching and blocking, verify the improvement with the following tools:

  • Query Monitor, Shows all HTTP API calls per request with duration. The “HTTP API Calls” panel lists every outgoing request, the response code, and how long it took. Before optimization, you might see 8-12 requests per page; after caching, the same page should show 0-2 (only cache misses or blocking calls).
  • New Relic / Datadog APM, For production environments, APM tools show external HTTP call timing as a distinct segment in transaction traces. You can see exactly which API calls add the most latency.
  • GTmetrix / WebPageTest waterfall, For frontend impact, a page waterfall shows whether external requests are delaying Time to First Byte. A blocked external API that adds 3 seconds of server-side wait appears as a long TTFB in the waterfall.

For a systematic approach to diagnosing all the performance factors affecting your site, the WordPress Performance Audit Checklist provides a structured 10-step process.


Frequently Asked Questions

Does blocking external requests break plugin functionality?

It depends on the plugin. License-check calls typically fail gracefully if blocked, the plugin falls back to a cached license status or simply shows an error in the admin, which does not affect front-end users. API-dependent features like payment gateways, shipping rate calculators, and external authentication providers cannot be blocked without breaking functionality. The WP_ACCESSIBLE_HOSTS constant lets you allow specific domains while blocking everything else.

How long should I cache API responses?

Cache duration depends on how stale the data is acceptable and how often the remote data changes. A rule of thumb: if the data would not visibly affect your users for 30-60 minutes if it were stale, cache it for at least that long. License statuses can be cached for 24 hours. Weather data for 30 minutes. Currency rates for 1 hour. Plugin update checks every 12 hours. The more the data matters to real-time user experience, the shorter your TTL, but remember that short TTLs mean more network calls.

What is the difference between wp_remote_get and file_get_contents?

Always use wp_remote_get(), never file_get_contents() for remote URLs in WordPress. The WordPress HTTP API respects the WP_HTTP_BLOCK_EXTERNAL constant, fires the pre_http_request filter (enabling all the optimizations in this guide), handles proxy settings, and provides consistent error handling via WP_Error. file_get_contents() bypasses all of this, you lose caching hooks, blocking capabilities, timeout control, and consistent error handling in one line.

Are there plugins that automatically cache HTTP API calls?

Not reliably. Some performance plugins add HTTP API caching as a feature, but implementation quality varies significantly. The transient wrapper pattern in this guide is 20 lines of code, transparent in its behavior, and gives you full control over TTL and cache invalidation. It is preferable to relying on a plugin that may cache responses incorrectly or fail to invalidate stale data.

How do I handle cache invalidation when the remote data changes?

Use delete_transient() when you know the data has changed, for example, when a WooCommerce order status changes and you need fresh shipping rates, or when an admin manually triggers a data refresh. For automatic invalidation, use a webhook from the remote service: when the remote API notifies your site of a change, delete the relevant transient and let it rebuild on the next request. If webhooks are not available, use a shorter TTL and accept the trade-off between freshness and performance.


Final Thoughts

External HTTP requests are one of the most commonly overlooked sources of WordPress slowdowns. Unlike database query optimization or server tuning, they often require no infrastructure changes, just better code patterns. Wrapping wp_remote_get() calls in transient caching, setting tight timeouts, blocking unnecessary requests, and moving non-critical calls to a background queue can eliminate seconds of latency per page load with a day’s worth of work.

The audit step is the most important: run the logger, read the output, and understand every outgoing request your site makes. Many teams discover calls they did not know existed, leftover API integrations, outdated plugin features, redundant license checks. Eliminating those first, before writing a single line of optimization code, is often the fastest path to a measurably faster site.

For the frontend performance side of the equation, removing render-blocking scripts and stylesheets that compound the impact of external request delays, see How to Remove Render-Blocking CSS and JS in WordPress.

Visited 15 times, 1 visit(s) today

Last modified: March 26, 2026