An AJAX request from the WordPress front-end to a REST API endpoint returns “Access to XMLHttpRequest has been blocked by CORS policy” in the browser console. Or a third-party service making API calls to WordPress gets a 403 from the browser’s preflight check. Or a decoupled Next.js front-end cannot fetch post data from the WordPress REST API because the browser blocks the cross-origin request. The WordPress CORS error is a browser security mechanism, not a WordPress bug — but configuring WordPress to send the correct response headers resolves it correctly and securely. For the bigger picture, our WordPress Errors Complete Guide pulls everything together.
WordPress CORS Error — Understanding What Causes It
CORS (Cross-Origin Resource Sharing) is a browser security policy that restricts JavaScript running on one domain from making HTTP requests to a different domain. When JavaScript on example-frontend.com makes a fetch() request to api.example-backend.com, the browser first sends a preflight OPTIONS request to the backend asking for permission. If the backend does not respond with the correct CORS headers (Access-Control-Allow-Origin, Access-Control-Allow-Methods, etc.), the browser blocks the request and shows a WordPress CORS error in the console.
The WordPress CORS error is always a browser error, not a server error — the server receives the request and responds, but the browser rejects the response because the CORS headers do not permit the requesting origin. This is why the request appears to succeed in API testing tools (Postman, curl) but fails in the browser — these tools do not enforce CORS policies. If a request works in Postman but fails in the browser with a CORS error, the problem is definitively the missing CORS response headers, not the WordPress API endpoint itself.
The browser’s preflight request is an HTTP OPTIONS request sent to the API endpoint before the actual request. WordPress must respond to OPTIONS requests with the correct CORS headers, or the browser never sends the actual GET/POST request. A CORS configuration that correctly handles preflight requests includes: Access-Control-Allow-Origin: https://allowed-origin.com (or * for public APIs), Access-Control-Allow-Methods: GET, POST, OPTIONS, Access-Control-Allow-Headers: Content-Type, Authorization, and for endpoints that require authentication: Access-Control-Allow-Credentials: true. According to Mozilla’s CORS documentation, the Access-Control-Allow-Origin header must exactly match the requesting origin for credentialed requests — using a wildcard (*) does not work when cookies or Authorization headers are included in the request. Our guide on using WordPress site health covers the REST API status check that confirms the REST API is functioning before investigating CORS configuration as the cause of failed API requests.
Adding CORS Headers via .htaccess and Nginx
The most reliable fix for a WordPress CORS error on the REST API is adding CORS response headers at the web server level — this handles both preflight OPTIONS requests and actual API requests without requiring WordPress PHP to execute for every preflight check.
Apache .htaccess approach for the WordPress CORS error — add above # BEGIN WordPress:
<IfModule mod_headers.c>
# Allow specific origin (replace with your front-end domain)
Header always set Access-Control-Allow-Origin "https://your-frontend.com"
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "Content-Type, Authorization, X-WP-Nonce"
Header always set Access-Control-Allow-Credentials "true"
# Handle preflight OPTIONS requests
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>
Nginx server block approach — inside the server { } block:
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-WP-Nonce' always;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
Replace the origin URL with your front-end domain. For WordPress CORS error on public APIs, use * For WordPress CORS error on public APIs where any origin should be allowed, use * — but this cannot be combined with Access-Control-Allow-Credentials: true, which is required for authenticated requests. For multiple allowed origins, use PHP (next section) rather than .htaccess — .htaccess cannot dynamically set the origin header based on the requesting origin, while PHP can check the Origin header and respond with the matching allowed origin from a list.
Adding CORS Headers via WordPress PHP
PHP-based WordPress CORS error handling uses WordPress hooks is more flexible than web server configuration — it allows dynamic origin checking, path-specific CORS policies, and integration with WordPress’s authentication system.
Add CORS headers via the rest_api_init hook:
add_action('rest_api_init', function() {
remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
add_filter('rest_pre_serve_request', function($value) {
$origin = get_http_origin();
$allowed_origins = [
'https://frontend.example.com',
'https://staging.example.com',
];
if (in_array($origin, $allowed_origins, true)) {
header('Access-Control-Allow-Origin: ' . esc_url_raw($origin));
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Headers: Authorization, Content-Type, X-WP-Nonce');
}
return $value;
});
}, 15);
This approach checks the requesting origin against an allowlist and only sends CORS headers for approved origins — more secure than a wildcard that permits any origin. The priority 15 (higher than the default 10) ensures this filter runs after WordPress’s default CORS filter, which is removed first by remove_filter('rest_pre_serve_request', 'rest_send_cors_headers'). For handling the preflight OPTIONS request correctly, add the OPTIONS handling to the same callback or use the rest_send_cors_headers hook. Testing the WordPress CORS error configuration: open browser DevTools → Network tab → trigger the cross-origin request → select the request → check Response Headers for Access-Control-Allow-Origin — the header must be present and match the requesting origin exactly for the request to succeed. Our guide on WordPress hooks and filters covers the filter mechanism used here — the rest_pre_serve_request filter is the correct WordPress extension point for modifying REST API response headers including WordPress CORS error resolutions.
CORS Errors With WordPress Authentication
Authenticated WordPress CORS error scenarios require stricter configuration — where the API endpoint requires login and the request includes cookies or an Authorization header — have additional CORS requirements beyond basic header configuration. Browser security rules are stricter for credentialed requests.
For cookie-based authentication (WordPress session cookies), the request must include credentials: 'include' in the JavaScript fetch() call and the CORS headers must include Access-Control-Allow-Credentials: true. Additionally, Access-Control-Allow-Origin cannot be a wildcard — it must be the exact requesting origin. Wildcard origins with credentials cause a CORS error even when the wildcard would otherwise allow the request. WordPress application passwords (Settings → Users → Application Passwords) bypass session cookie authentication entirely — they use HTTP Basic Auth with an Authorization header that does not involve cookies, simplifying the CORS configuration since Allow-Credentials is not required for Basic Auth.
WordPress nonce-based authentication for REST API requests (used by the block editor and many plugins) requires the X-WP-Nonce header to be included in the CORS allowed headers: Access-Control-Allow-Headers: Content-Type, Authorization, X-WP-Nonce. A missing X-WP-Nonce causes the WordPress CORS error even when all other configuration is correct even when all other CORS configuration is correct — the browser refuses to send the actual request because the preflight response did not permit the header it needs to include. This is a common cause of WordPress CORS error on headless WordPress setups where the decoupled front-end uses the block editor’s REST API authentication pattern. Reviews from Mozilla’s web security documentation confirm that the interaction between CORS and authentication credentials is one of the most common sources of CORS configuration errors — the stricter rules for credentialed requests catch many configurations that appear to work for non-authenticated requests. Our guide on fixing WordPress REST API errors covers the broader REST API configuration context including authentication setup that must be correct before CORS configuration can fully resolve cross-origin API access failures.
Cloudflare and CDN CORS Configuration
When behind Cloudflare, the WordPress CORS error may originate from the CDN layer rather than from WordPress itself — Cloudflare may not be passing the CORS response headers from the origin server to the browser, or may be caching a response that was generated without CORS headers and serving the cached (non-CORS) version to subsequent requests.
Cloudflare WordPress CORS error configuration: Cloudflare passes whatever the origin returns — it passes whatever headers the origin (WordPress) returns. If the origin is correctly sending CORS headers but the browser still sees a CORS error, check whether Cloudflare’s cache is serving a cached response from a request that did not include the Origin header. Cloudflare caches by URL by default; if the CORS headers vary by origin (which they should for multi-origin allowlists), Cloudflare must be configured to vary its cache by the Origin request header: add a Cache Rule in Cloudflare → match the API URL path → set Cache Key to include the Origin request header → this creates separate cache entries per requesting origin, ensuring each origin receives the correct CORS headers for its specific origin.
Cloudflare Transform Rules can add CORS headers to responses at the CDN edge, bypassing the need for WordPress to send them: Security → Transform Rules → Modify Response Header → add the Access-Control-Allow-Origin header with the allowed value. This approach adds CORS headers to all matched responses regardless of what the origin server returns — useful for CDN-cached static assets that cannot dynamically send CORS headers based on the request origin. For APIs where the CORS configuration is dynamic (different origins allowed for different endpoints, or authentication-dependent CORS settings), the PHP-based approach in WordPress is more appropriate than Cloudflare Transform Rules, since CDN-level rules cannot easily implement the conditional logic that dynamic WordPress CORS error resolution requires. Our guide on setting up WordPress Cloudflare covers the CDN configuration context that intersects with CORS header management when both the CDN and WordPress need to be correctly configured for cross-origin API access to function.
Local development environments frequently trigger WordPress CORS error when testing headless WordPress setups — the front-end running on localhost:3000 or localhost:3001 tries to fetch from WordPress on localhost:8080, and the different ports make these different origins from the browser’s perspective. Configure the development WordPress installation to allow localhost origins: add localhost:3000 (and any other development ports used) to the allowed origins list in the PHP CORS configuration. Alternatively, many JavaScript development servers (Vite, Next.js dev server, Create React App) support a proxy configuration that routes API requests through the dev server itself, bypassing CORS entirely during development — the requests appear same-origin to the browser because they go through the proxy. The proxy approach is simpler for development but cannot be used in production, so the PHP CORS configuration on the WordPress side must be correct for production regardless of the development approach used.
WooCommerce REST API WordPress CORS error issues affect third-party integrations — inventory management systems, ERP software, and custom mobile apps that use the WooCommerce REST API. These integrations typically authenticate with consumer key/secret (OAuth 1.0a) rather than session cookies or application passwords, and they must be able to make cross-origin requests for CORS to apply. Most server-to-server integrations (where the integration runs on its own server making requests to WordPress) are not affected by CORS — CORS is a browser restriction, not a server restriction. If a WooCommerce integration shows CORS errors, it is running JavaScript in a browser context rather than as a server-side integration. The fix is either configuring CORS on the WordPress server to allow the integration’s origin, or restructuring the integration to use a server-side proxy that handles the WordPress API calls without browser involvement, eliminating the CORS constraint entirely. Our guide on WordPress malware removal covers the security context that CORS headers complement — properly configured CORS is a defence-in-depth security measure, not a barrier to legitimate integration.
Content Security Policy (CSP) is related to but distinct from CORS — it restricts which resources a page can load, while CORS restricts which cross-origin requests are allowed. Both can produce similar-looking browser console errors on WordPress sites. A WordPress CORS error message says “blocked by CORS policy” with the specific violated CORS header mentioned. A CSP error says “Refused to load the script/style” citing a Content-Security-Policy directive violation. Diagnose which is occurring by reading the full console error message before applying a fix — applying a CORS fix to a CSP error (or vice versa) wastes time and leaves the actual issue unresolved. CSP headers on WordPress are configured separately via HTTP response headers (added through .htaccess, Nginx, or a security plugin like WP Headers) rather than through CORS-specific configuration. Some security plugins add restrictive CSP headers as a security hardening measure, which then causes CORS-like errors for legitimate third-party resources. Check for Content-Security-Policy headers in the browser’s DevTools Network panel (look at the Response Headers for any WordPress page) if CSP errors are suspected alongside or instead of WordPress CORS error issues.
Monitoring for WordPress CORS error regressions in production uses browser-based synthetic monitoring tools that actually execute JavaScript in a browser context — unlike simple HTTP ping checks that do not enforce CORS. Checkly, Playwright-based tests, or Puppeteer scripts can test the complete cross-origin request flow from a browser context, catching CORS regressions introduced by web server configuration changes, CDN policy updates, or WordPress plugin updates that modify REST API response headers. Schedule these synthetic CORS tests to run hourly — a CORS regression that breaks a headless front-end or third-party integration is typically not noticed until a user reports the failure, which may be hours after the regression was introduced. Automated CORS testing converts this reactive detection into proactive monitoring that catches the regression within minutes of its introduction.






