Skip to content

Extraction Basics

Kreuzberg provides 8 core extraction functions organized by input type (file path vs in-memory bytes), cardinality (single vs batch), and execution model (sync vs async). Pick the function that matches your situation — the extraction logic is identical across all variants.

Input Single sync Single async Batch sync Batch async
File path extract_file_sync extract_file batch_extract_files_sync batch_extract_files
Bytes extract_bytes_sync extract_bytes batch_extract_bytes_sync batch_extract_bytes

Pass a file path. Kreuzberg detects the MIME type from the extension and selects the right parser automatically.

Python
from kreuzberg import extract_file_sync, ExtractionConfig
config: ExtractionConfig = ExtractionConfig()
result = extract_file_sync("document.pdf", config=config)
content: str = result.content
table_count: int = len(result.tables)
metadata: dict = result.metadata
print(f"Content length: {len(content)} characters")
print(f"Tables: {table_count}")
print(f"Metadata keys: {list(metadata.keys())}")
Python
import asyncio
from kreuzberg import extract_file, ExtractionConfig
async def main() -> None:
config: ExtractionConfig = ExtractionConfig()
result = await extract_file("document.pdf", config=config)
content: str = result.content
table_count: int = len(result.tables)
print(f"Content length: {len(content)} characters")
print(f"Tables: {table_count}")
asyncio.run(main())

When the file is already loaded in memory (for example, from an upload or network response), pass the byte array with its MIME type. Unlike file extraction, the MIME type is required since there’s no file extension to infer it from.

Python
from kreuzberg import extract_bytes_sync, ExtractionConfig
with open("document.pdf", "rb") as f:
data = f.read()
result = extract_bytes_sync(
data,
mime_type="application/pdf",
config=ExtractionConfig()
)
print(result.content)
Python
import asyncio
from kreuzberg import extract_bytes, ExtractionConfig
async def main():
with open("document.pdf", "rb") as f:
data = f.read()
result = await extract_bytes(
data,
mime_type="application/pdf",
config=ExtractionConfig()
)
print(result.content)
asyncio.run(main())

Batch functions accept an array of file paths (or byte arrays) and process them concurrently. This is typically 2-5x faster than looping over single-file functions because Kreuzberg parallelizes internally.

Python
from kreuzberg import batch_extract_files_sync, ExtractionConfig
files: list[str] = ["doc1.pdf", "doc2.docx", "doc3.pptx"]
config: ExtractionConfig = ExtractionConfig()
results = batch_extract_files_sync(files, config=config)
for i, result in enumerate(results):
char_count: int = len(result.content)
print(f"File {i + 1}: {char_count} characters")
Python
from kreuzberg import batch_extract_bytes_sync, ExtractionConfig
files: list[str] = ["doc1.pdf", "doc2.docx"]
data_list: list[bytes] = []
mime_types: list[str] = []
for file in files:
with open(file, "rb") as f:
data_list.append(f.read())
mime_type: str = "application/pdf" if file.endswith(".pdf") else "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
mime_types.append(mime_type)
config: ExtractionConfig = ExtractionConfig()
results = batch_extract_bytes_sync(data_list, mime_types, config=config)
for i, result in enumerate(results):
char_count: int = len(result.content)
print(f"Document {i + 1}: {char_count} characters")

When a batch contains a mix of document types that need different settings (for example, scanned images needing OCR alongside text-based PDFs), use FileExtractionConfig to override options per file while sharing a common batch config.

mixed_batch.py
from kreuzberg import (
batch_extract_files_sync,
ExtractionConfig,
FileExtractionConfig,
OcrConfig,
)
config = ExtractionConfig(output_format="markdown")
paths = ["report.pdf", "scan.tiff", "notes.html"]
file_configs = [
None,
FileExtractionConfig(
force_ocr=True,
ocr=OcrConfig(backend="tesseract", language="deu"),
),
FileExtractionConfig(output_format="plain"),
]
results = batch_extract_files_sync(paths, config, file_configs=file_configs)

Fields set to None in FileExtractionConfig inherit the batch default. Batch-level concerns like max_concurrent_extractions, use_cache, and security_limits cannot be overridden per file. See the Configuration Reference for the full list of overridable fields.

Kreuzberg strips running headers, footers, watermarks, and cross-page repeating text by default so that downstream RAG and LLM pipelines see clean body content. ContentFilterConfig lets you opt back in to any of these when you need them, for example when extracting legal forms where the header carries the case number, or when running text analysis on a PDF whose brand name was being incorrectly removed by the repeating-text heuristic.

The defaults match the field defaults documented in ContentFilterConfig: include_headers=False, include_footers=False, strip_repeating_text=True, include_watermarks=False.

keep_headers_footers.py
from kreuzberg import (
extract_file_sync,
ContentFilterConfig,
ExtractionConfig,
)
# Legal/forms work: keep header and footer text
config = ExtractionConfig(
content_filter=ContentFilterConfig(
include_headers=True,
include_footers=True,
),
)
result = extract_file_sync("contract.pdf", config=config)

