By Raj

Build a Custom CRM in Google Sheets with Apps Script

Not every business needs Salesforce. If you have fewer than 1,000 contacts and want to track leads, deals, and follow-ups without paying $50/user/month, Google Sheets plus Apps Script is a surprisingly powerful CRM. You get a single source of truth in a spreadsheet, custom automations (reminders, logging, forms), and no new SaaS subscription—just Google Workspace and a bit of code.

This post outlines a simple sheet structure (Contacts, Deals, Activities), then shows three automations: a time-driven script that emails you follow-up reminders, using Gmail search to update "Last Contact Date," and a Web App form so your team can add leads without touching the sheet directly.

Sheet structure

Create tabs for Contacts, Deals, and Activities. The Contacts sheet has columns: Name, Email, Company, Phone, Status (Lead / Contacted / Won / Lost), Last Contact Date, Notes.

Automation 1: follow-up reminders

A time-driven trigger checks every morning: if "Last Contact Date" is more than 7 days ago and Status is "Contacted", send a reminder email to yourself:

function checkFollowUps() {
  const sheet = SpreadsheetApp
    .getActiveSpreadsheet().getSheetByName("Contacts");
  const data = sheet.getDataRange().getValues();
  const now = new Date();
  const reminders = [];

  for (let i = 1; i < data.length; i++) {
    const status = data[i][4]; // Status column
    const lastContact = new Date(data[i][5]);
    const daysSince = (now - lastContact)
      / (1000 * 60 * 60 * 24);

    if (status === "Contacted" && daysSince > 7) {
      reminders.push(data[i][0] + " (" + data[i][1] + ")");
    }
  }

  if (reminders.length > 0) {
    GmailApp.sendEmail(
      "you@example.com",
      "CRM: " + reminders.length + " follow-ups due",
      "Follow up with:\n" + reminders.join("\n")
    );
  }
}

Automation 2: log emails automatically

Use GmailApp.search() to find threads with a contact's email and log the latest date into the "Last Contact Date" column. Example: for each contact email in the sheet, search from:contact@example.com OR to:contact@example.com, get the most recent thread date, and write it to the Last Contact column. Run this on a schedule (e.g. daily) so the CRM updates itself.

function updateLastContactDates() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName("Contacts");
  const data = sheet.getDataRange().getValues();
  for (let i = 1; i < data.length; i++) {
    const email = data[i][1]; // Column B
    if (!email) continue;
    const threads = GmailApp.search("from:" + email + " OR to:" + email, 0, 1);
    if (threads.length > 0) {
      const lastMessage = threads[0].getLastMessageDate();
      sheet.getRange(i + 1, 6).setValue(lastMessage); // Column F
    }
  }
}

Automation 3: Web App form for new leads

Build a simple Web App (using HtmlService) that your team uses to add leads. The form writes to the Contacts sheet and sends a confirmation. No separate CRM tool needed.

When to level up

As your team and data grow, you might need: role-based access, pipeline visualizations, multi-user locking, or integration with Stripe/Shopify. I can build all of that inside Google Workspace—no new SaaS subscription. Get a quote.