How to Generate Offer Letters from a Google Sheets Hiring Tracker (2026)
Hiring trackers already hold the fields an offer letter needs: name, role, start date, compensation, manager, reply-by date. The slow part is copying those fields into a letter, one candidate at a time, and saving a PDF. You can keep the tracker as the source of truth and generate the letter from a template when a row is actually ready.
This is not legal advice, and the script does not write your terms for you. Put language your organization (and, where appropriate, a lawyer) has already approved into the Google Doc, and only merge the fields that change.
Step 1: a hiring sheet with a Ready flag
Use columns such as: Candidate, Email, Role, Team, Start date, Salary, Manager, Offer deadline, Status, plus empty Offer Doc and Offer PDF columns. Status should distinguish Draft, Ready, Sent, Accepted and Declined (or Held). The script below generates documents only for Ready rows, so a half-finished offer is not exported by mistake.
Format dates and currency in the sheet. Helper columns such as =TEXT(E2,"MMMM d, yyyy") for the start date and a similarly formatted salary keep the letter readable.
Treat the sheet as sensitive. Share it with the smallest group you can, and avoid putting extra personal data in columns you do not need to merge.
Step 2: the letter template
Write the offer in Google Docs the way you already would, and replace the variable parts with placeholders that match your headers exactly, for example {{Candidate}}, {{Role}}, {{Start date}}, {{Salary}}, {{Manager}} and {{Offer deadline}}. Keep the legal paragraphs, at-will language, contingencies and signature block as ordinary text in the Doc so they are not coming from a spreadsheet cell.
Copy the template ID (between /d/ and /edit) and the ID of a restricted Drive folder for finished offers (after /folders/). That folder's sharing settings are what control who can see generated letters.
Step 3: generate letters for Ready rows only
In the tracker, open Extensions › Apps Script, paste the script, fill in the two IDs, save, reload, and use Merge › Create offer letters for ready rows. Approve permissions the first time. Rows that already have an Offer PDF link are skipped.
/**
* Generate an offer letter Doc + PDF for rows whose Status is "Ready"
* and whose "Offer PDF" cell is empty. Ignores Draft / Held / Accepted rows.
* Menu: Merge > Create offer letters for ready rows.
*/
const TEMPLATE_ID = 'PASTE_TEMPLATE_DOC_ID';
const FOLDER_ID = 'PASTE_OUTPUT_FOLDER_ID';
function onOpen() {
SpreadsheetApp.getUi().createMenu('Merge')
.addItem('Create offer letters for ready rows', 'mergeReadyOffers')
.addToUi();
}
function mergeReadyOffers() {
const sh = SpreadsheetApp.getActiveSheet();
const data = sh.getDataRange().getDisplayValues();
const raw = sh.getDataRange().getValues();
const head = data[0];
const statusCol = head.indexOf('Status');
const pdfCol = ensureCol_(sh, head, 'Offer PDF');
const docCol = ensureCol_(sh, head, 'Offer Doc');
const folder = DriveApp.getFolderById(FOLDER_ID);
for (let r = 1; r < data.length; r++) {
if (String(raw[r][statusCol] || '').toLowerCase() !== 'ready') continue;
if (sh.getRange(r + 1, pdfCol).getValue()) continue;
const rec = {};
head.forEach((h, i) => { if (h) rec[h] = data[r][i]; });
const name = 'Offer-' + (rec['Candidate'] || rec['Role'] || ('row-' + (r + 1)));
const copy = DriveApp.getFileById(TEMPLATE_ID).makeCopy(name, folder);
const doc = DocumentApp.openById(copy.getId());
const body = doc.getBody();
Object.keys(rec).forEach((h) => {
const escaped = h.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
body.replaceText('\\{\\{' + escaped + '\\}\\}', rec[h] || '');
});
doc.saveAndClose();
const pdf = folder.createFile(copy.getAs(MimeType.PDF).setName(name + '.pdf'));
sh.getRange(r + 1, docCol).setValue(copy.getUrl());
sh.getRange(r + 1, pdfCol).setValue(pdf.getUrl());
}
}
function ensureCol_(sh, head, name) {
let i = head.indexOf(name);
if (i === -1) {
i = head.length;
sh.getRange(1, i + 1).setValue(name);
head.push(name);
}
return i + 1;
}
Caveats
- Review each letter before you send it. A merge will faithfully copy a typo in the Salary or Start date column.
- Permissions. The script can create files in the folder you chose and read the spreadsheet you run it on. Anyone who can edit the script or the trigger also has that reach.
- Execution time. A long list of Ready rows can hit the six-minute Apps Script limit; the empty Offer PDF check lets you run it again safely.
- Sending the letter is a separate step (email, e-signature, or your HR system). This guide only creates the file.
See SheetWeave
Related Google Sheets guides
- How to generate a PDF or Google Doc for each row in Google Sheets
- Best Autocrat alternatives for mail merge to PDF and Docs
- Make invoices or certificates from Google Sheets rows
- Create sales quotes or estimates from Google Sheets
- Generate receipts from Google Sheets rows
- Create purchase orders from Google Sheets
- Make packing slips from Google Sheets orders
- Generate a PDF certificate from a Google Form response
- Issue numbered training completion certificates with expiry dates
- Make a PDF progress report for each student
- Generate offer letters from a Google Sheets hiring tracker
- Email each row’s PDF as an attachment
- Automatic email reminders from a date column
- Contract renewal and expiration alerts from Google Sheets
- Track certificate of insurance (COI) expirations in Google Sheets
- Track employee license and certification expirations
- Track equipment and vehicle maintenance with reminders
- Track warranty expiration dates with reminders
- Birthday and work anniversary reminders from Google Sheets
- Rent due and lease renewal reminders from Google Sheets
- Send invoice payment reminders from Google Sheets
- Highlight overdue tasks and send email reminders
- Follow-up reminders for leads, clients and candidates
- Membership renewal reminders for clubs and associations
- SheetWeave vs Autocrat
- SheetWeave vs Document Studio
- SheetWeave vs RowDocs
Instructions refer to Google Sheets, Google Docs, Google Forms, Google Drive and Apps Script as they worked on November 10, 2026. Not affiliated with Google or any other vendor named here. Google Sheets, Google Docs, Google Forms, Google Slides and Google Drive are trademarks of Google LLC. Features change, so verify in your own account. Questions or corrections: hello@loomwise.app.