costco-watch: client-side browser headers, drop Transform Rule requirement

This commit is contained in:
2026-08-12 07:47:13 -07:00
parent bdace45cd6
commit 0d1da8583e
3 changed files with 29 additions and 17 deletions
+20 -11
View File
@@ -3,19 +3,28 @@
Polls a Costco tire product page on an interval and pushes an ntfy alert when
the item flips from out-of-stock to in-stock.
## Why it points at a proxy, not costco.com
## The header gotcha
Costco's bot mitigation silently stalls requests carrying a non-browser header
set (the connection completes TLS, then nothing comes back - no 403, just a
hang). The page loads fine through `costco-tire.alexzaw.dev`, a cloudflared
ingress rule with `httpHostHeader: tires.costco.com`, **provided** a Cloudflare
Transform Rule attaches browser-like request headers (`User-Agent`, `Accept`,
`Accept-Language`, `Sec-Fetch-*`, `Upgrade-Insecure-Requests`) for that
hostname. cloudflared itself cannot add headers - its `originRequest` block has
no such option - which is why the rule lives at the edge.
Costco's bot mitigation silently stalls requests that lack browser
fetch-metadata headers - TLS completes, then nothing comes back, no 403, just a
hang until timeout. Bisecting against the live site showed the gate is the
`Sec-Fetch-*` family: **any single one** of `Sec-Fetch-Site`, `Sec-Fetch-Mode`
or `Sec-Fetch-Dest` is enough to get a normal response, even with no
`User-Agent` at all. User-Agent, Accept and Accept-Language on their own make
no difference.
If the checker starts reporting `blocked`, that Transform Rule is the first
thing to verify.
This service therefore sends a browser header set itself (see
`BROWSER_HEADERS` in `watch.js`). Two things that do **not** work as fixes:
- cloudflared cannot add headers - its `originRequest` block has no such
option, it only forwards what the client sent.
- Cloudflare Transform Rules cannot set `Sec-*` headers - they're on
Cloudflare's restricted list, so the edge can't supply the one header family
that matters.
`TARGET_URL` still points at the `costco-tire.alexzaw.dev` cloudflared ingress
(which sets `httpHostHeader: tires.costco.com`), but no Cloudflare-side
configuration is required.
## Config