Using txtfetch as a LangChain and LlamaIndex document loader

May 5, 2026 · 3 min read · rag, langchain, llamaindex, llm-ingestion

LangChain and LlamaIndex both ship a long list of built-in document loaders — for PDFs, for S3 buckets, for Notion, for a dozen other sources — each wrapping some underlying parsing library. txtfetch doesn’t have an official loader in either ecosystem yet. What it does have is a plain HTTP endpoint, which is enough to write a thin custom loader yourself in about fifteen lines, without waiting on us to ship one.

Why write your own instead of waiting

A custom loader that calls /v1/extract gives you the same one-endpoint handling of PDFs, Office docs, scanned images, and HTML that the rest of txtfetch’s guides cover — multi-column PDFs, DOCX/PPTX/XLSX, OCR fallback — without a parsing library pinned in your requirements.txt for each format. The loader itself is a thin adapter: it calls the endpoint, reads extracted_text out of the JSON response, and hands it to the framework’s document object. There’s no hidden complexity to wait for an official package to solve.

A LangChain loader

LangChain’s BaseLoader interface just needs a load() method that returns a list of Document objects:

import requests
from langchain_core.document_loaders import BaseLoader
from langchain_core.documents import Document

class TxtfetchLoader(BaseLoader):
    def __init__(self, file_path: str, api_key: str):
        self.file_path = file_path
        self.api_key = api_key

    def load(self) -> list[Document]:
        with open(self.file_path, "rb") as f:
            resp = requests.post(
                "https://api.txtfetch.com/v1/extract",
                headers={"Authorization": f"Bearer {self.api_key}"},
                files={"file": f},
            )
        resp.raise_for_status()
        body = resp.json()
        if body["status"] != "success":
            raise ValueError(body.get("error", "extraction failed"))
        return [Document(
            page_content=body["extracted_text"],
            metadata={"source": self.file_path},
        )]

Use it exactly like any built-in loader:

loader = TxtfetchLoader("quarterly-report.pdf", api_key=TXTFETCH_KEY)
docs = loader.load()
# feed docs into your text splitter, then your vector store, as usual

A LlamaIndex reader

LlamaIndex’s equivalent is a BaseReader with a load_data() method:

import requests
from llama_index.core.readers.base import BaseReader
from llama_index.core.schema import Document

class TxtfetchReader(BaseReader):
    def __init__(self, api_key: str):
        self.api_key = api_key

    def load_data(self, file_path: str) -> list[Document]:
        with open(file_path, "rb") as f:
            resp = requests.post(
                "https://api.txtfetch.com/v1/extract",
                headers={"Authorization": f"Bearer {self.api_key}"},
                files={"file": f},
            )
        resp.raise_for_status()
        body = resp.json()
        if body["status"] != "success":
            raise ValueError(body.get("error", "extraction failed"))
        return [Document(text=body["extracted_text"], metadata={"source": file_path})]

Both loaders are deliberately minimal — a single request, a status check, and a document object. There’s no batching, retry, or concurrency built in; for ingesting more than a handful of files at once, see the batch ingestion guide for the concurrency and retry pattern to wrap around this same call. Full endpoint details — auth, request shape, response shape — are in the docs and the PDF extraction reference.

Feeding the URL variant instead of local files

If your documents live somewhere already reachable over HTTP — an S3 presigned URL, a CMS export — skip the local file entirely and pass ?url=:

resp = requests.post(
    "https://api.txtfetch.com/v1/extract",
    headers={"Authorization": f"Bearer {api_key}"},
    params={"url": document_url},
)

Same response shape, one fewer download step in your loader.

What this is and isn’t

This is a self-written adapter around a plain HTTP API — not an official txtfetch package on PyPI or npm, and not a LangChain- or LlamaIndex- maintained integration. If you’d rather not maintain even fifteen lines of loader code, an official SDK is on our roadmap; today, the pattern above is the fastest path to plugging txtfetch into either framework. Whatever document type it’s parsing — see the PDF extraction guide for the reasoning behind /v1/extract’s single-endpoint design — the loader itself doesn’t change; only the file you point it at does. Once you have documents loaded, chunking strategy is the next decision to make before embedding.

Building this into a production pipeline and want a hand? Get in touch and we’ll set you up with an API key.

Stop parsing. Start shipping.

Create an account and get an API key in minutes — the free Hobby plan needs no card.

Get started →