Overview
This practical guide shows how to convert paper intake forms into Google Forms using a structured definition (JSON/JS object) and Google Apps Script (GAS). The script below is ready to paste into the GAS editor and run.
Key points
- Use a schema (DSL) → GAS → FormApp to auto-generate forms
- Create choices with the item object's
createChoice()(there is noFormApp.createChoice()) - Diff/updating existing forms requires extra logic; regenerating is the simplest approach
Privacy / anonymization
The examples are generic and avoid any clinic or personal identifiers.
Schema example (JS object)
Copy and edit this FORM_SCHEMA to match your paper form structure.
const FORM_SCHEMA = {
title: "Intake Form (Sample)",
description: "Sample schema to convert paper intake to Google Form",
sections: [
{
title: "Basic Information",
items: [
{ type: "text", title: "Furigana" },
{ type: "text", title: "Full name", required: true },
{ type: "multipleChoice", title: "Gender", choices: ["Male", "Female"] },
{ type: "date", title: "Date of birth" },
{ type: "text", title: "Address" },
{ type: "text", title: "Mobile number" },
{ type: "text", title: "Household composition", help: "e.g. grandmother, mother, father, younger sibling (6)" }
]
},
{
title: "Visit Details",
items: [
{ type: "checkbox", title: "Reason for visit", choices: ["Checkup","Fluoride","Cavity prevention","Cleaning","Worried about alignment","Cavity","Injury","Other"] },
{ type: "text", title: "When did you last visit a dental clinic?" },
{ type: "text", title: "Clinic name" },
{ type: "multipleChoice", title: "Is this your first visit?", choices: ["First time","Unsure"] },
{ type: "multipleChoice", title: "Are you in pain now?", choices: ["No","Yes"] },
{ type: "text", title: "Since when are you in pain?" }
]
},
{
title: "Medical History / Medication / Allergies",
items: [
{ type: "multipleChoice", title: "Are you currently under treatment?", choices: ["No","Yes"] },
{ type: "text", title: "Diagnosis / medication names" },
{ type: "multipleChoice", title: "Do you have allergies?", choices: ["No","Yes"] },
{ type: "text", title: "Allergy details" },
{ type: "multipleChoice", title: "May we use fluoride for prevention?", choices: ["Yes","No"] }
]
},
{
title: "Visit Trigger & Preferences",
items: [
{ type: "checkbox", title: "How did you find us? (multiple)", choices: ["Local","Referral","Saw sign","Instagram","Google search","Other"] },
{ type: "text", title: "Search keywords (optional)" },
{ type: "text", title: "Requests or painful experiences at previous clinics (optional)" },
{ type: "multipleChoice", title: "Can you visit outside busy times (after 16:00 or Sat)?", choices: ["Yes","No"] },
{ type: "text", title: "Preferred days/times", help: "e.g. Tuesday" }
]
},
{
title: "Treatment Interests & Consent",
items: [
{ type: "checkbox", title: "Interested treatments (multiple)", choices: ["Orthodontics","Preventive dentistry"] },
{ type: "multipleChoice", title: "Do you agree to the cancellation policy?", choices: ["Yes","No"], required: true }
]
},
{
title: "Guardian Confirmation (if applicable)",
items: [
{ type: "text", title: "When did you last visit a dental clinic?" }
]
}
]
};
GAS script (paste and run)
function createFormFromSchema(schema) {
const form = FormApp.create(schema.title);
if (schema.description) form.setDescription(schema.description);
schema.sections.forEach(section => {
form.addSectionHeaderItem().setTitle(section.title);
section.items.forEach(item => {
addItem(form, item);
});
});
Logger.log('Edit URL: ' + form.getEditUrl());
Logger.log('Response URL: ' + form.getPublishedUrl());
}
function addItem(form, item) {
let q;
switch (item.type) {
case 'text':
q = form.addTextItem();
break;
case 'multipleChoice':
q = form.addMultipleChoiceItem();
q.setChoices(item.choices.map(c => q.createChoice(c)));
break;
case 'checkbox':
q = form.addCheckboxItem();
q.setChoices(item.choices.map(c => q.createChoice(c)));
break;
case 'date':
q = form.addDateItem();
break;
default:
throw new Error('Unknown item type: ' + item.type);
}
q.setTitle(item.title);
if (item.help) q.setHelpText(item.help);
if (item.required) q.setRequired(true);
if (item.other) {
try { q.setHasOtherOption(true); } catch (e) {}
}
}
function run() {
createFormFromSchema(FORM_SCHEMA);
}
// Paste the FORM_SCHEMA above in the same script file.
Practical notes
- For production: store
FORM_SCHEMAin a Spreadsheet or JSON file so non-developers can edit it. - To avoid breaking live forms, implement a safe update path: match question titles and update choices instead of recreating the form.
- OCR → schema pipeline makes this approach powerful for paper-to-digital automation.
Next steps (recommended)
- Build OCR →
FORM_SCHEMAconverter - Add Spreadsheet-based DSL editor for non-technical staff
- Implement a diff/update mechanism for existing forms
That's it — ready to paste and run. If you want, I can post these two drafts to WordPress on 2025-02-11 morning for you.