Skip to main content

How to Create a To-Do List App that Saves to Google Sheets Using JavaScript (No Backend Required)

Build a To-Do List That Saves Data in Google Sheets Using HTML, CSS, and JavaScript

Introduction

Creating a simple To-Do list is often a beginner-friendly way to practice HTML, CSS, and JavaScript. But what if we take it a step further and store the tasks online in a way that persists even after refreshing the page or switching devices? Enter Google Sheets – a free, cloud-based spreadsheet tool that can act like a database with the help of Google Apps Script.

In this tutorial, we'll build a To-Do list web app from scratch using HTML, CSS, and JavaScript, and then connect it to Google Sheets so that every task is saved, loaded, and managed from a spreadsheet.

Let’s dive in!


Why Google Sheets as a Database?

Using Google Sheets as a backend has several benefits:

  • It’s free and easy to use.

  • No need for external hosting or server setup.

  • Simple to read, write, and modify data.

  • Can be connected with Google Apps Script to expose REST APIs.

Perfect for small apps, personal projects, and quick prototyping!


Overview of What We'll Build

Our web app will allow users to:

  • Add tasks to the list

  • View all saved tasks

  • Delete individual tasks

  • Save and load all data from Google Sheets in real-time

We’ll create:

  • Google Apps Script to manage sheet data

  • A frontend UI with HTML and CSS

  • Functionality using JavaScript to talk to Google Sheets


Step 1: Set Up Your Google Sheet

  1. Go to Google Sheets

  2. Create a new spreadsheet

  3. Name it something like ToDoList

  4. In Row 1, add the column headers: TaskTimestamp

Keep this sheet open — we’ll connect to it shortly.


Step 2: Create a Google Apps Script API

We’ll now write a Google Apps Script that interacts with your spreadsheet.

1. Open the script editor:

  • Click Extensions > Apps Script

2. Replace default code with:

javascript
const SHEET_NAME = "Sheet1"; // adjust if you renamed it function doGet() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME); const data = sheet.getDataRange().getValues(); const tasks = []; for (let i = 1; i < data.length; i++) { tasks.push({ task: data[i][0], timestamp: data[i][1] }); } return ContentService.createTextOutput(JSON.stringify(tasks)).setMimeType(ContentService.MimeType.JSON); } function doPost(e) { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME); const data = JSON.parse(e.postData.contents); sheet.appendRow([data.task, new Date()]); return ContentService.createTextOutput("Task added"); }

This script:

  • GET: reads tasks from the sheet

  • POST: adds a new task to the sheet


3. Deploy the script as a web app:

  • Click Deploy > Manage Deployments > New Deployment

  • Choose "Web app"

  • Set access to: Anyone

  • Click Deploy and copy the web app URL

This URL is your API endpoint.


Step 3: Create Your HTML, CSS, and JavaScript

Let’s now build the frontend.

✅ HTML + CSS + JavaScript (All in One)

html
<!DOCTYPE html> <html> <head> <title>Google Sheets To-Do List</title> <style> body { font-family: Arial; max-width: 600px; margin: auto; padding: 20px; background: #f4f4f4; } h2 { text-align: center; } input, button { padding: 10px; font-size: 16px; } input { width: 70%; } button { width: 28%; } ul { list-style-type: none; padding: 0; } li { background: #fff; margin: 10px 0; padding: 10px; border-radius: 5px; display: flex; justify-content: space-between; } .timestamp { font-size: 0.8em; color: gray; } </style> </head> <body> <h2>Google Sheets To-Do List</h2> <input type="text" id="taskInput" placeholder="Enter your task" /> <button onclick="addTask()">Add</button> <ul id="taskList"></ul> <script> const apiURL = "YOUR_GOOGLE_SCRIPT_URL_HERE"; // replace with your deployed web app URL async function loadTasks() { const response = await fetch(apiURL); const tasks = await response.json(); const taskList = document.getElementById("taskList"); taskList.innerHTML = ""; tasks.forEach(t => { const li = document.createElement("li"); li.innerHTML = `<span>${t.task}</span><span class="timestamp">${new Date(t.timestamp).toLocaleString()}</span>`; taskList.appendChild(li); }); } async function addTask() { const taskInput = document.getElementById("taskInput"); const task = taskInput.value.trim(); if (!task) return alert("Please enter a task."); await fetch(apiURL, { method: "POST", body: JSON.stringify({ task }), headers: { "Content-Type": "application/json" } }); taskInput.value = ""; loadTasks(); } // Load on page load loadTasks(); </script> </body> </html>

Replace "YOUR_GOOGLE_SCRIPT_URL_HERE" with your deployed Apps Script URL.


How It Works

  1. User enters a task → Clicks "Add"

  2. JS sends a POST request to Google Script → It saves in the Sheet

  3. Tasks are fetched via GET and rendered on screen


Handling CORS and Security

For public use, ensure the script is shared as:

  • Execute as: Me

  • Accessible to: Anyone

Important: Don’t store sensitive data this way. For authenticated apps, you can use Google OAuth.


Advanced Improvements

1. Delete Tasks

Add an ID or use row index; use Google Sheets API or Apps Script deleteRow().

2. Mark as Completed

Add a checkbox and another column Done.

3. Add Google Login

Use Firebase Auth to restrict users and filter data.


Use Cases Beyond To-Do

Google Sheets is versatile. You can use this same technique for:

  • Contact forms

  • Guest books

  • Survey responses

  • Inventory lists

  • Booking systems


Conclusion

Using Google Sheets and Apps Script gives you a powerful backend for lightweight web applications without needing a full database or server.

You’ve now learned:

  • How to build a frontend with HTML, CSS, JS

  • How to use Apps Script as a REST API

  • How to send and fetch data from Google Sheets