speed brain
edge-side prefetch via speculation rules — conflicts with framework prefetching
speed brain
cloudflare's edge-side prefetch. injects a Speculation-Rules header into html responses so browsers prefetch the next likely navigation before the user clicks.
what it does
cloudflare adds a speculation rules config to every html response:
{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*","relative_to":"document"}]},"eagerness":"moderate"}]}the browser reads this and prefetches same-origin links. prefetch requests carry a Sec-Purpose: prefetch header.
prefetch only serves from cloudflare's cache. if the page isn't cached, cloudflare returns a 503 with an empty body. requests never reach origin.
eagerness levels
| level | trigger |
|---|---|
| conservative | mousedown / touchstart |
| moderate | hover |
| eager | viewport |
cloudflare defaults to moderate.
conflict with framework prefetching
astro, next.js, nuxt — all have their own prefetch systems. they send requests with the same Sec-Purpose: prefetch header that speed brain watches for.
both active at once: cloudflare intercepts the framework's prefetch at the edge, page isn't in cache, 503. browser logs failed resource loads. actual navigation works fine — only prefetch breaks.
use one or the other. for static sites where every page is already on the cdn, framework prefetching is simpler — no cache-eligibility gate, no 503s.
issue i had
astro configured with prefetchAll: true and defaultStrategy: 'viewport'. speed brain also enabled. every prefetch request returned 503:
cf-speculation-refused: prefetch refused: not eligible
vary: sec-purpose
content-length: 0disabled speed brain, 503s stopped.