Automatic Signed Exchanges (SXGs) Beta Launch

I think I see why, you have incorrect content encoding when you curl test the response headers for the Google served cache. Content type should be application/signed-exchange;v=b3 not text/html; charset=UTF-8

curl -s -i -H 'Accept: application/signed-exchange;v=b3'
HTTP/1.1 200 OK
Cache-Control: private
X-Silent-Redirect: true
Warning: 199 - "debug: content has ingestion error: Error fetching resource: Content is not cache-able or cache-able lifetime is too short"
Content-Type: text/html; charset=UTF-8
X-Content-Type-Options: nosniff
Date: Tue, 12 Oct 2021 22:26:22 GMT
Server: sffe
Content-Length: 287
X-XSS-Protection: 0
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"

<meta http-equiv="content-type" content="text/html;charset=utf-8">
<META HTTP-EQUIV="refresh" content="0; url=">
<BODY onLoad="location.replace(''+document.location.hash)">

Also could be related to HTML meta refresh <META HTTP-EQUIV="refresh" content="0; url="> ? Or that is SXG failing and falling back to non-SXG URL?

whereas on my blog the correct content type is returned Content-Type: application/signed-exchange;v=b3

curl -s -i -H 'Accept: application/signed-exchange;v=b3'
HTTP/1.1 200 OK
NEL: {"report_to":"nel","max_age":604800,"success_fraction":0.05}
Report-To: {"group":"nel","max_age":604800,"endpoints":[{"url":""},{"url":""}]}
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Type: application/signed-exchange;v=b3
Content-Security-Policy: require-trusted-types-for 'script'; report-uri
Cross-Origin-Resource-Policy: cross-origin
Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="webpkgcache-team"
Report-To: {"group":"webpkgcache-team","max_age":2592000,"endpoints":[{"url":""}]}
Content-Length: 223372
Date: Tue, 12 Oct 2021 22:30:04 GMT
Expires: Tue, 12 Oct 2021 22:30:04 GMT
Cache-Control: private, max-age=86399
Last-Modified: Tue, 12 Oct 2021 15:16:28 GMT
X-Content-Type-Options: nosniff
Server: sffe
X-XSS-Protection: 0
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"

