# costco-watch 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 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. If the checker starts reporting `blocked`, that Transform Rule is the first thing to verify. ## Config | Env | Purpose | |-----|---------| | `TARGET_URL` | Product page to watch (required) | | `ITEM_LABEL` | Friendly name used in notifications | | `NTFY_URL` / `NTFY_TOPIC` | ntfy server and topic (topic required) | | `NTFY_TOKEN` | Bearer token, if the topic is protected | | `INTERVAL_MINUTES` | Poll interval, default 60 | | `API_KEY` | Guards `/status` and `/check` | ## Endpoints - `GET /health` - liveness - `GET /status` - current stock state, last check, transition history - `POST /check` - force a check now ## Etiquette `tires.costco.com/robots.txt` allows `User-agent: *` on all paths, so a personal low-frequency check is within its terms. Keep the interval at an hour or more.