Scrape any site.
Then search everything.
10 endpoints over 405 pages from 10 companies. Point it at a domain and it crawls, cleans and scores every page; ask it a question and it searches across all of them at once, by meaning and by exact words.
- Hybrid search over sections, not pages. You get the paragraph that answers, with its heading path.
- Clean markdown for any page or any whole company, as a file rather than a JSON envelope.
- Filters are columns scored at index time. Technicality is measured, not tagged.
- Coverage is declared. A response that has 300 of 1,100 pages says so, and says why.
curl https://stealpage.com/api/content?technicality_min=4
Building an agent? Skip the HTTP.
The same corpus as 7 MCP tools. One command and Claude, Cursor or Codex reads it directly — no client, no keys, no plumbing.
claude mcp add --transport http stealpage https://stealpage.com/api/mcpWhat you can filter on
None of these is a text search. Every one is a value written when the page was indexed, which is the difference between asking for technical articles and asking for pages containing the word “technical”.
- type
- article, docs, pricing, landing, case-study, changelog, comparison — what the page is for, not what section of the site it sits in.
- format
- tutorial, teardown, research, listicle, announcement, interview, reference, opinion.
- audience
- developer, marketer, founder, designer, exec, general. Who the page is written at.
- technicality
- 1–5, measured from code fences, term density and paragraph-length variance over the PROSE, never the raw markdown. A URL is not a sentence.
- promotional
- 1–5. Set promotional_max=2 and the marketing goes away. The word “technical” appears in almost no technical article and in every landing page that wants to sound like one.
- originality & depth
- Whether the argument is the author's own, and how far it goes. The two axes that separate a reference guide from a rewrite of one.
The 10 endpoints
Parameters and a runnable curl for each of them are in the reference. Every row here links straight at its entry.
Content
GET /api/contentFaceted list. Every filter is a column scored at index time, not a text match.GET /api/content/:idOne page: markdown, facets, assets with alt text, screenshots, crawl history, and who cites it.GET /api/searchHybrid vector + full text over page chunks, fused on rank. Filters apply inside both engines.Markdown
GET /api/content/:id.mdThe same page as raw markdown with a frontmatter block, so it stays attributable after it is pasted somewhere else.GET /api/domains/:root/content.mdA company's pages as one markdown file. Every heading inside a page is demoted one level so the bundle is a real tree, and it states how many pages it left out.Collections
Questions
Do I need a key?
Not for reads. Everything the public website shows is readable over the API without one, because a key on public data buys nothing and costs anonymous discovery.
How is this different from a scraping API?
A scraper hands back one page and forgets it. This crawls the site's own link graph, converts every page to markdown, scores what each one is, keeps every version, and lets you search across all 10 companies at once. The scrape is the first step, not the product.
Can I just get the markdown?
Yes. /api/content/:id.md returns one page with a frontmatter block, and /api/domains/:root/content.md returns a company as a single file — headings inside each page demoted one level so the bundle is a real tree.
What happens to a filter you do not recognise?
It comes back in the response. Every list declares what it filtered on, so a misspelled parameter is visible rather than silently ignored — and the two quality gates nobody asked for are named in `qualityGates` with a count of what they removed.
What if you only have part of a site?
The response says so, and says which bucket the rest is in. Coverage is a view with no write path, so it cannot drift from what was actually fetched.
Can I make you index something?
POST /api/crawl with a domain. It returns a job id straight away because a crawl is minutes to hours, and /api/jobs/:id reports progress per page rather than per wave.
Every response is what the public website already shows, and every page in it carries the URL it came from — attribution is in the markdown, not in a licence nobody reads. llms.txt says the same thing to the thing most likely to be reading it.
