Scroll to Top
💻
Free Code
Users get ready-to-use code at no cost.
📋
Easy Copy
Copy and use the code instantly.
Quick Learning
Understand concepts fast and clearly.
📝
Step-by-Step
Follow simple instructions to implement.
📅 September 26, 2025 💻 Tutorial ⭐ Beginner Friendly

Google Apps Script: Build Dynamic Web Forms and Save Data to Google Sheets

Author Avatar

Ashish Dwivedi

Editorial Team • Tech Writer

About This Tutorial

  • Open a new Google Sheet. Go to the Extensions menu and click on Apps Script.
  • Paste the code we provided, but replace the spreadsheet ID with your own spreadsheet ID.
  • Deploy the Apps Script code and obtain the URL of the web form

Apps Scripts Blog

Read Blog

📂 javascript
⚡ script1.js
📂 html
🌐 template1.html
⚡ script1.js
🌐 template1.html
// ==== Code.gs ====

// Your Spreadsheet ID (optional if needed for external usage)
const SPREADSHEET_ID = '16vxtYxLb9052SGX6ZB5ySqh89MuheyGD-wWsS5l0r14';

/**
 * Add custom menu when spreadsheet is opened
 */
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('Form Manager')
    .addItem('Open Form Manager Sidebar', 'openSidebar')
    .addToUi();
}

/**
 * Handle POST requests (Form submissions)
 */
function doPost(e) {
  try {
    setupCORS();

    if (!e || !e.postData || !e.postData.contents) {
      return createResponse({ success: false, error: 'No data received' }, 400);
    }

    let data;
    try {
      data = JSON.parse(e.postData.contents);
    } catch (parseError) {
      data = parseFormData(e.postData.contents);
    }

    const validation = validateFormData(data);
    if (!validation.isValid) {
      return createResponse({ success: false, error: validation.message }, 400);
    }

    const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    prepareHeaders(sheet);
    addFormDataToSheet(sheet, data);

    return createResponse({
      success: true,
      message: 'Form submitted successfully!',
      timestamp: new Date().toISOString(),
      submittedData: data
    });
  } catch (error) {
    console.error('Error in doPost:', error);
    return createResponse({ success: false, error: 'Server error: ' + error.toString() }, 500);
  }
}

/**
 * Handle GET requests (basic info endpoint)
 */
function doGet(e) {
  setupCORS();
  return createResponse({
    success: true,
    message: 'Form submission endpoint is active',
    endpoints: {
      POST: 'Submit form data',
      GET: 'Get endpoint information'
    },
    instructions: 'Send POST request with form data to submit to Google Sheets'
  });
}

/**
 * Setup CORS headers
 */
function setupCORS() {
  const headers = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type'
  };
  Object.keys(headers).forEach(key => {
    ContentService.createTextOutput('').setMimeType(ContentService.MimeType.JSON)
  });
}

/**
 * Utility: Create JSON response
 */
function createResponse(data, statusCode = 200) {
  return ContentService.createTextOutput(JSON.stringify(data))
    .setMimeType(ContentService.MimeType.JSON)
    .setStatusCode(statusCode);
}

/**
 * Parse URL-encoded form data if JSON fails
 */
function parseFormData(contents) {
  const data = {};
  contents.split('&').forEach(pair => {
    const [key, value] = pair.split('=');
    if (key && value) data[decodeURIComponent(key)] = decodeURIComponent(value);
  });
  return data;
}

/**
 * Validate required form fields
 */
function validateFormData(data) {
  const requiredFields = ['fullName', 'dob'];
  for (const field of requiredFields) {
    if (!data[field] || data[field].trim() === '') {
      return { isValid: false, message: `Required field '${field}' is missing` };
    }
  }
  return { isValid: true };
}

/**
 * Add headers to a new sheet
 */
function prepareHeaders(sheet) {
  if (sheet.getLastRow() === 0) {
    const headers = [
      'Timestamp', 'Full Name', 'Date of Birth', 'Name Signature',
      'Work Party', 'Degree', 'Campus University', 'Graduate Year',
      'Majesty 1', 'Majesty 2', 'User Contact'
    ];
    sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
    sheet.getRange(1, 1, 1, headers.length)
      .setBackground('#4F200D')
      .setFontColor('#FFFFFF')
      .setFontWeight('bold');
  }
}

