---
title: "Extract and annotate PDFs with MuPDF"
description: "Use the shipped MuPDF facade to read page text, work with selections, and create annotations on the open document."
canonical: https://amnesia-docs.pages.dev/api/guides/render-with-mupdf/
source: "src/content/docs/api/guides/render-with-mupdf.md"
---

# Extract and annotate PDFs with MuPDF

This guide covers the shipped [`commands.mupdf`](/api/reference/commands-mupdf/) facade — the document
primitives for reading and annotating PDFs.

:::caution[Async, capability-gated, no raw bridge]
Every MuPDF method is **asynchronous and capability-gated**, and the facade **never returns the shared
rendering bridge**. Always `await`, avoid tight loops that could stall paint, and treat document
rendering as **desktop-first** — probe availability and degrade gracefully.
:::

## 1. Read the document

```js
const api = window.Amnesia; // or this.app.plugins.plugins['amnesia']?.api

const pages = await api.commands.mupdf.getPageCount();
const text = await api.commands.mupdf.extractPageText(1);
const dims = await api.commands.mupdf.getPageDimensions(1);
```

## 2. Work with selections and regions

```js
const snapped = await api.commands.mupdf.snapSelection(selection);
const copied = await api.commands.mupdf.copySelection(selection);
const region = await api.commands.mupdf.extractRegion(/* { page, bounds } */);
```

## 3. Search

```js
const matches = await api.commands.mupdf.search('mitochondria');
```

## 4. Annotate (requires write-annotations)

```js
const highlight = await api.commands.mupdf.highlightSelection(selection);
const annotation = await api.commands.mupdf.createAnnotation(/* annotation payload */);
const onPage = await api.commands.mupdf.getAnnotations(1);
await api.commands.mupdf.deleteAnnotation(annotation.id);
```

## Capabilities

Read primitives (`extractPageText`, `extractRegion`, `snapSelection`, `copySelection`, `getAnnotations`,
`getPageCount`, `getPageDimensions`, `search`) require `read-document`. Annotation writes
(`highlightSelection`, `createAnnotation`, `deleteAnnotation`) require `write-annotations`. On an
under-scoped [`connect()`](/api/reference/access/) handle, a gated call throws
[`PermissionError`](/api/reference/capabilities/#permissionerror). The facade-level `PermissionError` is
shipped and proven; the
[`connect()` capability-scoping](/api/reference/experimental-surfaces/#connect-capability-scoping-behavior)
that makes a handle under-scoped is itself experimental and untested.

## Performance

Because this surface drives the renderer, keep calls off hot paths, batch where you can, and never block
on synchronous work — the async contract exists so the engine can throttle or offload rendering.

<sub>Reference verified as of 2026-06-28.</sub>
