A common pattern in Apps Script is to maintain a Google Doc template with named placeholders (e.g. {{CustomerName}}), then copy it and replace those placeholders with real data. This is perfect for generating contracts, proposals, or onboarding documents from a spreadsheet.
Setting Up a Template
Create a Google Doc with placeholders like:
Dear {{CustomerName}},
Thank you for choosing the {{Product}} at ${{Amount}}/month.
Your account manager is {{SalesRep}} and your region is {{Region}}.
Contract Date: {{Date}}
Note the Template Doc ID from its URL — you'll use it in the script.
Generating a Doc for One Customer
functioncreateContractForCustomer(){var templateId ="YOUR_TEMPLATE_DOC_ID";var destinationFolder =DriveApp.getFolderById("YOUR_CONTRACTS_FOLDER_ID");// Customer datavar customerName ="Sarah Johnson";var product ="Pro Plan";var amount ="299";var salesRep ="Alex Martinez";var region ="North";var date ="2024-03-15";// Copy the templatevar templateFile =DriveApp.getFileById(templateId);var newDoc = templateFile.makeCopy(customerName +" - Contract", destinationFolder);// Open and replace placeholdersvar doc =DocumentApp.openById(newDoc.getId());var body = doc.getBody(); body.replaceText("{{CustomerName}}", customerName); body.replaceText("{{Product}}", product); body.replaceText("{{Amount}}", amount); body.replaceText("{{SalesRep}}", salesRep); body.replaceText("{{Region}}", region); body.replaceText("{{Date}}", date); doc.saveAndClose();Logger.log("Contract created: "+ newDoc.getUrl());}
Bulk Contract Generation from a Sheet
This example loops over every row in the Sales Tracker sheet and generates a contract for each closed deal:
With the sample data, contracts are generated for Sarah Johnson (Pro Plan, North) and Lisa Park (Starter Plan, South). Mark Chen is skipped because his status is In Progress.
Writing the Document URL Back to the Sheet
After generating each contract, you can write the URL back to the sheet for easy access:
// Inside the forEach loop, after doc.saveAndClose():var urlColumn =9;// Column Ivar rowIndex = data.indexOf(row)+2;// +2 accounts for header and 0-indexsheet.getRange(rowIndex, urlColumn).setValue(newDoc.getUrl());