> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/extraction/text-extract.md).

# Extract Text from PDF Documents Using JavaScript

Here is a sample showcasing how to extract text from PDF documents using JavaScript. Run the sample with Apryse SDK free trial. The Apryse Web SDK streamlines secure, serverless document processing wi

Text extraction is based on a inhouse heuristic algorithm which attempts to find the human readable reading order in a document. The reading order is determined by a number of factors such as spacing, font size, font type, and more. What makes text extraction challenging is there is no clear definition in the PDF specification which describes semantic information or logical structures.

{% hint style="warning" %}
Text extraction reading ordering is not defined in the ISO PDF standard. In fact, there is no concept of sentence, paragraph, tables, or anything similar in a typical PDF file. This means each PDF vendor is left to their own design/solution and will extract text with some differences. Therefore, reading order is not guaranteed to match the order that a typical user reading the document would follow.

The reading order of a magazine, newspaper article, and an academic article are all quite different due to the lack of semantic information in a PDF and the placement/ordering of text in the document. Where different users may have different expectations of the correct reading order.
{% endhint %}

Use [loadPageText](https://sdk.apryse.com/api/web/Core.Document.html#loadPageText__anchor) API to capture text from a document page.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
const wvElement = document.getElementById('viewer');
WebViewer({ ...options }, wvElement)
  .then(async instance => {
    const pageNumber = 1; // Extract the text in the first page
    const doc = instance.Core.documentViewer.getDocument();

    const text = await doc.loadPageText(pageNumber);
    // .. do something with text
    console.log(text);
  });
```

{% endcode %}

[DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [Document.loadPageText](https://sdk.apryse.com/api/web/Core.Document.html#loadPageText__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v7.0+)" %}
{% code lineNumbers="true" %}

```js
const wvElement = document.getElementById('viewer');
WebViewer({ ...options }, wvElement)
  .then(async instance => {
    const pageNumber = 1; // Extract the text in the first page
    const doc = instance.docViewer.getDocument();

    const text = await doc.loadPageText(pageNumber);
    // .. do something with text
    console.log(text);
  });
```

{% endcode %}

[DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [Document.loadPageText](https://sdk.apryse.com/api/web/Core.Document.html#loadPageText__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
const wvElement = document.getElementById('viewer');
WebViewer({ ...options }, wvElement)
  .then(instance => {
    const pageIndex = 0; // Extract the text in the first page
    const doc = instance.docViewer.getDocument();

    // Accepts 0 based page index
    doc.loadPageText(pageIndex, text => {
      // .. do something with text
      console.log(text);
    })
  });
```

{% endcode %}

[DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [Document.loadPageText](https://sdk.apryse.com/api/web/Core.Document.html#loadPageText__anchor)
{% endtab %}
{% endtabs %}

## Advanced text extraction from a page region

To perform advanced text extraction from a region of a PDF document page.

{% hint style="warning" %}
Make sure you have [Full API enabled in WebViewer.](/web/what-is-webviewer/full-api.md)
{% endhint %}

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer({
  fullAPI: true,
  // Other instantiation options
})
  .then(instance => {
    const { PDFNet, documentViewer } = instance.Core;

    documentViewer.addEventListener('documentLoaded', async () => {
      await PDFNet.initialize();
      const doc = await documentViewer.getDocument().getPDFDoc();
      const firstPage = await doc.getPage(1);

      const txt = await PDFNet.TextExtractor.create();
      const rect = new PDFNet.Rect(0, 0, 612, 794);
      txt.begin(firstPage, rect); // Read the page.

      // Extract words one by one.
      let line = await txt.getFirstLine();
      for (; (await line.isValid()); line = (await line.getNextLine()))
      {
          for (word = await line.getFirstWord(); (await word.isValid()); word = (await word.getNextWord()))
          {
              // await word.getString();
          }
      }
    })
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [PDFNet.PDFDoc.createFromUrl](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#.createFromURL__anchor) [PDFNet.PDFDoc.getPage](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#getPage__anchor) [PDFNet.TextExtractor.create](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#.create__anchor) [PDFNet.TextExtractor.getFirstLine](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#getFirstLine__anchor) [PDFNet.TextExtractorLine.isValid](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorLine.html#isValid__anchor) [PDFNet.TextExtractorLine.getNextLine](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorLine.html#getNextLine__anchor) [PDFNet.TextExtractorLine.isValid](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorLine.html#getFirstWord__anchor) [PDFNet.TextExtractorWord.isValid](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorWord.html#isValid__anchor) [PDFNet.TextExtractorWord.getNextWord](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorWord.html#getNextWord__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer({
  fullAPI: true,
  // Other instantiation options
})
  .then(instance => {
    const { PDFNet, docViewer } = instance;
    docViewer.on('documentLoaded', () => {
      await PDFNet.initialize();
      const doc = await docViewer.getDocument().getPDFDoc();
      const firstPage = await doc.getPage(1);
      const txt = await PDFNet.TextExtractor.create();
      const rect = new PDFNet.Rect(0, 0, 612, 794);
      txt.begin(page, rect); // Read the page.
      // Extract words one by one.
      let line = await txt.getFirstLine();
      for (; (await line.isValid()); line = (await line.getNextLine()))
      {
          for (word = await line.getFirstWord(); (await word.isValid()); word = (await word.getNextWord()))
          {
              // await word.getString();
          }
      }
    })
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [PDFNet.PDFDoc.createFromUrl](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#.createFromURL__anchor) [PDFNet.PDFDoc.getPage](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#getPage__anchor) [PDFNet.TextExtractor.create](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#.create__anchor) [PDFNet.TextExtractor.getFirstLine](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#getFirstLine__anchor) [PDFNet.TextExtractorLine.isValid](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorLine.html#isValid__anchor) [PDFNet.TextExtractorLine.getNextLine](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorLine.html#getNextLine__anchor) [PDFNet.TextExtractorLine.isValid](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorLine.html#getFirstWord__anchor) [PDFNet.TextExtractorWord.isValid](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorWord.html#isValid__anchor) [PDFNet.TextExtractorWord.getNextWord](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractorWord.html#getNextWord__anchor)
{% endtab %}
{% endtabs %}

[Read a PDF File (Parse & Extract Text)](/web/get-started/samples/textextracttest.md) Full sample code which illustrates the basic text extraction capabilities.

## Extract text under an annotation

To extract text from under an annotation in the document after all annotations are loaded.

{% hint style="warning" %}
Make sure you have [Full API enabled in WebViewer.](/web/what-is-webviewer/full-api.md)
{% endhint %}

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer({
  fullAPI: true,
  // Other instantiation options
})
  .then(instance => {
    const { PDFNet, documentViewer, annotManager } = instance.Core;
    documentViewer.addEventListener('annotationsLoaded', async () => {
      await PDFNet.initialize();
      const doc = await documentViewer.getDocument().getPDFDoc();
      // export annotations from the document
      const annots = await annotManager.exportAnnotations();
      // Run PDFNet methods with memory management
      await PDFNet.runWithCleanup(async () => {
        // lock the document before a write operation
        // runWithCleanup will auto unlock when complete
        doc.lock();
        // import annotations to PDFNet
        const fdf_doc = await PDFNet.FDFDoc.createFromXFDF(annots);
        await doc.fdfUpdate(fdf_doc);
        const page = await doc.getPage(1);
        const rect = await page.getCropBox();
        const annotation = await page.getAnnot(0);
        const te = await PDFNet.TextExtractor.create();
        te.begin(page, rect);
        const textData = await te.getTextUnderAnnot(annotation);
        console.log(textData);
      });
    })
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [Document.getPDFDoc ](https://sdk.apryse.com/api/web/Core.Document.html#getPDFDoc__anchor)[PDFNet.PDFDoc.getPage](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#getPage__anchor) [PDFNet.Page.getCropBox](https://sdk.apryse.com/api/web/Core.PDFNet.Page.html#getCropBox__anchor) [PDFNet.Page.getAnnot](https://sdk.apryse.com/api/web/Core.PDFNet.Page.html#getAnnot__anchor) [PDFNet.TextExtractor.create](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#.create__anchor) [PDFNet.TextExtractor.begin](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#begin__anchor) [PDFNet.TextExtractor.getTextUnderAnnot](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#getTextUnderAnnot__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer({
  fullAPI: true,
  // Other instantiation options
})
  .then(instance => {
    const { PDFNet, docViewer, annotManager } = instance;
    docViewer.on('annotationsLoaded', async () => {
      await PDFNet.initialize();
      const doc = await docViewer.getDocument().getPDFDoc();
      // export annotations from the document
      const annots = await annotManager.exportAnnotations();
      // Run PDFNet methods with memory management
      await PDFNet.runWithCleanup(async () => {
        // lock the document before a write operation
        // runWithCleanup will auto unlock when complete
        doc.lock();
        // import annotations to PDFNet
        const fdf_doc = await PDFNet.FDFDoc.createFromXFDF(annots);
        await doc.fdfUpdate(fdf_doc);
        const page = await doc.getPage(1);
        const rect = await page.getCropBox();
        const annotation = await page.getAnnot(0);
        const te = await PDFNet.TextExtractor.create();
        te.begin(page, rect);
        const textData = await te.getTextUnderAnnot(annotation);
        console.log(textData);
      });
    })
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [Document.getPDFDoc ](https://sdk.apryse.com/api/web/Core.Document.html#getPDFDoc__anchor)[PDFNet.PDFDoc.getPage](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#getPage__anchor) [PDFNet.Page.getCropBox](https://sdk.apryse.com/api/web/Core.PDFNet.Page.html#getCropBox__anchor) [PDFNet.Page.getAnnot](https://sdk.apryse.com/api/web/Core.PDFNet.Page.html#getAnnot__anchor) [PDFNet.TextExtractor.create](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#.create__anchor) [PDFNet.TextExtractor.begin](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#begin__anchor) [PDFNet.TextExtractor.getTextUnderAnnot](https://sdk.apryse.com/api/web/Core.PDFNet.TextExtractor.html#getTextUnderAnnot__anchor)
{% endtab %}
{% endtabs %}

## About extracting text

When we use the `ElementReader` class to read elements from a PDF document, we are often faced with data that is partial. For example, let us say that we are attempting to extract a sentence that says "This is a sample sentence." from a PDF document. We could potentially end up with two elements - "T" and "his is a sample sentence.". This is possible because in a PDF document, text objects are **not** always cleanly organized into words sentences, or paragraphs. The `ElementReader` class will return `Element` objects exactly as they are defined in the PDF page content stream.

## Text runs

An element of type `e_text` directly corresponds to a `Tj` element in the PDF document. Each `e_text` element represents a **text run**, which represents a sequence of text glyphs that use the same font and graphics attributes. Say, if there is a single word, whose letters are each presented with a different font, then each letter would be a separate text run. You may also encounter text runs that contain multiple words separated by spaces. The PDF format does not guarantee that the text will be presented in reading order.

## TextExtractor class

All this just goes to say that attempting to use an `ElementReader` to extract text data from a PDF document is not guaranteed to return data in the order expected (reading order). The most straightforward approach to extract words and text from text-runs is using the `pdftron.PDF.TextExtractor` class, as shown in the `TextExtract` sample project - [TextExtract Sample](/web/get-started/samples/textextracttest.md)

TextExtractor will assemble words, lines, and paragraphs, remove duplicate strings, reconstruct text reading order, etc. Using `TextExtractor` you can also obtain bounding boxes for each word, line, or paragraph (along with style information such as font, color, etc). This information can be used to search for corresponding text elements using `ElementReader`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/extraction/text-extract.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
