Opened 6 weeks ago
Last modified 3 weeks ago
#65407 new feature request
Proposal: Add support for the No-Vary-Search HTTP response header
| Reported by: | jonoaldersonwp | Owned by: | |
|---|---|---|---|
| Priority: | lowest | Milestone: | Future Release |
| Component: | General | Version: | |
| Severity: | normal | Keywords: | |
| Cc: | Focuses: | performance |
Description (last modified by )
This ticket proposes adding WordPress Core support for the No-Vary-Search HTTP response header.
The goal is to give WordPress sites, plugins, themes, hosts, and performance tooling a consistent way to describe when URL query-string differences do not affect the returned response.
This could help supporting browsers and cache layers to reuse responses more effectively - especially where URLs differ only by query parameter ordering or common non-render-affecting tracking parameters.
This proposal has three parts:
1) Add a small API for setting and managing the No-Vary-Search response header.
2) Consider sending No-Vary-Search: key-order by default for front-end and wp-admin (and REST) responses.
3) Consider providing an opt-in mechanism for ignoring common marketing parameters, such as utm_source, utm_medium, gclid, fbclid, and similar parameters.
This is intended as a low-risk, incremental performance enhancement.
MDN Doc
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/No-Vary-Search
Background
Many WordPress pages can be reached through URLs with equivalent query strings in different orders.
For example:
/?foo=1&bar=2
/?bar=2&foo=1
In many cases, those URLs return the same response. However, caches and browser-level prefetch/prerender mechanisms may treat them as separate resources unless the response explicitly says otherwise.
The No-Vary-Search response header allows a server to declare which parts of the query string do not affect the response. A conservative first step would be to declare that query parameter order does not affect the response by sending No-Vary-Search: key-order.
This does not say that parameters should be ignored. It only says that the ordering of query parameters should not affect response equivalence.
Proposed API
WordPress already has mechanisms for filtering response headers, but No-Vary-Search has structured semantics. A dedicated API would make it easier for Core, plugins, themes, and hosts to compose values safely.
Possible API shape:
wp_no_vary_search_add_directive( 'key-order' );
wp_no_vary_search_add_params( array( 'utm_source', 'utm_medium' ) );
wp_no_vary_search_remove_params( array( 'gclid' ) );
wp_get_no_vary_search_header_value();
The exact API design is open for discussion. The main requirement is that multiple components should be able to contribute to the final header without overwriting each other or producing invalid syntax.
This should also include a filter, for example:
$no_vary_search = apply_filters( 'wp_no_vary_search', $no_vary_search );
There should also be a filter to allow for disabling the header entirely.
That would allow plugins, themes, hosts, and enterprise deployments to adjust or disable the header where needed.
Proposed default: key-order
Core could set the following header by default: No-Vary-Search: key-order
This is an intentionally conservative default. It does not collapse different query parameters. It only indicates that the order of those parameters should not be significant.
In practice, it is hard to imagine many WordPress sites intentionally varying their response based only on the order of otherwise identical query parameters. If such cases exist, they are likely to be highly unusual, and the value should be filterable or removable.
Potential benefits include:
- Better browser reuse of prefetched or prerendered documents.
- Better cache efficiency for URLs with reordered query strings.
- Reduced duplicate cache entries at scale.
This should apply to both front-end and wp-admin responses unless there is a reason to scope it more narrowly.
Optional opt-in: common marketing parameters
A second, more ambitious option would be to provide a way for site owners, hosts, or plugins to opt in to ignoring common marketing and click-tracking parameters (e.g., utm_* keys).
Many sites use these parameters only for client-side analytics, attribution, or marketing tools. In those cases, the server-rendered HTML is usually identical whether the parameter is present or absent.
However, this should not be a default behaviour in Core without further discussion. Some sites may use these parameters server-side for personalisation, redirects, A/B testing, lead attribution, cache segmentation, or analytics logging.
A safer approach would be:
- Core provides the API.
- Core defaults only to
key-order. - Plugins, hosts, or site owners can opt in to ignoring recognised marketing parameters.
Interaction with Speculation Rules
This proposal should be considered alongside the Speculation Rules API.
Speculation Rules can include an expects_no_vary_search value, which tells the browser what No-Vary-Search value it should expect on the prefetched or prerendered response. This can help the browser decide whether an existing speculative load can satisfy a later navigation.
If WordPress Core emits No-Vary-Search, then any Core, plugin, theme, or Performance Lab feature that emits speculation rules may need to account for it.
This is also a reason for the proposed API to expose the computed header value before headers are sent.
Backwards compatibility and risk
The proposed default of key-order should have a low backwards-compatibility risk because it does not ignore, remove, or normalise query parameters. It only declares that parameter ordering is not meaningful.
The higher-risk behaviour is ignoring named parameters. That should be opt-in and filterable.
Potential edge cases to review
- Sites that intentionally vary output based on query parameter order.
- Plugins that parse raw query strings rather than using normalised request data.
- REST API endpoints and custom endpoints that may have different cache semantics.
- Admin screens that use query parameters heavily.
- Login, registration, password reset, preview, customiser, and nonce-bearing URLs.
- Hosts or CDNs that already set or transform No-Vary-Search.
- Interaction with page caching, object caching, browser prefetching, prerendering, and speculation rules.
Implementation considerations
A minimal implementation could:
- Introduce a small internal representation of the No-Vary-Search directives.
- Add a public API for adding, removing, and retrieving directives.
- Add a filter for the final value.
- Send No-Vary-Search: key-order by default for front-end responses.
- Allow the header to be disabled or modified by plugins, themes, or hosts.
- Add tests for header construction and default behaviour.
Open questions
- Should key-order be emitted for front-end responses only initially, or also for wp-admin?
- What should the API look like so multiple plugins can contribute safely?
- Should Core maintain a canonical list of common marketing parameters?
- Should there be a separate filter for the default Core value and the final emitted value?
- How should this interact with current and future speculation rules support?
- Should REST API responses be included, excluded, or separately filterable?
- If considering allow/disallow lists, what does Core do natively (e.g., ?paged=); particularly considering when pretty permalinks are disabled?
Why this belongs in Core
WordPress powers a large part of the web, and small improvements to default HTTP semantics can have an outsized impact.
Because several independent systems may need to cooperate on the same header, including Core, performance plugins, caching plugins, hosts, CDNs, and speculation-rules generators, this benefits from a shared Core abstraction.
Change History (9)
#6
@
6 weeks ago
For opt-in, I think we'd need to consider:
- Scenarios where sites use server-side logic around capturing campaign parameters (e.g., "this session came from Facebook"); e.g., for passing through a lead-gen form into Salesfore/similar.*
- A/B testing / marketing customization / personalisation stuff, which runs server-side - which is 'relatively' common. We'd need that kit to either disable the header, or opt their affected params into an allow list.
Annoyingly, the breakage in both cases would be silent/invisible, as it'd be as if the parameter simply wasn't there. That makes debugging breakages naaaaasty.
*I can't think of a reason why those kinds of systems couldn't/shouldn't be client-side (cookies, local storage, etc). Am I missing something, other than "doing it wrong"?
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
Re: Optional opt-in: common marketing parameters
Considering that the vast vast majority of sites would never vary on these marketing parameters, I think it would be worth considering adopting an opt-out approach.