When a layout-detection model is active, it can independently classify regions as page headers or footers and strip them per page. Setting include_headers=True / include_footers=True also disables that per-page stripping. See the reference page for the full field semantics and per-format behavior.

Kreuzberg supports 75+ file formats across 8 categories:

Category Extensions Notes
PDF .pdf Native text + OCR for scanned pages
Images .png, .jpg, .jpeg, .tiff, .bmp, .webp Requires OCR backend
Office .docx, .pptx, .xlsx Modern formats via native parsers
Legacy Office .doc, .ppt Native OLE/CFB parsing
Email .eml, .msg Full support including attachments
Web .html, .htm Converted to Markdown with metadata
Text .md, .txt, .xml, .json, .yaml, .toml, .csv Direct extraction
Archives .zip, .tar, .tar.gz, .tar.bz2 Recursive extraction

Kreuzberg can track page boundaries and extract per-page content. Page tracking availability depends on the format:

  • PDF — Full byte-accurate page tracking with O(1) lookup
  • PPTX — Slide boundary tracking (each slide = one page)
  • DOCX — Best-effort detection using explicit <w:br type="page"/> tags
  • Other formats — No page tracking

Enable page extraction with PageConfig:

page_tracking.py
config = ExtractionConfig(
pages=PageConfig(
insert_page_markers=True,
marker_format="\n\n<!-- PAGE {page_num} -->\n\n"
)
)

Page markers like <!-- PAGE 1 --> are inserted at boundaries in the content field — useful for LLMs that need to understand document layout. When both page tracking and chunking are enabled, chunks automatically include first_page and last_page metadata.

See PageConfig Reference for all options and Advanced Page Tracking for chunk-to-page mapping examples.

When extracting source code files (.py, .rs, .ts, .go, etc.), Kreuzberg uses tree-sitter to produce structured code intelligence. The result is available in ExtractionResult.code_intelligence as a ProcessResult containing:

  • Structure – Functions, classes, methods, interfaces, and their nesting hierarchy
  • Imports/Exports – Module dependencies and re-exports
  • Symbols – Variables, constants, type aliases
  • Docstrings – Parsed documentation in 10+ formats (Google, NumPy, JSDoc, RustDoc, etc.)
  • Diagnostics – Parse errors with line/column positions
  • Chunks – Semantic code chunks split at function/class boundaries

Code files bypass the text-splitter chunking pipeline entirely. Instead, TSLP’s CodeChunks (function/class-aware) map directly to Kreuzberg Chunks with semantic chunk_type and heading context.

Control the content mode with TreeSitterProcessConfig.content_mode:

  • chunks (default) – Semantic TSLP chunks as the content output
  • raw – Source code as-is, no transformation
  • structure – Headings and docstrings only

Render individual PDF pages as PNG images. Unlike the extraction pipeline (which parses text, tables, metadata), this API produces raw pixel data for thumbnails, vision model input, or custom OCR pipelines.

API When to use
render_pdf_page You know which page you need, or only need a few pages
PdfPageIterator Process every page sequentially without loading all images into memory
DPI Pixel size (US Letter) Use case
72 612 x 792 Thumbnails, quick previews
150 (default) 1275 x 1650 General-purpose, screen display
300 2550 x 3300 OCR input, print quality

Tip: Use 300 DPI when rendering pages for OCR or vision models. The default 150 DPI may reduce recognition accuracy on small text.

When extracting from bytes, Kreuzberg requires an explicit MIME type since there’s no file extension to infer it from. For file paths, auto-detection from the extension is automatic.

Python
from kreuzberg import extract_file
# File without extension — provide MIME type explicitly
result = extract_file("document_copy", mime_type="application/pdf", config=config)

All extraction functions raise typed exceptions on failure. Catch specific exceptions to handle different failure modes:

Python
from kreuzberg import extract_file_sync, extract_bytes_sync, ExtractionConfig
from kreuzberg import (
KreuzbergError,
ParsingError,
OCRError,
ValidationError,
)
try:
result = extract_file_sync("document.pdf")
print(f"Extracted {len(result.content)} characters")
except FileNotFoundError as e:
print(f"File not found: {e}")
except ParsingError as e:
print(f"Failed to parse document: {e}")
except OCRError as e:
print(f"OCR processing failed: {e}")
except KreuzbergError as e:
print(f"Extraction error: {e}")
try:
config: ExtractionConfig = ExtractionConfig()
pdf_bytes: bytes = b"%PDF-1.4\n"
result = extract_bytes_sync(pdf_bytes, "application/pdf", config)
print(f"Extracted: {result.content[:100]}")
except ValidationError as e:
print(f"Invalid configuration: {e}")
except OCRError as e:
print(f"OCR failed: {e}")
except KreuzbergError as e:
print(f"Extraction failed: {e}")