> Source: https://txtfetch.com/blog/langchain-llamaindex-document-loader > Plain-text twin — every page on txtfetch.com has one. https://txtfetch.com/text --- # 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, covering PDFs, S3 buckets, Notion, and a dozen other sources. Each one wraps some underlying parsing library. txtfetch doesn’t have an official loader in either ecosystem yet. What it does have is a plain HTTP endpoint. That’s 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 as the rest of txtfetch’s guides: PDFs, Office docs, scanned images, and HTML. That covers multi-column PDFs, DOCX/PPTX/XLSX, and OCR fallback. You don’t pin a parsing library 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: ```python 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: ```python 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: ```python 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](https://txtfetch.com/blog/batch-and-large-document-ingestion). It covers the concurrency and retry pattern to wrap around this same call. Full endpoint details (auth, request shape, response shape) are in the [docs](https://txtfetch.com/docs) and the [PDF extraction reference](https://txtfetch.com/extract/pdf). ## Feeding the URL variant instead of local files If your documents already live somewhere reachable over HTTP (an S3 presigned URL, a CMS export), skip the local file and pass `?url=`: ```python 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. It’s not an official `txtfetch` package on PyPI or npm. It’s also 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. The loader itself doesn’t change no matter what document type it’s parsing. Only the file you point it at does. See the [PDF extraction guide](https://txtfetch.com/blog/extract-text-from-pdf-for-rag) for the reasoning behind `/v1/extract`’s single-endpoint design. Once you have documents loaded, [chunking strategy](https://txtfetch.com/blog/chunking-strategies-for-rag) is the next decision to make before embedding. Building this into a production pipeline and want a hand? [Get in touch](https://txtfetch.com/contact) and we’ll set you up with an API key. keep reading - **[Ingesting large documents and big batches without falling over](https://txtfetch.com/blog/batch-and-large-document-ingestion)** A 500-page PDF and a ten-thousand-file backfill stress the same two things: single-request time and concurrency. Jun 23, 2026 · 3 min read - **[Chunking strategies for RAG: from clean text to good retrieval](https://txtfetch.com/blog/chunking-strategies-for-rag)** Fixed-size, recursive, and structure-aware chunking all assume clean extracted text. Extraction quality bounds chunk quality, whichever one you pick. Apr 7, 2026 · 3 min read - **[How to extract text from a PDF for RAG (without maintaining a parser)](https://txtfetch.com/blog/extract-text-from-pdf-for-rag)** Feeding PDFs into a RAG pipeline breaks the usual parser stack: multi-column layouts, embedded tables, scanned pages. One request handles all three. Jan 12, 2026 · 3 min read See also: [API docs →](https://txtfetch.com/docs) ## Try it on your own file. The free reader runs in your browser. Nothing gets uploaded. [Open the file reader →](https://txtfetch.com/tools/file-to-text) [Get an API key →](https://app.txtfetch.com/signup)