Estravon

Open source

Estravon is built on two public repositories. You can use just estravon-plugin or both.

estravon-plugin

tiberavonltd/estravon-plugin

The Zotero plugin. Works with both the hosted service (api.estravon.com) and a self-hosted local backend. Install from the XPI file — no developer tools needed.

estravon-backend

tiberavonltd/estravon-backend

The vanilla Python backend. Runs on your machine and serves results to the plugin over localhost. Use your own API key with Mistral, Replicate, or Datalab — or the MinerU engine, which runs entirely on your own hardware with no key and no third party in the loop.

Quickest start: pip install

You don't need to clone the repository to run the backend. Install directly from PyPI, create a working folder with a .env file containing your Mistral API key (or skip the key entirely — see below), and start:

pip install estravon-backend
estravon --port 7766

Get a pay-as-you-go API key at Mistral / Replicate, or a subscription API key at Datalab — or run the MinerU engine locally and pay no one. Full step-by-step at

estravon.com/install →

Two ways to use the plugin

Option A — Hosted service

Install the plugin, point it at api.estravon.com (the default), and buy a credit pack. No local setup, we take care of everything else.

Get started →

Option B — Self-hosted backend

Install the plugin and the backend. Point the plugin at http://localhost:7766. Configure your backend. Your machine sends your PDF straight to Mistral, Replicate, or Datalab — or, with the MinerU engine, to nowhere at all.

Install guide →

Updating the plugin

Zotero checks for plugin updates automatically once every 24 hours. The check is driven by a background timer — restarting Zotero does not reset the countdown. When a new version is available, Zotero installs it silently if "Allow automatic updates" is enabled in Tools → Plugins.

To update immediately without waiting 24 hours:

  1. Open Zotero → Tools → Plugins
  2. Click the gear icon (⚙) next to Estravon
  3. Choose Check for Updates

This calls the update check directly and bypasses the timer. The plugin downloads and installs the new XPI in place.

For developers: integrating with Estravon

Two ways to drive extraction programmatically, depending on what you're building.

Call the backend directly over HTTP

Any tool can POST a PDF to /process and read back Markdown — no plugin needed. The local backend responds synchronously; the hosted service queues the job and you poll GET /jobs/{id}. The backend returns Markdown and images only — attaching results to a Zotero item isn't part of this contract; that's what the hook below is for. Full endpoint contract, including the two-step Markdown fetch, is in docs/API.md (with an OpenAPI spec alongside it) in the backend repo.

Local backend:

# Local backend — synchronous
const form = new FormData();
form.append("pdf_file", pdfBlob, "section.pdf");
form.append("section_name", "chapter_01");
form.append("page_range", "14-40");

const res = await fetch("http://localhost:7766/process", {
  method: "POST",
  body: form,
});
const { files } = await res.json();  // [{label, md_url, image_urls}, ...]
const markdown = await (await fetch("http://localhost:7766" + files[0].md_url)).text();

Hosted backend:

# Hosted backend — async, poll until done
const res = await fetch("https://api.estravon.com/process", {
  method: "POST",
  headers: { "X-API-Key": apiKey },
  body: form,
});
const { job_id } = await res.json();  // HTTP 202 — queued

let result;
while (true) {
  const poll = await fetch(`https://api.estravon.com/jobs/${job_id}`,
    { headers: { "X-API-Key": apiKey } });
  result = await poll.json();
  if (result.status === "done" || result.status === "error") break;
  await new Promise(r => setTimeout(r, 3000));
}
docs/API.md on GitHub →

Trigger extraction through the Estravon plugin

If you're building a Zotero plugin yourself, call Zotero.Estravon.extract() and let Estravon handle backend routing and attaching results for you — no HTTP details, no re-implementing the attach/log-note logic.

const result = await Zotero.Estravon.extract({
  itemID,
  pageRange: "112-148",
  sectionName: "chapter_04",
  attach: true,   // false: resolve with markdown only, you handle filing
  silent: true,   // false: also show Estravon's own error dialog on failure
});
// => { status: "done"|"error", jobId?, markdown?, attachmentIDs?, error? }
Full reference in the estravon-plugin DEVELOPMENT.md →

Compare engines on your own PDF

estravon-backend-benchmarks runs the same PDF through MinerU, Mistral, Datalab, and Replicate and shows the results side by side — timing, cost, and the actual Markdown output. Drives a running estravon-backend over HTTP. It's the evaluation aid we are using to test the VLMs.

from estravon_bench.compare import compare

result = compare("your.pdf", "1-4", engines=["mineru", "mistral"])
print(result.to_markdown_table())
estravon-backend-benchmarks on GitHub →Worked examples: real engine comparisons →