@firat is Report-To: {"group":"webpkgcache-team","max_age":2592000 in my response header what determines SXG cache time or Cache-Control: private, max-age=86399 as that matches what I set on CF CDN edge response for CF Worker full HTML page caching at 2592000 but browser cache control is 86400


I only recently turned on APO to see if that would fix the issue. The cache private and debug message appears regardless of whether or not APO is being used.

It could certainly be something that WP Engine is doing. Although I wouldn’t know the first thing to do to fix that.

Should I do anything from my side?

I’m using Cache level as “Standard” and Browser Cache TTL “2 minutes”

hmm from webpackager/ at main · google/webpackager · GitHub

Google SXG cache

The Google SXG cache sets these requirements in addition to the ones set by the SXG spec:

  • The SXG must have a freshness lifetime of at least 120 seconds, as computed for a shared cache from its outer headers.
  • The signed fallback URL must approximately equal the URL at which the SXG was served. Where possible, aim to make them byte-equal. The set of allowed differences is not precisely specified, but approximately:
    • Characters may be substituted by their percent encodings, and vice versa, with the exception of meaningful delimiters like / , ; , ? , & , and = .
    • Query parameters may be re-ordered.
    • Valueless query parameters may be encoded with or without a trailing = .
    • Extra & s in the query string are allowed.
  • The signed cert-url must be https .
  • The signature header must contain only:
    • One parameterised identifier.
    • Parameter values of type string, binary, or identifier.
  • The payload must be non-empty.
  • The signed cache-control header cannot have a no-cache or private directive, even with a value (e.g. no-cache=some-header is disallowed).
  • The content-type must satisfy the media-type grammar.
  • The link header, if present, must lead to successful substitution per the Loading spec. Specifically, it must meet these requirements, in addition to the ones set by the Link spec:
    • Each URI-Reference must be an absolute https URL.
    • Parameter names can only be as , header-integrity , media , rel , imagesrcset , imagesizes , or crossorigin .
    • All rel parameters must be either preload or allowed-alt-sxg .
    • All imagesrcset values must parse as a srcset attribute.
    • There may be no more than 20 rel=preload s.
    • All crossorigin values must either be the empty string, or anonymous .
    • Every rel=preload must have a corresponding rel=allowed-alt-sxg with the same URI, which in turn must contain a header-integrity parameter with a value that satisfies the CSP hash-source grammar using the sha256 variant.
    • The preloaded URLs, when requested with an SXG-preferring Accept header, must respond with valid SXGs that match their given header-integrity .
  • The link header must not be present on subresources, i.e. SXGs that are themselves preloaded from other SXGs.
  • There must not be a signed variant-key-04 or variants-04 header.
  • The signature’s lifetime ( expires minutes request time) must be >= 120 seconds.
  • The SXG must be no larger than 8 megabytes.
  • The page should be responsive, i.e. correct on all media. (In the future, a supported-media annotation should allow this constraint to be removed.)

Some of the above limitations are overly strict for an SXG cache’s needs, and were implemented as such for the sake of expediency. They may be loosened over time, especially in response to publisher feedback.

and rfc7234

4.2.1. Calculating Freshness Lifetime A cache can calculate the freshness lifetime (denoted as freshness_lifetime) of a response by using the first match of the following:

  • If the cache is shared and the s-maxage response directive (Section is present, use its value, or
  • If the max-age response directive (Section is present, use its value, or
  • If the Expires response header field (Section 5.3) is present, use its value minus the value of the Date response header field, or
  • Otherwise, no explicit expiration time is present in the response. A heuristic freshness lifetime might be applicable; see Section 4.2.2.

Not sure if CF follows this, but that would mean in order of priority would be cache-control s-maxage, max-age, expires? Looks like cdn-cache-control header isn’t supported then.

1 Like

So since we have HSTS enabled we will not be able to use signed exchanges?

Also, WordPress sites should have no issues with signed exchanges, correct?


Hi @henshaw. This appears to be a Google bug. The problem is we are interpreting Cache-Control: must-revalidate as equivalent to max-age=0 . This seems wrong per the HTTP spec.

  1. Short term, you can remove the must-revalidate.
  2. Medium term, we’ll try to fix this bug or make some changes to remove must-revalidate.

cc @eva2000


Hi @Terms_G, I replied to the thread you’ve created. For visibility, I also put it here:

For “The dates for the signed exchange are invalid.” errors: You can ignore them. Google can still parse the SXG and treat it like normal HTML, so it falls back to earlier behavior.

For HSTS: There are Users [ @eva2000, @junellabanag1 ] reporting that SXGs is working on their websites even in the presence of HSTS. I will update you when we know more.


Hi folks. Regarding errors in the Search Console:
If it’s an AMP page, you can check out the AMP status report - Search Console Help, which explains the impact.

For non-AMP cases, or non-AMP SXGs customers, unfortunately, a nice help page doesn’t exist yet which would describe the error type breakdown, but if there are any critical errors that would warrant disabling SXGs:

  • You should be able to detect them for a specific URL by following the steps in Verify SXG Setup.
  • They should show up later in Search Console as "Fetch error"s, per Monitor and debug SXG.
1 Like

Hey Jon,

I have the same issue, my main content is set to cache at 2 minutes, my directory pages set to cache 20 days (confirmed via my headers that this is correct). Yet I am getting the same error as you

“debug: content has ingestion error: Error fetching resource: Content is not cache-able or cache-able lifetime is too short”

Thanks I can confirm that I am also getting this bug most likely due to must-revalidate

“Cache-Control: max-age=1728000, must-revalidate”

“debug: content has ingestion error: Error fetching resource: Content is not cache-able or cache-able lifetime is too short”

Thanks for the update :smiley:

1 Like

I did a write up of my own Cloudflare Automatic Signed Exchanges testing on my blog (which is SXG enabled) :sunglasses:

Also for checking to see if SXG is working, you can simply use Google Search Console and do a Mobile Usability URL Live Inspection of a URL link on your site and inspect the MORE INFO → HTTP Response (screenshot below) to check if content-encoding: mi-sha256-03 is displayed. Mobile Usability URL live inspection is done using Android Chrome so would fetch a Cloudflare generated SXG version if it’s available :slight_smile:


Great read! Thanks for sharing your expertise.

Tested mine on Google Search Console :grinning:

1 Like

Hi @firat,

I also posted this in the thread I created but I will post it on here as well.

I googled our site and indeed the SXG is working normally. The URL goes from the google URL then switches to our URL.

However, our logo is no longer in the search results for any AMP page. Is this normal behavior?

Thanks and regards.

You’re welcome. I’ve since updated my write up with more info :slight_smile:


Google search and Cloudflare Signed Exchange SXG cache pre-fetching in action :sunglasses: :nerd_face: :heart_eyes:


Thanks for the updates, Sir. I also followed you on Twitter :innocent:

1 Like

Hi folks.

I added a new section to the first post of thread: FAQs.



Great post, @eva2000. As always :slight_smile:

1 Like

Cheers :slight_smile:

Thanks for that :slight_smile:

Thanks. Updated my article with Webpagetest generated video demo of Cloudflare Signed Exchange being prefetched when loading Google Searched term – – notice how after clicking on the Google search result listing’s link, the WordPress blog page loading :sunglasses: instantly!

Seems this forum doesn’t support MP4 file attachments heh