Apps Script example · 6 min read

Copy a Template Doc and Fill In the Details: Copy-Paste Apps Script Pattern

Working copy a template doc and fill in the details example in Apps Script—copy-paste code, common mistakes, and when to get it built professionally.

DocsDriveTemplates

Keeping one master contract or proposal template and duplicating it for every new client beats copy-pasting text into a fresh document each time and hoping nothing gets left out.

This script uses DriveApp.getFileById on a template document, calls makeCopy to duplicate it into a target folder, then opens the copy with DocumentApp to fill in a handful of placeholder values.

Separating the copy step from the edit step matters because makeCopy operates on the file at the Drive level, while the placeholder replacement needs the richer DocumentApp API to touch the document body.

The result is a new, uniquely named document for each client that already contains their name, date, and any other detail you choose to inject at copy time.

Need this built? Hire a Google Apps Script developer →

Sheet / project setup

ResourceName / valuePurpose
Template DocTEMPLATE_DOC_IDSource makeCopy target
Dest folderDEST_FOLDER_IDWhere copies land
Placeholders{{ClientName}}, {{Date}}Tokens replaced after copy

What It Does

The script duplicates a template document into a destination folder using makeCopy, renames the copy to include the client's name, then opens the new file and replaces placeholder tokens with real values.

Because makeCopy returns a DriveApp File object rather than a Doc, the script has to reopen the new file's ID with DocumentApp.openById before it can touch the document's body text.

Prerequisites

Build your template document with clearly bracketed placeholders like {{ClientName}} and {{StartDate}} so the replacement step can target exact strings without accidentally matching unrelated text.

Create or choose a destination folder in Drive for finished copies and note its ID, since makeCopy accepts a folder as an optional second argument.

Walkthrough

Set TEMPLATE_ID to your template document's ID and DEST_FOLDER_ID to the destination folder, then call createClientDoc with an object containing the client's name and start date.

Run createClientDoc({ ClientName: 'Acme Co', StartDate: '2026-08-01' }) from the editor and confirm a new document appears in the destination folder with both placeholders replaced correctly.

Open the generated document and manually verify formatting around the replaced text still looks correct, since replaceText can occasionally affect surrounding character styles in edge cases.

Edge Cases

If a placeholder appears in the template but is missing from the data object passed to the function, that placeholder is left in the document unchanged rather than being replaced with the word undefined.

Placeholders that appear inside a table cell or a header are still replaced correctly, since body.replaceText searches the entire document body regardless of which structural element contains the text.

Testing

Run the function twice with two different client names and confirm two separate documents exist in the destination folder, each with the correct name substituted and no cross-contamination between the two.

Deliberately omit one placeholder value and confirm the unmatched token remains visibly in the output document so a missed field is easy to spot before sending it to a client.

Hardening

Validate that every required key exists in the incoming data object before calling makeCopy, so the script fails fast with a clear error instead of producing a half-filled document.

Log the new document's ID and URL to a tracking sheet immediately after creation so there is a record connecting each generated document back to the client it was created for.

Variations

Chain this script with the mail-merge tutorial so each generated document is automatically emailed to the corresponding client as soon as it is created.

Convert the finished document to PDF with getAs('application/pdf') before handing it off if the destination system expects a static file rather than an editable Google Doc.

createClientDoc.gs

createClientDoc duplicates a template document into a destination folder, reopens the copy, and replaces every bracketed key from the supplied data object with its value.

// Copy a template Doc and fill in client-specific placeholders
function createClientDoc(data) {
  var TEMPLATE_ID = 'REPLACE_WITH_TEMPLATE_ID';
  var DEST_FOLDER_ID = 'REPLACE_WITH_DEST_FOLDER_ID';

  var template = DriveApp.getFileById(TEMPLATE_ID);
  var destFolder = DriveApp.getFolderById(DEST_FOLDER_ID);
  var copy = template.makeCopy(data.ClientName + ' - Agreement', destFolder);

  var doc = DocumentApp.openById(copy.getId());
  var body = doc.getBody();

  for (var key in data) {
    var token = '{{' + key + '}}';
    body.replaceText(token, data[key]);
  }

  doc.saveAndClose();
  Logger.log('Created document: ' + copy.getUrl());
  return copy.getId();
}
  1. Line 8: makeCopy takes the new file's name and destination folder together, so the duplicate lands in the right place with a useful name in one call.
  2. Line 10: openById reopens the freshly created copy as a Doc, since makeCopy itself only returns a generic Drive File object.
  3. Line 13: Looping over the keys already present in the data object means only placeholders you actually supplied a value for get touched.
  4. Line 15: replaceText runs once per key, substituting every occurrence of that bracketed token throughout the whole document body.
  5. Line 18: saveAndClose flushes the pending edits, which matters because DocumentApp changes are not guaranteed to be visible elsewhere until the document is closed.

Deploy this example

  1. 01

    Open Apps Script

    In the bound spreadsheet: Extensions → Apps Script. For standalone projects, create one at script.google.com and link your Sheet by ID.

  2. 02

    Paste and save

    Add a .gs file, paste the code below, rename constants at the top (sheet names, column letters, API property keys), then save.

  3. 03

    Authorize once

    Run the main function from the editor. Accept OAuth scopes when prompted — triggers cannot run until authorization succeeds once.

  4. 04

    Add the trigger

    Triggers → Add trigger → choose the handler function and event (time-driven, on edit, or on form submit). Delete test triggers before production.

Before you run: copy template doc

  • 1Template document built with clearly bracketed placeholders
  • 2Destination folder created for finished copies
  • 3TEMPLATE_ID and DEST_FOLDER_ID filled in at the top of the script
  • 4Function run with sample client data
  • 5Generated document reviewed for correct placeholder replacement
  • 6Second client tested to confirm no cross-contamination between documents

Frequently asked questions

It is left in the document exactly as written rather than being replaced with the word undefined, since the loop only iterates over keys actually present in the object.

Yes, the create-slides-from-template tutorial follows the identical makeCopy pattern, just swapping DocumentApp for SlidesApp and replaceText for replaceAllText.

Generally yes, replaceText substitutes the matched string while leaving surrounding character formatting intact.

Yes, call getAs('application/pdf') on the finished document right after saveAndClose and save that blob instead of, or alongside, the editable Doc.

DriveApp.getFileById throws immediately with a clear error, which is a fast way to confirm you copied the correct ID from the template's URL.

Yes, body.replaceText searches the whole document body including table cells and headers.

Related examples

Want this wired into your real workflow?

I adapt these patterns to your Sheet structure, APIs, and triggers — deployed in your Google account. Fixed-scope quotes from $500 · free 30-min consult · quote within 24 hours.