/**
 * Add a form submission row
 */
function addFormDataToSheet(sheet, data) {
  const rowData = [
    new Date(),
    data.fullName || '',
    data.dob || '',
    data.nameSignature || '',
    data.workParty || '',
    data.degree || '',
    data.campusUniversity || '',
    data.gradYear || '',
    data.majesty1 || '',
    data.majesty2 || '',
    data.contact || ''
  ];
  sheet.appendRow(rowData);
  sheet.autoResizeColumns(1, rowData.length);
}

/**
 * Create a new sheet
 */
function createNewSheet(sheetName) {
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = spreadsheet.getSheetByName(sheetName);
  if (!sheet) {
    sheet = spreadsheet.insertSheet(sheetName);
  }
  prepareHeaders(sheet);
  return { success: true, message: `Sheet "${sheetName}" created successfully`, sheetName: sheet.getName() };
}

/**
 * Open sidebar with HTML file
 */
function openSidebar() {
  const html = HtmlService.createHtmlOutputFromFile('Sidebar')
    .setTitle('Form Manager')
    .setWidth(300);
  SpreadsheetApp.getUi().showSidebar(html);
}

/**
 * Get all sheet names
 */
function getSheetNames() {
  return SpreadsheetApp.getActiveSpreadsheet().getSheets().map(s => s.getName());
}

/**
 * Set active sheet by name
 */
function setActiveSheet(sheetName) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  if (sheet) {
    sheet.activate();
    return { success: true, message: `Active sheet set to: ${sheetName}` };
  } else {
    return { success: false, error: `Sheet "${sheetName}" not found` };
  }
}

/**
 * Get the Web App URL
 */
function getWebAppUrl() {
  return ScriptApp.getService().getUrl();
}

/**
 * Test submission (adds dummy row)
 */
