First CH Apps / RSS/Atom Feed Validator
A feed URL or a site URL both work. Given a site URL we discover the feed first, then check its XML syntax, required elements, item list, character encoding and date formats. RSS 2.0, Atom 1.0 and RSS 1.0 (RDF) are supported, and feeds using the itunes namespace also get the podcast required-element check.
We request only the URL you enter (plus the candidates found during feed discovery). The feed itself is never re-served — you get the findings and short, truncated titles, dates and links. sitemap.xml validation belongs to the sitemap.xml Validator.
e.g. https://example.com/feed/ or https://example.com/ (we discover the feed from the site URL)
XML syntax: unclosed and mismatched tags, bare & and <, unterminated comments and CDATA, duplicate roots, text outside the root, <!DOCTYPE> (never expanded)
Feed shape: format (RSS 2.0 / RSS 1.0 / Atom), required elements (RSS: channel title, link, description; Atom: feed title, id, updated), rel="self", empty feeds
Items: title, link (absolute?), <guid> / <id> (missing, duplicated), dates (format, timezone, weekday, future), reverse-chronological order
Encoding: XML encoding vs HTTP charset, undecodable bytes, byte patterns typical of mojibake, BOM
Podcast: itunes:image, itunes:category, itunes:explicit, language, <enclosure> (url, type, length), <guid>, <pubDate>, itunes:duration, owner email
Errors are at the "readers cannot parse this" level — a bare &, an unclosed tag, a missing required element. Warnings are "most readers cope, but it violates the spec", and FYI items are "works either way, safer if aligned".
The correct date format depends on the spec. RSS 2.0 wants RFC 822 (Fri, 18 Sep 2026 09:00:00 +0900); Atom wants RFC 3339 (2026-09-18T09:00:00+09:00). We warn when a parseable value still has the wrong shape.
Mojibake is a mismatch between what you declare and what you send. We compare the XML declaration's encoding, the HTTP charset and the actual bytes, and report undecodable bytes and byte patterns typical of mojibake.
Even when a <!DOCTYPE> is present, entities are never expanded (no external entity references, no entity expansion). We only report that the declaration exists.
We validate a single feed. Links are not followed and article bodies are not checked (broken links belong to the Broken Link & Alt Checker).
Sent: only the URL you type. Our server (Cloudflare Workers) fetches it with a public GET. If the URL returns HTML we additionally fetch just the first few KB of up to six discovered candidates, then fetch the one confirmed to be a feed. No cookies, no credentials.
Stored: nothing. The validation lives entirely inside one request and writes neither the URL nor the result to any database (no KV, no D1). It leaves memory when the request ends.
Returned: the findings plus truncated titles, summaries, dates and links. The fetched feed is never re-served — this app cannot be used as a proxy for other sites. Item HTML is stripped of tags and cut to 200 characters before display.
Limits: 5 redirects, 10 second timeout, 512KB read limit for the feed and 4KB for each candidate check. Anything beyond that is not read.
Note: public GET only. URLs pointing at internal networks, localhost or private IPs are rejected.
POST /feed-check/api/check with JSON ({"url": "https://example.com/feed/"}) or a form body and you get the same result back as JSON.