The Browser That Fact-Checks
Built a bash CLI around Cloudflare Browser Rendering, pointed it at school websites for a live research project, and watched it catch two things AI research had gotten wrong.
I found the tool, built the CLI, and aimed it at an open research problem — all in the same session.
I came across Cloudflare Browser Rendering — a service that runs a real headless browser against any URL and returns the rendered DOM, markdown, a screenshot, or a PDF. Most of the modern web doesn’t return anything useful to a raw HTTP fetch because the content is rendered with JavaScript. Browser Rendering loads the page properly, then hands you back what a human would actually see.
I wrapped its REST API in a single bash file called cfbr — one curl call per subcommand, a bit of python3 to shape the JSON, no Node runtime, no install step beyond curl -fsSL to drop it into ~/bin/. It ships with the verbs I actually needed: markdown, scrape (CSS selectors), json (AI-structured extraction), links, screenshot, pdf, content, and crawl. The whole thing fit in an evening, mostly because there was nothing clever to invent — Cloudflare’s API does the work, the CLI just makes it callable from a shell or another script.
I didn’t build it because I’d planned a tool day. I built it because a research task was already open and cfbr markdown was exactly the missing step.
The Live Job: Eight Schools
The project: gathering information on eight schools for a real client decision. Initial research had run through Perplexity and produced a working document — admissions criteria, fees, languages, facilities, transport. Solid as a starting point, but indexed-and-summarised. I wanted to bounce each claim against the schools’ own live sites.
So I fed each school’s URL into cfbr markdown and got back clean, rendered text — the kind of output Claude can read natively without me babysitting an HTML parser. Eight pages, eight markdown files, one Cerebro reconciliation pass against the Perplexity working doc.
Two things came back wrong.
First, one school’s comedor — the dining hall — was listed as not available. The school’s own site clearly said otherwise, with photos and a menu. That’s the kind of error that quietly changes a shortlist when a family has working parents and no fallback for lunch.
Second, a school’s domain had moved in a way Perplexity hadn’t surfaced. The redirect chain pointed to a different parent organisation, and the new branding made it obvious the school had been acquired. The press hadn’t covered it. Perplexity hadn’t connected the dots. The redirect itself was the smoking gun, and you only see redirects when a real browser follows them.
Neither would have surfaced from a summary. Both surfaced inside ten minutes of scraping.
Wrap It, Then Aim It
The wrapper isn’t the interesting part — it’s an evening of bash and a Cloudflare API token. What’s interesting is the sequence: discover a primitive that does something the LLM-summary layer can’t (fetch live, fully-rendered content), wrap it just enough to be callable from the shell or from Cerebro, and aim it at a research task that’s already open — so you get real-world signal on the first run instead of synthetic test cases.
The Perplexity layer is fast and broad; cfbr is direct and current. Perplexity tells you what was probably true — the browser tells you what the site currently says. The gap between those two is wider than you’d expect, and it’s where the errors live.
cfbr is now wired into my default research stack: Perplexity for breadth, cfbr for verification, Cerebro to reconcile. The school decision went out clean. The tool stayed.
Most sessions don’t arrive with a fresh primitive attached. But when they do — when the discovery and the open problem land in the same hour — aim it immediately. I’ve deferred that move before. The tool never feels as urgent the next day.