
Auto-generate RAMS PDFs from a simple Google Form: a 60‑minute setup for small contractors
Auto-generate RAMS PDFs from a simple Google Form: a 60‑minute setup for small contractors
Category: How-to Guides Niche: RAMS automation, Google Forms, Google Docs, Apps Script

Site manager fills a Google Form while a RAMS PDF appears in Google Drive on a laptop
Contents
- Quick answer
- What you’ll set up
- Before you start: UK safety note
- Step-by-step: build the RAMS generator
- Add approvals and version control
- Make it easy on site: QR codes and WhatsApp
- Troubleshooting
- FAQ
Quick answer
You’ll create a short Google Form for each job, send responses into a Google Sheet, use a Google Doc as the RAMS template with {{placeholders}}, and an Apps Script will auto‑create a filled PDF in the right Drive folder whenever the form is submitted. It cuts paperwork time, keeps a consistent layout, and gives you a PDF you can email to clients or attach to work orders.
What you’ll set up
- A Google Doc RAMS template that uses placeholders like {{Company name}}, {{Job address}}, {{Supervisor}}, {{Sign-off name}}.
- A Google Form (mobile friendly) to capture task, hazards, controls, PPE, plant, COSHH references and sign‑off details.
- A Google Sheet to store the responses.
- An Apps Script that copies the template, replaces placeholders and saves a PDF into a “Job RAMS” Drive folder per job.

