Web Scraping
Endpoints that only answer a POST
Some data never appears in a page. It sits behind a JSON or GraphQL endpoint that will not answer aGET, and until now the URL was the only thing you could describe.method: "POST"andbodysend the request the endpoint expects. The body goes verbatim, and you set your own content type throughheaders, so JSON, form-encoded and anything else are all just a body and a headerGETstays the default. Every existing call behaves exactly as before- Bodies are capped at 64KB. A request body selects what an endpoint returns; anything larger is a file upload, which is a different thing and not one we do
- A
POSTand aGETto the same URL are cached separately, and so are twoPOSTs with different bodies
POST target is fetched, never rendered, because a browser navigation is a GET and rendering one would quietly ask the origin a different question than you did. And PUT, PATCH and DELETE are deliberately not supported: POST is what makes unreachable data reachable, and a narrower surface is easier to reason about for a service that takes arbitrary URLs.MCP
Crawl and batch are tools now
Last time these were left off, on the grounds that they are jobs and a tool call is not. That was the wrong call for an agent that is perfectly happy to come back later.crawlandbatchstart the job and hand back an id;crawl_statusandbatch_statusread itlogojoins them, so an agent can fetch a company’s mark without building a URL itselfscreenshotnow takes the same sizing and timing options as the REST call- Thirteen tools, all under the existing
web:scrapescope, so a grant you have already approved needs no re-authorising
Platform
Bring your team in
A workspace was effectively one person. It is now a team, with the awkward cases handled rather than left to support.- Invite people, set their role, and remove them. A removed member’s seat comes back to the plan immediately
- Sign up with an email at a company that already has a workspace and you are not turned away: you ask to join, and an owner approves or declines it from the team page
- An invitation now survives sign-in and sign-up, so following an invite link and then creating an account lands you in the right workspace instead of a new empty one
- One workspace per company domain, enforced everywhere a workspace can be created
Platform
Told in the product, not just by email
Things that only ever arrived in an inbox now appear in the app, as they happen.- Credits running low, credits exhausted, a failed payment, a cancelled plan, your logo allowance, a publishable key being used off-domain, and join requests waiting on you
- They arrive live. No reload, no polling
- Email is now something you choose per category in settings, split into account alerts and product updates, so you can turn off the newsletter without also turning off “your payment failed”
Brand
Colours and marks you can trust
A brand’s palette is only useful if it is the brand’s palette. Several cases where it was not are fixed.- The primary colour now comes from the company’s own mark rather than from whatever colour the page happened to use most, and a palette leads with that colour instead of the page background
- Your operating system’s font is no longer reported as a company’s typeface
- A mark that cannot say what colour it is loses to one that can, and a saturated mark is classified as mono rather than by brightness alone
- We never serve an SVG that renders blank, which is what happened when a mark was being coloured by a stylesheet we do not have
- A domain whose certificate does not cover the bare name is retried on
wwwrather than failing to resolve - A styleguide that cannot read one value returns the rest instead of nothing
Brand
Logos you can put straight in an <img> tag
A company’s logo as an image URL, with no request to make first and no credits spent.- Publishable keys (
hf_pk_) are safe to commit and safe to ship in client-side markup. They serve logos and nothing else, so a key lifted from your page source cannot scrape on your account - Logo serves never spend credits. They have their own per-cycle allowance, so a page rendering forty logos costs forty serves and zero credits
- Lock a key to your own domains if you want, and pick the size, theme and shape per URL
- Served from the edge, so the second visitor gets it immediately
Web Scraping
PDFs come back as Markdown
Pointscrape at a PDF and you get Markdown, the same as any page. No separate endpoint, no extra credits, one scrape.- Headings stay headings and tables stay tables, instead of collapsing into a flat run of text in reading order
- Works on anything with a text layer, including exports from Word, LaTeX and design tools
- Previously a PDF could come back carrying page markup rather than clean Markdown. It no longer does
Web Extraction
A publication date only when the page has one
metadata.publishedTime is now read from what the page actually declares, and is null when it declares nothing.- A copyright year in a footer is no longer treated as a publication date. An undated pricing page used to come back “published 1 January” of whatever year the footer mentioned
- The same applies to the date line at the top of the Markdown: present when the page states one, absent when it does not
- Pages that declare a real date are unaffected
Search
Search returns results; scraping them is opt-in
search used to fetch every result’s page by default, so a call that reads like one credit billed six. Scraping is now something you ask for.- A search costs 1 credit and returns the ranked title, url and snippet
- Set
scrapeResults: trueto also fetch each result, at 1 credit per page scraped, the same as scraping that page yourself dataon each result isnullunless you asked for the scrape
scrapeResults: true and the behaviour and cost are exactly what they were.The engine parameter and the data.engine response field are also gone. Which index answered is an implementation detail we route on for cost and availability, and pinning it stopped us falling back when an engine was unavailable.Web Scraping
One URL, one response shape
A scrape used to wait, then hand back a job id if the page ran long. That meant a second code path most callers never wrote, appearing only on the rare slow page. It is gone.- A single URL is answered inline, always:
/scrape,/markdown,/html,/raw-html,/linksand/structured - The synchronous budget is 90 seconds. Past it you get
504with codeREQUEST_TIMEOUT, naming the budget - The fetch keeps running in the background after a timeout, so the capture usually lands in the cache and an immediate retry is fast
- Want a job instead? Send
async: true. It is opt-in now, never automatic - Crawl and batch are unchanged: they span many URLs and can genuinely run for minutes
MCP
Every sync endpoint is an MCP tool
The MCP server now exposes the whole synchronous surface, and describes itself so you never have to guess what it can do.- New tools:
styleguide,screenshotandimages, joiningscrape,map,search,extractandbrand GET /mcp/toolslists every tool with its description, credit cost and full JSON Schema — no authentication required, so a client can see the capabilities before connecting- Tools cost exactly what the equivalent REST call costs
- The new tools sit under the existing
web:scrapescope, so an existing grant needs no re-authorising
Brand
Brand and styleguide
Answer “what is this company” and “what does it look like” from nothing but a domain, instead of scraping a homepage and guessing.GET /v1/web/brandreturns logos suited to light and dark backgrounds, the real brand colours, name, description and social profiles. Every field states whether the company declared it or we harvested itPOST /v1/web/brandresolves up to 50 domains in one callGET /v1/web/brand/searchfinds brands we already hold by company name or domain, so you can turn what a user typed into a domain before resolving it. Returns enough to render a picker, never resolves a new domain, and is not billedGET /v1/web/styleguidereads the design system a site actually paints, from computed styles in a real browser, so a colour defined through four layers of CSS variables comes back as the hex it resolved to. Colours arrive by role with contrast ratios, so they drop into a theme without guesswork
Platform
Billing that matches what you got
Several cases where a call could be charged without delivering a usable page are now not billed at all.- An origin’s own error page is no longer recorded as a delivered scrape
- A response with no bytes is never treated as a success, whatever status the origin returned
- A failed render no longer discards the static capture it was meant to improve on
- Upstream failures surface as errors rather than empty
200s
Web Scraping
Ask for structure when you need it
preferStructure keeps headings, lists and tables as real markdown. It was already on the REST API; it is now on the MCP tools too, so agents can ask for it.metadata.formatis nowmetadata.structure, reportingmarkdownorplainplainis not a failure — the default extractor optimises for capturing every word and wins on listing and forum pages — but if you wanted headings, retry withpreferStructure: true- Available on
scrape,searchandextractover both REST and MCP
Web Scraping
See whether your webhooks landed
Every callback we attempt for a crawl or batch is now recorded and readable, so a webhook that never arrives is something you can diagnose instead of guess at.GET /v1/web/crawl/{id}/deliveriesandGET /v1/web/batch/{id}/deliveries- Each delivery reports its status, attempt count, the HTTP status your endpoint returned, and why the last attempt failed
- A
failedrow with a 5xx means we couldn’t reach you; a 4xx means we did and you rejected it
Platform
Errors you can branch on
Every error now returns the same envelope with a stable, machine-readablecode. Branch on the code — the wording of message may change, the code won’t. Each response also carries a requestId to quote if you need us to look something up.Web Extraction
Trustworthy extraction
Structured extraction now returns, per field, how confident it is and the exact passage a value came from. Turn it on withshowConfidence and showSources.- Extract across a whole site: pass a
/*scope inurlsand every discovered page is merged into one result. - New
entitiesprimitive returns normalized people, companies, and products found on a page. - Every response reports the credits it consumed and how fresh the data is.
Web Scraping
Dedicated format endpoints
Prefer a single, purpose-built route? Each output now has its own endpoint, alongside the flexible/scrape.POST /v1/web/markdownfor clean MarkdownPOST /v1/web/htmlfor cleaned main-content HTMLPOST /v1/web/raw-htmlfor unmodified page HTMLPOST /v1/web/linksfor a page’s linksPOST /v1/web/structuredfor the page’s own structured data
/scrape, so you can switch anytime.Web Scraping
Search, crawl, and media
- Search the web and get ranked results, each scraped to clean data. Filter by time, domain, and country.
- Crawl a whole site as one asynchronous job, with completion webhooks so you do not have to poll.
- Media: capture a full-page screenshot or collect a page’s images.
Platform
Launch
The first public version of the Hydrafetch API.POST /v1/web/scrapetakes one URL and returns clean Markdown and structured data.POST /v1/web/mapdiscovers every URL on a site.- Credit-based billing, charged only on success, with a live balance on every response.
- API-key authentication through the
X-API-Keyheader.