function testFormSubmission() {
  const testData = {
    fullName: 'Test User',
    dob: '01/01/1990',
    nameSignature: 'Test Signature',
    workParty: 'party1',
    degree: 'Bachelor of Science',
    campusUniversity: 'Test University',
    gradYear: '2000',
    majesty1: 'Test Majesty 1',
    majesty2: 'Test Majesty 2',
    contact: 'test@example.com'
  };
  return addFormDataToSheet(SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(), testData);
}
<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <style>
    /* ====== Global Styles ====== */
    body {
      font-family: Arial, sans-serif;
      margin: 20px;
      color: #333;
      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
    }

    .container {
      max-width: 100%;
    }

    h1 {
      font-size: 18px;
      margin-bottom: 20px;
      color: #4F200D;
      text-align: center;
      padding-bottom: 10px;
      border-bottom: 2px solid #FF9A00;
    }

    .section {
      margin-bottom: 20px;
      padding: 15px;
      background: rgba(255, 255, 255, 0.9);
      border-radius: 10px;
      border-left: 4px solid #FF9A00;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    }

    label {
      display: block;
      margin-bottom: 5px;
      font-weight: bold;
      font-size: 14px;
      color: #4F200D;
    }

    select, input {
      width: 100%;
      padding: 10px;
      border: 2px solid #e0e0e0;
      border-radius: 5px;
      margin-bottom: 10px;
      box-sizing: border-box;
      font-size: 14px;
      transition: border-color 0.3s;
    }

    select:focus, input:focus {
      border-color: #FF9A00;
      outline: none;
      box-shadow: 0 0 0 2px rgba(255, 154, 0, 0.2);
    }

    button {
      background: linear-gradient(to right, #FF9A00, #FFD93D);
      color: #4F200D;
      border: none;
      padding: 12px 15px;
      border-radius: 5px;
      cursor: pointer;
      font-size: 14px;
      font-weight: bold;
      width: 100%;
      margin-top: 10px;
      transition: all 0.3s;
      box-shadow: 0 2px 5px rgba(255, 154, 0, 0.3);
    }

    button:hover {
      transform: translateY(-2px);
      box-shadow: 0 4px 8px rgba(255, 154, 0, 0.4);
    }

    button:active {
      transform: translateY(0);
    }

    .status {
      margin-top: 15px;
      padding: 10px;
      border-radius: 5px;
      font-size: 12px;
      display: none;
      text-align: center;
    }

    .success {
      background: #d4edda;
      color: #155724;
      border: 1px solid #c3e6cb;
    }

    .error {
      background: #f8d7da;
      color: #721c24;
      border: 1px solid #f5c6cb;
    }

    .info {
      background: #cce7ff;
      color: #004085;
      border: 1px solid #b3d7ff;
      display: block;
    }

    .url-box {
      background: #f8f9fa;
      padding: 10px;
      border-radius: 5px;
      border: 1px solid #dee2e6;
      word-break: break-all;
      font-size: 11px;
      margin-bottom: 10px;
    }

    .copy-btn {
      background: #6c757d;
      margin-top: 5px;
    }

    .copy-btn:hover {
      background: #545b62;
    }

    .info-text {
      font-size: 12px;
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>Form Manager</h1>

    <div class="section">
      <h3>Current Sheets</h3>
      <label for="sheetSelect">Select Active Sheet:</label>
      <select id="sheetSelect">
        <option value="">Loading sheets...</option>
      </select>
      <button onclick="setActiveSheet()">Set as Active Sheet</button>
    </div>

    <div class="section">
      <h3>Create New Sheet</h3>
      <label for="newSheetName">New Sheet Name:</label>
      <input type="text" id="newSheetName" placeholder="e.g., Contact Form, Signups">
      <button onclick="createNewSheet()">Create New Sheet</button>
    </div>

    <div class="section">
      <h3>Webhook URL for Your Form</h3>
      <p class="info-text">Copy this URL and update the WEB_APP_URL in your signup form:</p>
      <div class="url-box info" id="webhookUrl">Loading webhook URL...</div>
      <button onclick="copyWebhookUrl()" class="copy-btn">Copy Webhook URL</button>
    </div>

    <div class="section">
      <h3>Test Submission</h3>
      <button onclick="testSubmission()">Test Form Submission</button>
    </div>

    <div id="statusMessage" class="status"></div>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      loadSheets();
      loadWebhookUrl();
    });

    function loadSheets() {
      google.script.run
        .withSuccessHandler(function(sheets) {
          const select = document.getElementById('sheetSelect');
          select.innerHTML = '';
          sheets.forEach(sheet => {
            const option = document.createElement('option');
            option.value = sheet;
            option.textContent = sheet;
            select.appendChild(option);
          });
        })
        .withFailureHandler(showError)
        .getSheetNames();
    }

    function loadWebhookUrl() {
      google.script.run
        .withSuccessHandler(function(url) {
          const webhookDiv = document.getElementById('webhookUrl');
          webhookDiv.textContent = url;
        })
        .withFailureHandler(function() {
          document.getElementById('webhookUrl').textContent = 'Error loading URL. Please deploy the script first.';
        })
        .getWebAppUrl();
    }

    function setActiveSheet() {
      const sheetSelect = document.getElementById('sheetSelect');
      const sheetName = sheetSelect.value;
      if (!sheetName) { showError('Please select a sheet first'); return; }
      google.script.run
        .withSuccessHandler(result => showMessage(result.message, 'success'))
        .withFailureHandler(showError)
        .setActiveSheet(sheetName);
    }

    function createNewSheet() {
      const sheetName = document.getElementById('newSheetName').value;
      if (!sheetName) { showError('Please enter a sheet name'); return; }
      google.script.run
        .withSuccessHandler(result => {
          showMessage(result.message, 'success');
          document.getElementById('newSheetName').value = '';
          loadSheets();
        })
        .withFailureHandler(showError)
        .createNewSheet(sheetName);
    }

    function copyWebhookUrl() {
      const webhookUrl = document.getElementById('webhookUrl').textContent;
      navigator.clipboard.writeText(webhookUrl)
        .then(() => showMessage('Webhook URL copied to clipboard!', 'success'))
        .catch(() => showError('Failed to copy URL. Please copy manually.'));
    }

    function testSubmission() {
      google.script.run
        .withSuccessHandler(() => showMessage('Test submission completed successfully!', 'success'))
        .withFailureHandler(showError)
        .testFormSubmission();
    }

    function showMessage(message, type) {
      const statusDiv = document.getElementById('statusMessage');
      statusDiv.textContent = message;
      statusDiv.className = 'status ' + type;
      statusDiv.style.display = 'block';
      setTimeout(() => statusDiv.style.display = 'none', 5000);
    }

    function showError(error) {
      showMessage(error, 'error');
    }
  </script>
</body>
</html>