langchain-hydrafetch
LangChain integration for the Hydrafetch web data API.
Load pages as documents, search the web as a retriever, and give agents four tools that read, extract and enrich from the live web. Sync and async, fully typed.
Installation
pip install langchain-hydrafetch
Create a key at app.hydrafetch.com and set it:
export HYDRAFETCH_API_KEY="hf_..."
Everything below reads that variable when no api_key= is passed.
Quick start
from langchain_hydrafetch import HydrafetchLoader
docs = HydrafetchLoader("https://example.com/article").load()
print(docs[0].page_content)
print(docs[0].metadata["title"])
Document loader
Three modes. scrape loads one page, crawl walks a site and loads every page it finds, and map returns one document per discovered URL without fetching the bodies.
HydrafetchLoader("https://example.com/article").load()
HydrafetchLoader("https://example.com", mode="crawl", params={"limit": 50}).load()
HydrafetchLoader("https://example.com", mode="map").load()
content_format chooses what lands in page_content — markdown by default, or html, rawHtml, summary. params is forwarded to the API untouched, so anything the endpoint accepts works here:
HydrafetchLoader(
"https://example.com/article",
content_format="markdown",
params={"onlyMainContent": True, "preferStructure": True, "blockAds": True},
).load()
Documents carry source and status, plus whatever page metadata was found: title, description, language, site_name, author, published_time, word_count, page_type, image. A redirect adds final_url; a crawled page adds depth; a mapped URL adds lastmod when the sitemap declares one.
Use lazy_load() to stream a large crawl instead of building the whole list in memory:
for doc in HydrafetchLoader("https://example.com", mode="crawl").lazy_load():
index.add(doc)
Error pages are refused, not loaded
A URL that answers with an error status raises instead of returning a document, because the body of a 404 page is not the page you asked for and a retrieval index should not quietly absorb one.
HydrafetchLoader("https://example.com/gone").load()
# ValueError: https://example.com/gone returned HTTP 404. The body of an error
# page is not the page you asked for; pass raise_for_status=False to load it anyway.
In crawl mode a single dead page must not throw away the whole job, so error pages are dropped and the rest of the crawl is kept. Pass raise_for_status=False to load error pages in either mode.
Retriever
from langchain_hydrafetch import HydrafetchSearchRetriever
retriever = HydrafetchSearchRetriever(k=5)
docs = retriever.invoke("best open source vector databases")
Each document holds the result snippet, with source, title and rank in metadata. Pass scrape_content=True to fetch and return the full page body for every result instead:
HydrafetchSearchRetriever(k=3, scrape_content=True).invoke("...")
That costs one extra credit per result. k works as a constructor argument or per call, and search_params is forwarded to the search endpoint:
retriever.invoke("...", k=2)
HydrafetchSearchRetriever(search_params={"country": "us"})
Agent tools
from langchain_hydrafetch import (
HydrafetchBrandTool,
HydrafetchExtractTool,
HydrafetchScrapeTool,
HydrafetchSearchTool,
)
tools = [
HydrafetchSearchTool(),
HydrafetchScrapeTool(),
HydrafetchExtractTool(),
HydrafetchBrandTool(),
]
| tool | argument | returns |
|---|---|---|
hydrafetch_search |
query, limit |
JSON with query and results of title, url, snippet |
hydrafetch_scrape |
url |
the page as markdown |
hydrafetch_extract |
urls, json_schema or prompt |
JSON with one entry per URL |
hydrafetch_brand |
domain |
JSON brand record: name, description, tagline, logo assets, colours, fonts, socials |
Search finds pages, scrape reads a page you already have. Giving an agent both is the usual setup.
Structured extraction takes either a schema or a plain-language description:
HydrafetchExtractTool().invoke({
"urls": ["https://example.com/pricing"],
"json_schema": {
"type": "object",
"properties": {"plans": {"type": "array", "items": {"type": "string"}}},
},
})
HydrafetchExtractTool().invoke({
"urls": ["https://example.com/about"],
"prompt": "the founding year and the headquarters city",
})
Async
The retriever and every tool support ainvoke, and the loader supports alazy_load and aload:
docs = await HydrafetchSearchRetriever().ainvoke("...")
text = await HydrafetchScrapeTool().ainvoke({"url": "https://example.com"})
Error handling
Failures raise HydrafetchError from the underlying client, carrying the API's error code, HTTP status and request id.
from hydrafetch import HydrafetchError, HydrafetchTimeout
try:
docs = HydrafetchLoader(url).load()
except HydrafetchTimeout:
raise
except HydrafetchError as err:
if err.is_out_of_credits:
top_up()
elif err.is_retryable:
enqueue(url)
else:
raise
| Status | Meaning | Retried |
|---|---|---|
| 400, 422 | invalid request | no |
| 401, 403 | invalid or missing key | no |
| 402 | out of credits | no |
| 429 | rate limited | yes, twice with backoff |
| 5xx | upstream failure | yes, twice with backoff |
A page that loads but answers with an error status raises ValueError from the loader instead — that is a bad URL, not a failed request.
Configuration
Every class accepts the same connection options, all optional:
| option | default | meaning |
|---|---|---|
api_key |
HYDRAFETCH_API_KEY |
your API key |
base_url |
https://api.hydrafetch.com |
API base URL |
timeout |
120.0 |
per-request timeout in seconds |
max_retries |
2 |
retries on 429 and 5xx |
Credits
| call | credits |
|---|---|
loader, scrape mode |
1 |
loader, map mode |
1 |
loader, crawl mode |
1 per page |
| retriever | 1, plus 1 per result with scrape_content=True |
hydrafetch_scrape |
1 |
hydrafetch_search |
1 |
hydrafetch_extract |
5 per URL |
hydrafetch_brand |
5 |
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
- Prefer
mapthen a batch ofscrapeloads over a broadcrawl. Fetching a whole site and discarding most of it is the most common source of wasted credits. paramsincrawlmode is forwarded to the crawl endpoint, so per-page options belong underscrapeOptions. At the top level they are ignored.preferStructureis off by default. Turn it on when headings, lists and tables matter; leave it off for raw article text.- The loader constructs its client eagerly, so a missing API key fails at construction rather than at
load(). - The retriever and tools construct their clients lazily on first use, which keeps them cheap to build and safe to define at import time.
- Metadata keys are snake_cased on the way out, so the API's
siteNamebecomessite_name. - Scraped content is untrusted input. Do not pass it to a model as instructions, and keep
metadata["source"]with anything extracted from it.
Development
uv sync
uv run ruff check src tests
uv run ruff format --check src tests
uv run pytest -q
Unit tests run offline against fake clients. The integration tests are LangChain's own langchain-tests standard suite; they are skipped unless HYDRAFETCH_API_KEY is set, and they spend real credits.
Links
- Documentation
- OpenAPI specification
- MCP server and editor setup
- Python client — the client this integration wraps
- LlamaIndex reader
- Other clients: Node · Go · Ruby · Rust · PHP
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langchain_hydrafetch-0.1.0.tar.gz.
File metadata
- Download URL: langchain_hydrafetch-0.1.0.tar.gz
- Upload date:
- Size: 155.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9eb47d3166a5e8d086c4616c568db7ec35d34e69e35ef656b2c752a1a607bd3
|
|
| MD5 |
182cee02a814245d812b78553478ba88
|
|
| BLAKE2b-256 |
e416ba7ff1977139f736d6766a6c266120502157c34e4f483fcad32d593115d3
|
Provenance
The following attestation bundles were made for langchain_hydrafetch-0.1.0.tar.gz:
Publisher:
publish.yml on Hydrafetch/langchain-hydrafetch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_hydrafetch-0.1.0.tar.gz -
Subject digest:
e9eb47d3166a5e8d086c4616c568db7ec35d34e69e35ef656b2c752a1a607bd3 - Sigstore transparency entry: 2559418545
- Sigstore integration time:
-
Permalink:
Hydrafetch/langchain-hydrafetch@7969cfa4f835b71b8614964afffca79648969fc5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Hydrafetch
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7969cfa4f835b71b8614964afffca79648969fc5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file langchain_hydrafetch-0.1.0-py3-none-any.whl.
File metadata
- Download URL: langchain_hydrafetch-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e7407405f3df5bb8f2eada50c93c4d19dc5ac6c8b824c6c343e160815b4f4be
|
|
| MD5 |
8be1a0856f51c96482e9fcc05171818b
|
|
| BLAKE2b-256 |
bf3d862f6514e538c84a7df9eff7d6f8f07abc93223ee9b189a6b282edb33221
|
Provenance
The following attestation bundles were made for langchain_hydrafetch-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Hydrafetch/langchain-hydrafetch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_hydrafetch-0.1.0-py3-none-any.whl -
Subject digest:
0e7407405f3df5bb8f2eada50c93c4d19dc5ac6c8b824c6c343e160815b4f4be - Sigstore transparency entry: 2559419001
- Sigstore integration time:
-
Permalink:
Hydrafetch/langchain-hydrafetch@7969cfa4f835b71b8614964afffca79648969fc5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Hydrafetch
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7969cfa4f835b71b8614964afffca79648969fc5 -
Trigger Event:
push
-
Statement type: