Merge text into a document

One useful application of the Google Docs API is to merge information from one or more data sources into a document.

This page outlines how you can take data from an external source and insert it into an existing template document.

A template is a special type of document containing the same fixed text for all documents created from the template, along with designated placeholders where other dynamic text can be placed. For example, a contract template might have fixed content, along with spots for the receiver's name, address, and other details. Your app can then merge customer-specific data into the template to create finished documents.

There are several reasons why this approach is useful:

  • It's easy for designers to fine-tune a document's design using the Google Docs editor. This is much easier than tuning parameters in your app to set the rendered layout.

  • Separating content from presentation is a well-known design principle with many benefits.

Conceptual diagram of a merge.

A basic recipe

Here's an example of how you can use the Docs API to merge data into a document:

  1. Create your document using placeholder content to help you with the design and format. Any text formatting you want to replace is preserved.

  2. For each element you'll be inserting, replace the placeholder content with a tag. Be sure to use strings that are unlikely to occur normally. For example, {{account-holder-name}} might be a good tag.

  3. In your code, use the Google Drive API to make a copy of the document.

  4. In your code, use the Docs API's batchUpdate() method with the document name and include a ReplaceAllTextRequest.

Document IDs reference a document and they can be derived from the URL

https://docs.google.com/document/d/documentId/edit

Example

Consider the following example, which replaces 2 fields in a template with real values to generate a finished document.

To perform this merge, you can use the code below.

Java

        String customerName = "Alice";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        String date = formatter.format(LocalDate.now());

        List<Request> requests = new ArrayList<>();
        requests.add(new Request()
                .setReplaceAllText(new ReplaceAllTextRequest()
                        .setContainsText(new SubstringMatchCriteria()
                                .setText("{{customer-name}}")
                                .setMatchCase(true))
                        .setReplaceText(customerName)));
        requests.add(new Request()
                .setReplaceAllText(new ReplaceAllTextRequest()
                        .setContainsText(new SubstringMatchCriteria()
                                .setText("{{date}}")
                                .setMatchCase(true))
                        .setReplaceText(date)));

        BatchUpdateDocumentRequest body = new BatchUpdateDocumentRequest();
        service.documents().batchUpdate(documentId, body.setRequests(requests)).execute();

Node.js

  let customerName = 'Alice';
  let date = yyyymmdd()
  let requests = [
    {
      replaceAllText: {
        containsText: {
          text: '{{customer-name}}',
          matchCase: true,
        },
        replaceText: customerName,
      },
    },
    {
      replaceAllText: {
        containsText: {
          text: '{{date}}',
          matchCase: true,
        },
        replaceText: date,
      },
    },
  ];

  google.options({auth: auth});
  google
      .discoverAPI(
          'https://docs.googleapis.com/$discovery/rest?version=v1&key={YOUR_API_KEY}')
      .then(function(docs) {
        docs.documents.batchUpdate(
            {
              documentId: '1yBx6HSnu_gbV2sk1nChJOFo_g3AizBhr-PpkyKAwcTg',
              resource: {
                requests,
              },
            },
            (err, {data}) => {
              if (err) return console.log('The API returned an error: ' + err);
              console.log(data);
            });
      });

Python

    customer_name = 'Alice'
    date = datetime.datetime.now().strftime("%y/%m/%d")

    requests = [
         {
            'replaceAllText': {
                'containsText': {
                    'text': '{{customer-name}}',
                    'matchCase':  'true'
                },
                'replaceText': customer_name,
            }}, {
            'replaceAllText': {
                'containsText': {
                    'text': '{{date}}',
                    'matchCase':  'true'
                },
                'replaceText': str(date),
            }
        }
    ]

    result = service.documents().batchUpdate(
        documentId=document_id, body={'requests': requests}).execute()

Manage templates

For template documents the application defines and owns, create the template using a dedicated account representing the application. Service accounts are a good choice and avoid complications with Google Workspace policies that restrict sharing.

When you create instances of documents from templates, always use end-user credentials. This gives users full control over the resulting document and prevents scaling issues related to per-user limits in Drive.

To create a template using a service account, perform the following steps with the application credentials:

  1. Create a document using documents.create in the Docs API.
  2. Update the permissions to allow the document recipients to read it using permissions.create in the Drive API.
  3. Update the permissions to allow template authors to write to it using permissions.create in the Drive API.
  4. Edit the template as required.

To create an instance of the document, perform the following steps with the user credentials:

  1. Create a copy of the template using files.copy in the Drive API.
  2. Replace values using documents.batchUpdate in the Docs API.