Flowchart: Form to Sheet to Doc template to PDF to email
Before you start: UK safety note
HSE requires you to assess risk; if you employ 5 or more people you must record significant findings. Method statements are not generally a legal requirement, but HSE recognises them as good practice for communicating the safe system of work and they are required in writing for demolition/dismantling. Useful pages: HSE risk assessment template and steps and the construction admin and method statement guidance on HSE construction.
If you’re new to RAMS, read our primer: RAMS for UK construction: simple steps, free template and how to brief your team.
Step-by-step: build the RAMS generator
1) Create the RAMS Doc template
- In Google Docs, create sections you always use: Scope, Responsibilities, Hazards, Controls, PPE, Plant, Emergency, COSHH, Sign‑off.
- Insert placeholders in double curly braces, matching your Sheet headers later: {{Company name}}, {{Job address}}, {{Task}}, {{Hazards}}, {{Controls}}, {{PPE}}, {{Plant}}, {{Supervisor}}, {{Sign-off name}}, {{Date}}.
- Grab the template file ID from its URL (between /d/ and /edit).
2) Build a short Google Form
Suggested fields:
- Company name, Job address, Task summary
- Hazard checklist with “Other” free‑text
- Controls text area (method steps)
- PPE, Plant/Tools, COSHH refs or SDS links
- Supervisor name, Date, Sign‑off name and email
Keep it quick so operatives can complete on a phone. Use Response validation where helpful (e.g., email format).
3) Link the Form to a Sheet
- In the Form, go to Responses > Link to Sheets and create a new spreadsheet.
- Note the tab name (usually “Form Responses 1”).
4) Add the Apps Script to generate PDFs
Open the Sheet > Extensions > Apps Script and paste this working script. Update TEMPLATE_ID, DEST_FOLDER_ID and SHEET_NAME.
const CONFIG = {
TEMPLATE_ID: 'PUT_YOUR_DOC_TEMPLATE_ID_HERE',
DEST_FOLDER_ID: 'PUT_YOUR_DEST_FOLDER_ID_HERE',
SHEET_NAME: 'Form Responses 1',
PDF_LINK_COLUMN_NAME: 'PDF URL',
TIMEZONE: Session.getScriptTimeZone()
};
function escRe(s){return String(s).replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}
function ensureHeaderColumn_(sheet, headerName){
const headers = sheet.getRange(1,1,1,sheet.getLastColumn()).getValues()[0]||[];
let col = headers.indexOf(headerName)+1;
if(col===0){sheet.getRange(1,sheet.getLastColumn()+1).setValue(headerName);col=sheet.getLastColumn();}
return col;
}
function rowToObject_(headers,row){const o={};headers.forEach((h,i)=>o[h]=row[i]);return o;}
function generatePdfFromData_(templateId, dataObj, destFolderId, fileNameNoExt){
const destFolder = DriveApp.getFolderById(destFolderId);
const tempCopy = DriveApp.getFileById(templateId).makeCopy(fileNameNoExt+' (tmp)', destFolder);
try{
const doc = DocumentApp.openById(tempCopy.getId());
const body = doc.getBody();
Object.keys(dataObj).forEach(key=>{
const val = dataObj[key]==null?'':String(dataObj[key]);
body.replaceText('\\{\\{'+escRe(key)+'\\}\\}', val);
});
doc.saveAndClose();
const pdfBlob = tempCopy.getAs(MimeType.PDF).setName(fileNameNoExt+'.pdf');
const pdfFile = destFolder.createFile(pdfBlob);
return pdfFile;
} finally {
tempCopy.setTrashed(true);
}
}
function generateAllPdfs(){
const sheet = SpreadsheetApp.getActive().getSheetByName(CONFIG.SHEET_NAME);
if(!sheet) throw new Error('Sheet not found');
const lastRow = sheet.getLastRow(), lastCol = sheet.getLastColumn();
if(lastRow<2) return;
const headers = sheet.getRange(1,1,1,lastCol).getValues()[0];
const rows = sheet.getRange(2,1,lastRow-1,lastCol).getValues();
const pdfCol = ensureHeaderColumn_(sheet, CONFIG.PDF_LINK_COLUMN_NAME);
rows.forEach((row,i)=>{
const r = i+2; const existing = sheet.getRange(r,pdfCol).getValue(); if(existing) return;
const obj = rowToObject_(headers,row);
const stamp = Utilities.formatDate(new Date(), CONFIG.TIMEZONE, 'yyyy-MM-dd HHmm');
const base = (obj['Job address']||obj['Task']||'RAMS');
const pdf = generatePdfFromData_(CONFIG.TEMPLATE_ID,obj,CONFIG.DEST_FOLDER_ID, base+' - '+stamp);
sheet.getRange(r,pdfCol).setValue(pdf.getUrl());
});
}
function onFormSubmit(e){
const sheet = e.range.getSheet(); if(sheet.getName()!==CONFIG.SHEET_NAME) return;
const dataObj={}; Object.keys(e.namedValues).forEach(k=>{const v=e.namedValues[k];dataObj[k]=Array.isArray(v)?v[0]:v;});
const stamp = Utilities.formatDate(new Date(), CONFIG.TIMEZONE, 'yyyy-MM-dd HHmm');
const base = (dataObj['Job address']||dataObj['Task']||'RAMS');
const pdf = generatePdfFromData_(CONFIG.TEMPLATE_ID,dataObj,CONFIG.DEST_FOLDER_ID, base+' - '+stamp);
const pdfCol = ensureHeaderColumn_(sheet, CONFIG.PDF_LINK_COLUMN_NAME);
sheet.getRange(e.range.getRow(), pdfCol).setValue(pdf.getUrl());
}
- Set the trigger: Apps Script > Triggers > Add Trigger > onFormSubmit > From spreadsheet > On form submit.
- Test with a dummy submission. Check the PDF lands in your Drive folder and the URL is written back to the Sheet.
5) File naming and job folders
- Create a Drive parent folder called “Job RAMS”. For each new job, create a subfolder “Job address – RAMS”. Point DEST_FOLDER_ID to the right subfolder so each job keeps its own PDFs.
- If you use a job number, include it at the start of the PDF file name for easy sorting, e.g., 241007‑004‑RAMS‑Kitchen‑refit.pdf.
6) Email the PDF and store approvals
Add this helper to email a copy to your supervisor or client:
function sendPdf_(to, subject, body, pdfFile){
if(!to) return; GmailApp.sendEmail(to, subject, body, {attachments:[pdfFile.getAs(MimeType.PDF)]});
}
Call it from onFormSubmit, for example using the {{Sign-off email}} field.
Add approvals and version control
- Approvals in Gmail: keep it simple. When a RAMS is generated, email the PDF to an approver and ask them to reply “Approved”. File the thread in a label like RAMS/Approved.
- Version numbering: include v1, v2 in the Doc title and a {{Version}} field in the Form.
- Change log: add a small table in your Doc template to note date, editor, and a one‑line change reason.
Make it easy on site: QR codes and WhatsApp
- Print a QR code that links to the Form so operatives can scan and complete on site. See: Toolbox talk attendance QR code.
- If you run WhatsApp Business, paste the Form link in a canned reply like “Please complete the RAMS form before starting.” Pair this with your induction messages.
Troubleshooting
- Placeholders didn’t replace: headers must exactly match the {{placeholders}} (case sensitive). Check brackets.
- Script errors: first run needs authorisation for Drive, Docs, Sheets (and Gmail if emailing). Re‑run and accept.
- Multiple lines not appearing: long text areas are fine, but keep the Doc template styles simple.
- Missing PDFs: confirm DEST_FOLDER_ID is a folder ID, not a file ID; make sure you have edit permission.
FAQ
Is this legal for UK sites?
Risk assessment is a legal duty and must be suitable and sufficient. Method statements aren’t generally required by law but are common and often requested by clients. See HSE’s guidance and risk assessment template: HSE risk assessment and [Construction admin](https://www.hse.go…