> 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/salesforce/search/searching-documents-salesforce.md).

# Searching documents in Salesforce

Learn how to search and navigate documents effectively using WebViewer in Salesforce. Find tips on using config.js, searching for text, and handling messages in your LWC component. Explore the Salesfo

## Getting Started

We recommend the [Overview](/salesforce/get-started/readme.md) page to learn how to correctly use a `config.js` before getting started.

## Open a document

To search a document, you need to open it in WebViewer. See more in docs on [opening documents](/salesforce/open-save/opening-documents-salesforce.md).

## Searching an open document

Once your document is loaded in WebViewer it is ready for search. From your LWC component where the WebViewer iFrame is mounted (in our sample, it is `pdftronWvInstance`), you need to post a message to your `iframeWindow` like so:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
this.iframeWindow.postMessage({ type: 'SEARCH_DOCUMENT', searchTerm }, '*');
```

{% endcode %}
{% endtab %}
{% endtabs %}

`searchTerm` is required and represents a string or regular expression you would like to search the document for. `type` is optional, but recommended for handling multiple messages in a readable fashion.

Note: You must set `regex: true` in your `options` parameter to enable searching for a regex string.

## Processing search in your config.js

Since WebViewer is hosted in an iFrame, we need to use our `config.js` file to access our WebViewer instance. In a Salesforce deployment, the equivalent of `instance` is [`readerControl`](/web/advanced/config-files.md#accessing-webviewer-instance-from-the-config-file).

In your `config.js` file, you can you listen for messages posted to the iFrame by registering an event listener using `window.addEventListener("message", receiveMessage, false);`. In this case, `receiveMessage` is a function that handles these posted messages. You can review the snippet below for an example of how to deal with posted messages.

### Searching the document for a single instance of search term

This snippet uses the [`searchText()`](https://sdk.apryse.com/api/web/UI.html#.searchText) function. It searches the document one by one for the text matching searchValue. To go to the next result this function must be called again. Once document end is reach it will jump back to the first found result. To search and highlight every occurrence of the search term, review the next section.

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
function receiveMessage(event) {
  const annotManager = docViewer.getAnnotationManager();
  
  //you can register a searchListener to use a callback for result handling
  const searchListener = (searchTerm, options, results) => {
    // add redaction annotation for each search result
    const newAnnotations = results.map(result => {
      const annotation = new Annotations.RedactionAnnotation();
      annotation.PageNumber = result.pageNum;
      annotation.Quads = result.quads.map(quad => quad.getPoints());
      annotation.StrokeColor = new Annotations.Color(136, 39, 31);
      return annotation;
    });

    annotManager.addAnnotations(newAnnotations);
    annotManager.drawAnnotationsFromList(newAnnotations);
  };

  if (event.isTrusted && typeof event.data === 'object') {
    switch (event.data.type) {
      case 'SEARCH_DOCUMENT':
        if (event.data.term) {
          const searchOptions = {
            caseSensitive: true,  // match case
            wholeWord: true,      // match whole words only
            wildcard: false,      // allow using '*' as a wildcard value
            regex: false,         // string is treated as a regular expression
            searchUp: false,      // search from the end of the document upwards
            ambientString: true,  // return ambient string as part of the result
          };
          instance.addSearchListener(searchListener);
          instance.searchText(event.data.term, searchOptions); //search full text for single occurence of searchTerm
        }
        break;
      default:
        break;
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
function receiveMessage(event) {
  const annotManager = docViewer.getAnnotationManager();
  
  //you can register a searchListener to use a callback for result handling
  const searchListener = (searchTerm, options, results) => {
    // add redaction annotation for each search result
    const newAnnotations = results.map(result => {
      const annotation = new Annotations.RedactionAnnotation();
      annotation.PageNumber = result.pageNum;
      annotation.Quads = result.quads.map(quad => quad.getPoints());
      annotation.StrokeColor = new Annotations.Color(136, 39, 31);
      return annotation;
    });

    annotManager.addAnnotations(newAnnotations);
    annotManager.drawAnnotationsFromList(newAnnotations);
  };

  if (event.isTrusted && typeof event.data === 'object') {
    switch (event.data.type) {
      case 'SEARCH_DOCUMENT':
        if (event.data.term) {
          const searchOptions = {
            caseSensitive: true,  // match case
            wholeWord: true,      // match whole words only
            wildcard: false,      // allow using '*' as a wildcard value
            regex: false,         // string is treated as a regular expression
            searchUp: false,      // search from the end of the document upwards
            ambientString: true,  // return ambient string as part of the result
          };
          readerControl.addSearchListener(searchListener);
          readerControl.searchText(event.data.term, searchOptions); //search full text for single occurence of searchTerm
        }
        break;
      default:
        break;
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Searching the document for all instances of search term (multiple highlights)

The following snippet uses the [`searchTextFull()`](https://sdk.apryse.com/api/web/UI.html#.searchTextFull) function:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
function receiveMessage(event) {
  const annotManager = docViewer.getAnnotationManager();
  
  //you can register a searchListener to use a callback for result handling
  const searchListener = (searchTerm, options, results) => {
    // add redaction annotation for each search result
    const newAnnotations = results.map(result => {
      const annotation = new Annotations.RedactionAnnotation();
      annotation.PageNumber = result.pageNum;
      annotation.Quads = result.quads.map(quad => quad.getPoints());
      annotation.StrokeColor = new Annotations.Color(136, 39, 31);
      return annotation;
    });

    annotManager.addAnnotations(newAnnotations);
    annotManager.drawAnnotationsFromList(newAnnotations);
  };

  if (event.isTrusted && typeof event.data === 'object') {
    switch (event.data.type) {
      case 'SEARCH_DOCUMENT':
        if (event.data.term) {
          const searchOptions = {
            caseSensitive: true,  // match case
            wholeWord: true,      // match whole words only
            wildcard: false,      // allow using '*' as a wildcard value
            regex: false,         // string is treated as a regular expression
            searchUp: false,      // search from the end of the document upwards
            ambientString: true,  // return ambient string as part of the result
          };
          instance.addSearchListener(searchListener);
          instance.searchTextFull(event.data.term, searchOptions); //search full text for every occurence of searchTerm
        }
        break;
      default:
        break;
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
function receiveMessage(event) {
  const annotManager = docViewer.getAnnotationManager();
  
  //you can register a searchListener to use a callback for result handling
  const searchListener = (searchTerm, options, results) => {
    // add redaction annotation for each search result
    const newAnnotations = results.map(result => {
      const annotation = new Annotations.RedactionAnnotation();
      annotation.PageNumber = result.pageNum;
      annotation.Quads = result.quads.map(quad => quad.getPoints());
      annotation.StrokeColor = new Annotations.Color(136, 39, 31);
      return annotation;
    });

    annotManager.addAnnotations(newAnnotations);
    annotManager.drawAnnotationsFromList(newAnnotations);
  };

  if (event.isTrusted && typeof event.data === 'object') {
    switch (event.data.type) {
      case 'SEARCH_DOCUMENT':
        if (event.data.term) {
          const searchOptions = {
            caseSensitive: true,  // match case
            wholeWord: true,      // match whole words only
            wildcard: false,      // allow using '*' as a wildcard value
            regex: false,         // string is treated as a regular expression
            searchUp: false,      // search from the end of the document upwards
            ambientString: true,  // return ambient string as part of the result
          };
          readerControl.addSearchListener(searchListener);
          readerControl.searchTextFull(event.data.term, searchOptions); //search full text for every occurence of searchTerm
        }
        break;
      default:
        break;
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Sample project

You can review the Salesforce PDF App to showcase an end-to-end example of search, and how you can leverage it for redaction and content replacing on our [Github repository](https://github.com/ApryseSDK/salesforce-pdf-app/).

## Live demo

Check out this live [PDF Search Demo](https://showcase.apryse.com/pdf-search) (hosted outside of Salesforce).


---

# 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/salesforce/search/searching-documents-salesforce.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.
