> 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/content-edit/replacing-content-salesforce.md).

# Replace Document Text in Salesforce

Learn how to use ContentReplacer in WebViewer with this comprehensive guide. Find out how to replace content on a document and initialize PDFNet for redaction. Explore code samples and a live demo for

## Getting Started

We recommend familiarizing yourself with the [Overview](/salesforce/get-started/readme.md) page to learn how to correctly use a `config.js` file. If you are using a version of WebViewer older than `8.0+`, you should also learn about [`readerControl`](/salesforce/get-started/readme.md) before getting started. Make sure you also understand [document search](/salesforce/search/searching-documents-salesforce.md).

## WebViewer configuration required for ContentReplacer

In order to use the `ContentReplacer` class, you need to enable `fullAPI`. In your Lightning Web Component where you initialize WebViewer (you can check out [`pdftronWvInstance.js`](https://github.com/ApryseSDK/salesforce-pdf-app/blob/main/force-app/main/default/lwc/pdftronWvInstance/pdftronWvInstance.js) in our sample repository), include `fullAPI: true`:

<pre class="language-js" data-line-numbers><code class="lang-js">//snipped for brevity
const viewerElement = this.template.querySelector('div');

const viewer = new PDFTron.WebViewer({
    path: libUrl,
    custom: JSON.stringify(myObj),
    config: myfilesUrl + '/config_apex.js',
    fullAPI: true // this must be set to true
    // l: '<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>_HERE',
}, viewerElement);
</code></pre>

Note: You need to use the `pdf_full.zip` file in your `/staticresources/` folder to access full API, which is required for redaction.

## Open a document

To replace content on a document, open it in WebViewer. Check out this [link](/salesforce/open-save/opening-documents-salesforce.md) to learn more.

## ContentReplacer placeholders

`ContentReplacer` is used for replacing strings that are wrapped in match strings. An example of this is `[Content to be replaced]`. This allows the user to build templates with these placeholders, which are then targeted by `ContentReplacer` and filled with data.

## Initializing PDFNet

`ContentReplacer` is a PDFNet class. Below is a code sample on how to initialize PDFNet:

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

```js
const docViewer = instance.Core.documentViewer;
const doc = docViewer.getDocument();//get current document from WV
if (!doc) {
    return;
}
const PDFdoc = await doc.getPDFDoc(); //pass WV Doc to PDFNet
await PDFNet.initialize();

PDFdoc.initSecurityHandler();
PDFdoc.lock();

console.log('PDFNet initialized and document locked');
```

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

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

```js
const docViewer = readerControl.docViewer;
const doc = readerControl.docViewer.getDocument();//get current document from WV
if (!doc) {
    return;
}
const PDFdoc = await doc.getPDFDoc(); //pass WV Doc to PDFNet
await PDFNet.initialize();

PDFdoc.initSecurityHandler();
PDFdoc.lock();

console.log('PDFNet initialized and document locked');
```

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

## Sample replaceContent() method

Place the following function into your `config.js` file:

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

```js
async function replaceContent(searchString, replacementString) {
  const docViewer = instance.Core.documentViewer;
  const doc = docViewer.getDocument();//get current document from WV
  if (!doc) {
    return;
  }
  const PDFdoc = await doc.getPDFDoc(); //pass WV Doc to PDFNet
  await PDFNet.initialize();

  PDFdoc.initSecurityHandler();
  PDFdoc.lock();

  // Run PDFNet methods with memory management
  await PDFNet.runWithCleanup(async () => {
    // lock the document before a write operation
    // runWithCleanup will auto unlock when complete
    const replacer = await PDFNet.ContentReplacer.create();
    await replacer.setMatchStrings(searchString.charAt(0), searchString.slice(-1));
    await replacer.addString(searchString.slice(1, -1), replacementString);
    for (var i = 1; i <= docViewer.getPageCount(); ++i) {
      const page = await PDFdoc.getPage(i);
      await replacer.process(page);
    }
  });

  docViewer.refreshAll();
  docViewer.updateView();
  docViewer.getDocument().refreshTextData();
}
```

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

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

```js
async function replaceContent(searchString, replacementString) {
  const docViewer = readerControl.docViewer;
  const doc = readerControl.docViewer.getDocument();//get current document from WV
  if (!doc) {
    return;
  }
  const PDFdoc = await doc.getPDFDoc(); //pass WV Doc to PDFNet
  await PDFNet.initialize();

  PDFdoc.initSecurityHandler();
  PDFdoc.lock();

  // Run PDFNet methods with memory management
  await PDFNet.runWithCleanup(async () => {
    // lock the document before a write operation
    // runWithCleanup will auto unlock when complete
    const replacer = await PDFNet.ContentReplacer.create();
    await replacer.setMatchStrings(searchString.charAt(0), searchString.slice(-1));
    await replacer.addString(searchString.slice(1, -1), replacementString);
    for (var i = 1; i <= docViewer.getPageCount(); ++i) {
      const page = await PDFdoc.getPage(i);
      await replacer.process(page);
    }
  });

  docViewer.refreshAll();
  docViewer.updateView();
  docViewer.getDocument().refreshTextData();
}
```

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

To handle posted messages to the WebViewer iFrame, use a `receiveMessage()` function like below:

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

```js
//snipped for brevity
function receiveMessage(event) {
    if (event.isTrusted && typeof event.data === 'object') {
        switch (event.data.type) {
            case 'REPLACE_CONTENT':
                const { searchString, replacementString } = event.data.payload;
                replaceContent(searchString, replacementString);
                break;
            default:
                break;
    }
  }
}
```

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

In your LWC component that hosts the WebViewer iFrame, you can communicate with the `config.js` file using `this.iframeWindow.postMessage({ type: 'REPLACE_CONTENT', payload }, '*');`.

Make sure that the payload you are publishing matches the structure of the `event.data.payload` object in your `receiveMessage()` function:

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

```js
const payload = {
    searchString: this.searchTerm,
    replacementString: this.replaceTerm
}
fireEvent(this.pageRef, 'replace', payload); //fire pub-sub event or use LMS
```

{% 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/).


---

# 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/content-edit/replacing-content-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.
