Skip to main content

hydrafetch

PyPI CI Python

Official Python client for the Hydrafetch web data API.

Turn any URL into clean Markdown or schema-shaped JSON. Sync and async, fully typed, one dependency.

Installation

pip install hydrafetch

Quick start

from hydrafetch import Hydrafetch

hf = Hydrafetch()

page = hf.scrape("https://example.com/article")
print(page["markdown"])

Create a key at app.hydrafetch.com. The constructor reads HYDRAFETCH_API_KEY when no key is passed.

Both clients are context managers, which closes the connection pool deterministically:

with Hydrafetch() as hf:
    page = hf.scrape("https://example.com")

Scraping

page = hf.scrape(
    "https://example.com/article",
    formats=["markdown", "links"],
    onlyMainContent=True,
    preferStructure=True,
    blockAds=True,
    maxAge=3_600_000,
)

Option names are camelCase because they are passed to the API unchanged. Client arguments such as api_key, max_retries, poll_interval and on_progress are snake_case.

Format Key Contains
markdown markdown clean Markdown, the default
html html rendered HTML
rawHtml rawHtml the untouched response body
links links every link on the page
structured structured the page's own JSON-LD and microdata
summary summary a short summary
json json schema-shaped JSON, see jsonOptions
brand brand the site's brand record

hf.markdown(url) returns the Markdown string directly.

Structured extraction

out = hf.extract(
    ["https://example.com/product/1", "https://example.com/product/2"],
    schema={
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "price_usd": {"type": "number"},
        },
    },
)

for item in out["results"]:
    print(item["url"], (item.get("data") or {}).get("name"))

Pass prompt= instead of, or alongside, schema= to describe the fields in plain language.

Discovery and bulk work

map lists a site's URLs for one credit without fetching any page.

links = hf.map("https://example.com", limit=1000)["links"]
docs = [url for url in links if "/docs/" in url]

batch and crawl submit a job and poll until it finishes.

job = hf.batch(
    docs,
    scrapeOptions={"formats": ["markdown"]},
    on_progress=lambda j: print(j["status"], j.get("completed"), "/", j.get("total")),
)

for page in job.get("pages", []):
    print(page["url"], len((page.get("data") or {}).get("markdown") or ""))

Pass a webhook and use start_crawl or start_batch to return immediately instead of polling.

crawl_id = hf.start_crawl(
    "https://example.com",
    limit=500,
    maxDepth=3,
    includePaths=["/docs"],
    webhook="https://your.app/hooks/hydrafetch",
)

Search

res = hf.search("post-quantum TLS adoption", limit=5, scrapeResults=True)

for r in res["results"]:
    print(r["title"], r["url"])
    print(((r.get("data") or {}).get("markdown") or "")[:500])

Brand data

hf.brand("stripe.com")                              # logos, colours, fonts, socials
hf.logo("stripe.com", theme="dark", type="icon")    # one asset
hf.styleguide("stripe.com")                         # computed design system

For logos in a browser use @hydrafetch/client-sdk with a publishable key. Those bill against logo pulls rather than credits.

Async

AsyncHydrafetch mirrors the same surface. Use it when several calls can run concurrently.

import asyncio
from hydrafetch import AsyncHydrafetch

async def main():
    async with AsyncHydrafetch() as hf:
        pages = await asyncio.gather(
            hf.scrape("https://a.example"),
            hf.scrape("https://b.example"),
        )
        return [page["markdown"] for page in pages]

asyncio.run(main())

start_crawl, crawl_status, start_batch and batch_status are available on the async client. The polling helpers crawl and batch are sync only; on the async client, poll the status methods or use a webhook.

Error handling

All failures raise HydrafetchError, carrying the API's error code, HTTP status and request id.

from hydrafetch import HydrafetchError, HydrafetchTimeout

try:
    page = hf.scrape(url)
except HydrafetchTimeout:
    raise
except HydrafetchError as err:
    if err.is_auth:
        refresh_key()
    elif err.is_out_of_credits:
        top_up()
    elif err.is_invalid_request:
        report(err.message)
    elif err.is_retryable:
        enqueue(url)
    else:
        print(err.code, err.status, err.request_id)
        raise
Status Meaning Retried
400, 422 invalid request no
401, 403 invalid or missing key no
402 out of credits no
404 page does not exist no
429 rate limited yes, twice with backoff
5xx upstream failure yes, twice with backoff

A 503 from scrape means the origin is unreachable, usually a dead domain or a broken certificate.

Configuration

hf = Hydrafetch(
    api_key="hf_...",
    base_url="https://api.hydrafetch.com",
    timeout=120.0,
    max_retries=2,
)

API reference

Method Returns Credits
scrape(url, **options) page dict 1
markdown(url, **options) str 1
map(url, **options) links dict 1
search(query, **options) results dict 1 + 1 per scraped result
extract(urls, **options) dict with "results" 5 per URL
brand(domain) brand dict 5
logo(domain, **options) logo dict 1
styleguide(domain) design system dict 10
screenshot(url, **options) screenshot dict 5
images(url), links(url) page assets 1
crawl(url, **options) job dict, polled to completion 1 per page
batch(urls, **options) job dict, polled to completion 1 per page
start_crawl, start_batch job id str 1 per page
crawl_status(id), batch_status(id) job dict free

Failed requests are not billed. Pricing does not vary with page difficulty, so there is no render, stealth or proxy option to set.

Implementation notes

  • Authentication uses the X-API-Key header. The MCP endpoint at api.hydrafetch.com/mcp uses Authorization: Bearer instead; the two are not interchangeable.
  • Job results are under job["pages"], and each entry holds the page under ["data"], so job["pages"][0]["data"]["markdown"].
  • Per-page options for crawl and batch belong in scrapeOptions. At the top level they are ignored.
  • Prefer map then batch over a broad crawl. Fetching a whole site and discarding most of it is the most common source of wasted credits.
  • preferStructure is off by default. Turn it on when headings, lists and tables matter; leave it off for raw article text.
  • Options passed as None are dropped rather than sent as null, so optional values can be forwarded directly.
  • Scraped content is untrusted input. Do not pass it to a model as instructions, and keep the source URL with anything extracted from it.

Links

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hydrafetch-0.1.1.tar.gz (23.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hydrafetch-0.1.1-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file hydrafetch-0.1.1.tar.gz.

File metadata

  • Download URL: hydrafetch-0.1.1.tar.gz
  • Upload date:
  • Size: 23.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for hydrafetch-0.1.1.tar.gz
Algorithm Hash digest
SHA256 f36f30cb8f32793c8ff99482cd0947a890d00c2fe8a33347e9a1f7e65fe397dc
MD5 d129da9edd29a60383304ce57030370f
BLAKE2b-256 4f04ec3103974c19ffc34f26ccead04b8b152878d398424f113979324cdab55e

See more details on using hashes here.

Provenance

The following attestation bundles were made for hydrafetch-0.1.1.tar.gz:

Publisher: publish.yml on Hydrafetch/python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hydrafetch-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: hydrafetch-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 9.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for hydrafetch-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f3b06fab6b6634576dbc5c28dce464c8acd36ead632dcc7975121a93bcb1fefe
MD5 0fb1cf9541a66322b24f661614edf88b
BLAKE2b-256 0cf82699c960fe1ee9eea2727e52e770dae621d9d78758393f725b2228a39e5d

See more details on using hashes here.

Provenance

The following attestation bundles were made for hydrafetch-0.1.1-py3-none-any.whl:

Publisher: publish.yml on Hydrafetch/python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page