# Site Kit by Google Turns Off WordPress Defer on 92% of the WooCommerce Stores That Run It

> WordPress withdrew 1,156 defer requests across 401 stores we measured. One Google plugin accounts for the largest share, and the handle in the tag is not at fault.

- Published: 2026-10-24
- Author: M Asif Rahman (https://ar.bd), Founder, WPDeveloper
- Tags: Render Blocking, Research, Methodology, Performance, WooCommerce, WordPress, check:A1, fix:render-blocking
- Canonical: https://xspeedcache.com/blog/defer-refused-dependency-census/

---

Updated October 2026

On 24 October 2026 we read the homepages of 2,363 WordPress origins from our own xSpeed Scan archive and counted 6,305 requests for a script loading strategy. WordPress granted most of them and refused 1,156, across 401 stores. The comparison people expect from a render-blocking study is one plugin against another. The more useful comparison is the same plugin against itself: `wc-jquery-blockui` was deferred on 309 of the stores that asked and blocking on 224 of them, same handle, same WooCommerce 11.2.1, the current release per wordpress.org's plugin API on 24 October 2026. Something outside that plugin decides which it gets. This study names it.

## Quick Summary: What to Check Before You Touch Another Setting

| If you want to… | Do this | Why |
|:---|:---|:---|
| Know whether core refused you | Look for `data-wp-strategy` with no `defer` on the tag | That attribute is the only trace of a refusal |
| Find the cause | List the handles that **depend on** yours, not the ones yours depends on | Core walks dependents, in that direction only |
| Fix a WooCommerce store running Site Kit | Check Site Kit's WooCommerce conversion events before anything else | Present on 82.8% of refusals, 2.5% of successes |
| Stop wasting a pass | Do not re-apply `strategy` to the refused handle | Core will refuse it again for the same reason |
| Check the whole estate | Run the free scan, then read the HTML of the worst pages | Check A1 sizes the blocking in milliseconds |

Three findings, in order of how much they should change what you do. Core refused 18.3% of all the strategies it was asked for. In 1,123 of 1,156 refusals the cause sits in a handle other than the one wearing the attribute. And on the stores where Google's Site Kit registers its WooCommerce conversion-event script, 92.3% carry at least one refusal, against 40.0% of WooCommerce stores without it.

## The Method, and Everything It Cannot Tell You

The method comes before the numbers here, because every number below is only as good as it.

**The receipt.** WordPress writes `data-wp-strategy` on a script tag whenever that handle asked for a loading strategy. When core grants the request the tag carries both the attribute and a real `defer` or `async`. When core withdraws it, the attribute stays and the real one never appears. Our earlier piece on [render-blocking CSS and JavaScript](https://xspeedcache.com/blog/fix-render-blocking-resources-wordpress/) established that behaviour and demonstrated it on ten sites. A refusal is therefore readable from outside the site, with no plugin installed and no login.

**The corpus.** We drew every origin the scan archive marks as WordPress, the same corpus behind our [three-way count of caching plugin adoption](https://xspeedcache.com/blog/cache-plugin-adoption-measured/), 2,582 of 3,736 scans across 150 pages of `/api/scan-list`, and requested each homepage once under a desktop Chrome user agent. 2,328 answered 200. 2,363 returned a document we could parse, because several 403 and 5xx responses still render a WordPress page. From each we kept only the opening `<script>` tags, which is enough to see every handle, every strategy attribute and every inline script printed in the `after` position.

**The two refusal rules.** Core's `filter_eligible_strategies()` in `wp-includes/class-wp-scripts.php`, fetched from the WordPress develop repository on 24 October 2026, returns an empty list of eligible strategies in exactly two cases: a non-alias handle with no intended strategy of its own, and a handle with an inline script attached in the `after` position. It then recurses over the handle's **dependents**, so an empty list anywhere below propagates all the way up. One of those two cases is visible in the HTML, because an `after` inline prints as `<script id="handle-js-after">`. The other is not.

### Six limitations, before a single result

- A homepage is one URL, logged out, at one moment. A store whose checkout refuses a defer and whose homepage does not is counted clean here.
- We see only handles whose developer asked for a strategy in the first place. A plugin that never calls the API cannot appear, however much it blocks.
- Cohort membership is read from the same HTML, so a plugin that is installed but prints nothing on the homepage counts as absent.
- The population is stores that have been scanned by us, which is not a random sample of WordPress. It over-represents sites whose owner was already worried about speed.
- For the 97.1% of refusals caused by a dependent, the dependency graph is not in the HTML. We can name a culprit by association and then confirm it in source, which we do below, but a single page cannot prove it on its own.
- An optimizer that combines or minifies JavaScript destroys the file path we attribute by. 125 refused tags came through one: Jetpack Site Accelerator on 55, LiteSpeed Cache on 52, our own xSpeed Cache minifier on 9, Autoptimize on 4, and 5 we could not name. Rewriting the URL does not cause the refusal, and our own plugin does nothing to repair one either.

## Result 1: One Store in Six Carries a Refusal, and Almost None of Them Are Self-Inflicted

Of the 2,363 origins parsed, 1,257 asked core for a strategy somewhere on the page, which is 53.2%. Of those askers, 401 got at least one refusal, which is 31.9% of the stores that tried and 17.0% of every WordPress store measured. The median affected store carries 3 refusals and the worst carries 17.

| Measure | Count | Share |
|:---|---:|---:|
| WordPress origins parsed | 2,363 | — |
| Origins printing `data-wp-strategy` at all | 1,257 | 53.2% of parsed |
| Origins with one refusal or more | 401 | 17.0% of parsed |
| Strategy requests seen | 6,305 | — |
| Requests refused | 1,156 | 18.3% of requests |
| Refusals caused by a dependent | 1,123 | 97.1% of refusals |
| Refusals caused by the handle's own `after` inline | 33 | 2.9% of refusals |

The last two rows are the ones that decide what you do next. Only 33 refusals in the whole corpus are the fault of the handle in the tag, and 21 of those are a single pattern: a Cloudflare Turnstile widget loaded with its configuration printed directly after it. Everything else was refused because of something further down the tree.

## Result 2: The Ranking Names WooCommerce, and WooCommerce Is Not the Culprit

Attributing each refused handle to the plugin or theme that registered it gives a ranking with one obvious leader. WooCommerce owns 937 of the 1,156 refusals, 81.1%, spread over 270 of the 401 affected stores.

| Owner of the refused handle | Stores | Refusals | Of which self-inflicted |
|:---|---:|---:|:---:|
| WooCommerce | 270 | 937 | 2 |
| Cloudflare Turnstile | 32 | 32 | 21 |
| WordPress core | 24 | 24 | — |
| Google Tag Manager | 23 | 23 | — |
| Hostinger Reach | 20 | 20 | — |
| Trustindex | 12 | 12 | — |
| Jetpack Stats | 11 | 19 | — |
| GTM4WP | 7 | 10 | — |
| Site Reviews | 7 | 7 | 7 |
| MonsterInsights | 7 | 7 | — |
| XStore theme | 6 | 6 | — |

Read that table as a list of victims, not of offenders. The refusal rate per handle is what gives it away.

![Refusal rate by handle: wc-jquery-blockui refused on 224 of 533 stores that asked, wc-js-cookie 162 of 535, woocommerce 145 of 539, and core's wp-hooks 16 of the 18 origins that asked](https://xspeedcache.com/images/blog/defer-refused-rate-by-handle.webp)

`wc-jquery-blockui` asked for a strategy on 533 stores and was refused on 224 of them, 42.0%. The other 58% run the same plugin at the same version and get their defer. A handle refused everywhere it asks would point at a fault inside its own plugin. A handle refused on two stores in five points at something that varies between stores, which means a third party. The one row with the opposite shape is core's own `wp-hooks`, refused on 16 of the 18 origins that asked for it, and that sample is far too small to carry a claim.

## Result 3: The Differential Test Names Site Kit by Google

Comparing a plugin's installed base against a refusal rate tells you very little, because almost everything correlates with running WooCommerce. The test that works holds WooCommerce constant and splits on core's answer instead.

> **The differential test.** Take every store where one handle carried `data-wp-strategy` and no `defer`. Take every store where the same handle carried both. Both cohorts asked. Only the answer differs. Now rank every other handle on the page by how much more often it appears in the refused cohort than in the deferred one.

For the `woocommerce` handle that gives 145 refused stores against 394 deferred, and one row runs away with it.

![The differential test: googlesitekit-events-provider-woocommerce present on 82.8% of the refused cohort against 2.5% of the deferred cohort, with google_gtagjs marked as a confounder](https://xspeedcache.com/images/blog/defer-refused-differential-test.webp)

`googlesitekit-events-provider-woocommerce` is present on 120 of the 145 refused stores, 82.8%, and on 10 of the 394 deferred stores, 2.5%. That is a gap of 80.2 percentage points. Turned round the other way, the test is cleaner still: 130 stores in the corpus print that script, and 120 of them, 92.3%, carry at least one refusal. Among the 412 WooCommerce stores without it, 165 do, which is 40.0%.

## The Receipt: Two Registrations and One Loop in Core

Association is where this study would normally stop. It does not have to, because both halves of the mechanism are open source and both can be read on the day.

Site Kit by Google 1.190.0, released 19 October 2026 according to wordpress.org's plugin API, registers the script in `includes/Core/Conversion_Tracking/Conversion_Event_Providers/WooCommerce.php`:

```php
$script = new Script(
    'googlesitekit-events-provider-' . self::CONVERSION_EVENT_PROVIDER_SLUG,
    array(
        'src'          => $this->context->url( 'dist/assets/js/googlesitekit-events-provider-woocommerce.js' ),
        'execution'    => 'defer',
        'dependencies' => array( 'woocommerce' ),
    )
);
```

Two things in that array matter. `dependencies` makes the script a dependent of WooCommerce's `woocommerce` handle, which puts it inside the tree core walks. `execution` is Site Kit's own key, not WordPress's, and its `Script::register()` records what happens to it:

```php
wp_register_script( $this->handle, $src, (array) $this->args['dependencies'], $version, $this->args['in_footer'] );

if ( ! empty( $this->args['execution'] ) ) {
    wp_script_add_data( $this->handle, 'script_execution', $this->args['execution'] );
}
```

The fifth argument to [`wp_register_script()`](https://developer.wordpress.org/reference/functions/wp_enqueue_script/) is a plain boolean. Since WordPress 6.3 that argument can instead be an array carrying `strategy`, and the [6.3 developer note](https://make.wordpress.org/core/2023/07/14/registering-scripts-with-async-and-defer-attributes-in-wordpress-6-3/) states that this is how a script asks core to defer it. Site Kit does not use it. It adds its own `script_execution` key and appends the `defer` attribute later through a `script_loader_tag` filter, which works perfectly well for its own tag.

From core's point of view the handle is registered, enqueued, has a `src`, and has no intended strategy. That is the first of the two refusal rules, and the result propagates up the tree.

![How one dependent cancels the defer on six scripts above it, with the two return array() lines from filter_eligible_strategies](https://xspeedcache.com/images/blog/defer-refused-dependency-chain.webp)

Nothing here is a bug report against Site Kit's own loading. Its script defers correctly. The cost lands on the handles it declares a dependency on, and those belong to someone else. Four more of its conversion providers declare the same kind of cross-plugin dependency: Easy Digital Downloads on `edd-ajax`, Mailchimp for WordPress on `mc4wp-forms-api`, Popup Maker on `popup-maker-site`, and Ninja Forms on core's own `backbone`. The Contact Form 7, WPForms, OptinMonster and content-event providers declare none. No handle belonging to any of those five dependency targets turns up in our refusal set at all, so the mechanism traced here is confirmed for WooCommerce and merely predicted for the rest.

## The Confounder That Would Have Named the Wrong Plugin

One `after` inline shows an even larger association than the provider script, and following it would have produced a different and wrong article. `google_gtagjs` carries an `after` inline on 85.5% of the refused cohort and 13.2% of the deferred one. It is a tempting culprit: an `after` inline is one of core's two refusal rules, and the lift is 72.3 points.

It is not the cause. `google_gtagjs` is not a dependent of any WooCommerce handle, so core never reaches it while deciding `woocommerce`. It scores highly because the same plugin installs both, which makes it a marker of Site Kit rather than a mechanism. The second-placed row, `googlesitekit-events-provider-content-events` at 77.9% against 2.5%, fails the same way: it ships in the same plugin and declares no dependencies at all.

That is the methodological point worth taking from this study. Ranking `after` inlines by association names the loudest co-occurring script. Only the dependency declaration explains anything, and the only way to separate the two is to read the registration.

## What the Other 250 Stores Are Doing, and Why We Will Not Guess

Site Kit's conversion providers appear on 133 of the 401 affected stores, 33.2%. A further 18 are fully explained by an `after` inline attached to the refused handle itself. **That leaves 250 stores, 62.3% of the affected population, with no named culprit at all.** The honest summary of this study is that it explains a large minority.

We ran the same differential across those 250 looking for a second offender and did not find one. Every high-lift row in that cohort is simply another WooCommerce handle, which says the stores run WooCommerce and nothing more. The single candidate worth recording is `woo-variation-swatches`, present on 10.1% of the unexplained refusals against 0.4% of a clean comparison cohort. That is a 27-store signal and we have not read its registration, so it is a lead rather than a finding.

Three things would close the gap and none of them can be done from a homepage: the registered dependency graph, which needs `wp_scripts()` on the server; a logged-out crawl of more than one template; and a controlled install where providers are switched on one at a time. The last is the one we would run next.

## Running This Across the Stores You Did Not Build

On one site the differential is unnecessary, because the dependency graph is right there in `wp_scripts()->registered`. The problem is an estate, where the refusal shows up on the three stores whose owner complains and not on the thirty that never mention it.

[xSpeed Hub](https://xspeedcache.com/xspeed-hub/), our fleet dashboard, runs the scan across every connected site, so the stores whose critical path is worst surface without opening thirty dashboards. [WooCommerce stores](https://xspeedcache.com/use-cases/woocommerce/) are the ones to check first on this particular fault, since 937 of the 1,156 refusals land on WooCommerce handles. xSpeed Cache is ours, built by WPDeveloper, and on this fault it is a measuring instrument rather than a cure: nothing in our minifier restores a strategy core has withdrawn, and our combined files appear in 9 of the refused tags above.

**Worth keeping in proportion before you spend a day on it.** Our [measured fix-priority study](https://xspeedcache.com/blog/wordpress-speed-fix-priority-order/) put page weight ahead of the critical path on most sites, and our [scan of 958 origins](https://xspeedcache.com/blog/wordpress-core-web-vitals-scan-data/) found 83.9% of sites with a sub-200ms server response still failing LCP. A refused defer is real and it is cheap to find. It is rarely the largest thing wrong.

Run the free scan on your own site: [xspeedcache.com/scan/](https://xspeedcache.com/scan/)

## Common Mistakes People Make Chasing a Refused Defer

- Re-applying `strategy` to the handle that shows the attribute. Core refused it for a reason that lives somewhere else and will refuse it again.
- Reading the dependency list the wrong way round. Core walks dependents, the scripts that depend on yours.
- Blaming the optimizer because the URL in the tag belongs to it. 125 refused tags were rewritten by one, and in every case the handle had already been refused.
- Testing while logged in, where a different set of scripts loads and conversion tracking often does not fire at all.
- Treating an `after` inline on a co-occurring script as the cause. It has to be a dependent before it can block anything.
- Deferring everything with a plugin setting after core refused, which produces the breakage described in [the post on a delayed script that broke a menu](https://xspeedcache.com/blog/delay-javascript-broke-menu/).

## Frequently Asked Questions

### I set `strategy` to `defer` and the tag came back with no `defer` at all. What did I do wrong?

Probably nothing. Check whether the tag carries `data-wp-strategy`. If it does, core received your request and withdrew it, which means a handle that depends on yours is ineligible. Fix that handle.

### I removed every `after` inline from my own script and it is still blocking. Why?

Because the `after` rule applies to dependents too, and so does the empty-strategy rule. In our corpus only 2.9% of refusals came from the handle's own inline. The overwhelming majority came from further down.

### I uninstalled Site Kit and my defer came back. Is that proof?

For your store, yes, and that is the right test to run. It is also the experiment this study could not run at scale, which is why we published the association and the source side by side rather than one of them alone.

### Does this mean Site Kit by Google is slowing my site down?

Not directly. Its own script defers as intended. The side effect is that WooCommerce's scripts lose a deferral they had asked for, and on a product page that is usually several files moving back into the critical path.

### I only run Site Kit for Search Console. Do I still get this?

Only if conversion tracking is on and WooCommerce is active, because the provider's own source notes that it activates on `class_exists( 'WooCommerce' )`. The script printing on your page is the thing to check, not the setting.

### My handle is not in your ranking. Should I assume it is fine?

No. The ranking is built from stores we have scanned, and it only sees handles whose developer asked for a strategy. A plugin that never calls the API blocks just as hard and leaves no receipt.

### Why is the refusal rate 42% on one WooCommerce handle and 12% on another?

Because each handle has a different set of dependents, and the chance that one of them is ineligible rises with the size of that set. `wc-jquery-blockui` sits under more of WooCommerce's tree than `wc-cart-fragments` does.

### Can a caching or minification plugin fix this?

No, and ours does not. The decision happens in PHP while the tag is printed. Combining the files afterwards changes which URL appears, not whether core granted the strategy.

### What is the fastest manual check on one store?

View source logged out, search for `data-wp-strategy`, and note every match that has no `defer` or `async` beside it. Each one is a refusal. [Our guide to CSS and JavaScript options](https://xspeedcache.com/docs/css-and-javascript/) covers what to do about them once you have the list.

### Is any of this visible in a PageSpeed report?

Only as a consequence. [Chrome's own Lighthouse documentation](https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources) states which resources count as render-blocking, and a refused script simply appears as one of them with no explanation attached.

### Does the same thing happen to stylesheets?

There is no stylesheet equivalent, which is the more serious half of the problem. WordPress gives scripts a dependency-aware API that refuses unsafe requests and gives stylesheets nothing at all, as [our render-blocking guide](https://xspeedcache.com/blog/fix-render-blocking-resources-wordpress/) sets out.

### How often should this be re-measured?

Quarterly. Both [Site Kit](https://wordpress.org/plugins/google-site-kit/) and [WooCommerce](https://wordpress.org/plugins/woocommerce/) ship frequently, and a single line in either registration would move every number in this study.

## Conclusion: Fix the Dependent, Not the Handle

| If you are… | Do this first | Then |
|:---|:---|:---|
| A store owner with one site | Search the source for `data-wp-strategy` with no `defer` | Disable conversion tracking in Site Kit and re-check |
| An agency with an estate | Scan the estate and sort by render-blocking milliseconds | Run the differential on the two worst stores |
| A plugin developer | Pass `strategy` inside the fifth argument of `wp_register_script()` | Audit anything you declare a dependency on |
| Comparing caching plugins | Read the [80-capability comparison](https://xspeedcache.com/comparison/) | Check [Free vs Pro](https://xspeedcache.com/free-vs-pro/) for what each tier automates |

**What to do this week:** read the HTML of your busiest product page logged out and count the refusals. If Site Kit's WooCommerce provider is on the page, turn conversion tracking off for one deploy and count again. Pass `strategy` properly in anything you register yourself. Then run the [free xSpeed Scan](https://xspeedcache.com/scan/) and look at check A1, which sizes the blocking in milliseconds rather than counting files. xSpeed Cache is free forever for the complete toolkit, and Pro starts at $29 a year with a 14-day money-back guarantee if you want the tuning run for you, with the current [pricing](https://xspeedcache.com/pricing/) on the site.

If you run this differential on your own estate and find a culprit we did not name, we would rather hear about it than guess at the other 250 stores for another quarter.
