Back to Blog
AutomationMay 18, 202612 min read

How to Build a Google Sheets CRM with WhatsApp Follow-Ups (Free Template Inside)

A complete, lightweight CRM your team will actually use — built on tools you already pay nothing for. Includes Apps Script snippets and a free copy-and-go template.

$0/mo
Total cost
10 min
Setup time
3x
Faster response

If you're running a small business, you've probably tried at least one "real" CRM — HubSpot, Zoho, Salesforce, Pipedrive — and quietly gone back to a spreadsheet within a month.

It's not because you're lazy. It's because most CRMs are built for sales teams of 50, not founders, ops leads, and 3-person teams trying to stop losing leads. The features are bloated. The pricing scales aggressively. And nobody on your team logs into them.

Meanwhile, your leads are dying in WhatsApp chats and Excel files that only one person knows how to read.

💡A "good enough" CRM that your team actually uses every day is infinitely better than a perfect CRM that nobody opens. Google Sheets, when set up right, is that good-enough CRM.

In this guide, we'll walk through building a complete CRM in Google Sheets — lead capture, status tracking, auto-reminders, WhatsApp follow-ups, and team assignment — using Apps Script. No paid tools. No code skills required. You can have it running in 10 minutes.

Why Google Sheets Works Better Than You Think

We've set up this exact system for hundreds of small businesses. The pattern is the same every time:

❌ Weak

Pay $50–$300/mo for a CRM. Spend a week onboarding. Watch the team gradually abandon it for WhatsApp again. Lose visibility into where leads stand. Cancel after 6 months.

✅ Better

Spend 10 minutes setting up a Google Sheet. Wire up Apps Script for auto-reminders. Everyone already knows how to use a spreadsheet. WhatsApp templates go out automatically. Pipeline is visible at a glance.

The Apps Script layer is the unlock. It turns a passive spreadsheet into an active system — one that pings you when leads go cold, sends WhatsApp messages when a status changes, and auto-assigns new leads to the right team member.

If you haven't already, our previous post on why most MSMEs fail to convert leads explains the cost of bad follow-up in detail. This post is the practical fix.

What a Good Enough CRM Actually Needs

Forget the 47 features your last CRM tried to sell you. After auditing hundreds of small business setups, here's the minimum a CRM needs to do its job:

  1. 1Capture every lead in one place — no more lost WhatsApp chats.
  2. 2Track status — new, contacted, qualified, closed, lost.
  3. 3Trigger follow-up reminders — automatically, when leads go quiet.
  4. 4Send templated messages — so response time is consistent across the team.
  5. 5Show pipeline at a glance — conversion rates per source, per stage.

Everything beyond this is nice-to-have. We'll build all five today.

Step 1: Set Up Your Lead Sheet

Create a new Google Sheet. Name it something like "Lead CRM". Rename the first tab to "Leads" and set up these columns in row 1:

  • A: Timestamp (auto-filled on capture)
  • B: Name
  • C: Phone
  • D: Email
  • E: Source (Meta, Google, Referral, Website, etc.)
  • F: Status (New, Contacted, Qualified, Closed, Lost)
  • G: Assigned To (team member name)
  • H: Last Contacted (date)
  • I: Next Follow-Up (date)
  • J: Notes

Freeze row 1 (View → Freeze → 1 row). Bold the headers. Use Data → Data validation to make Status and Source dropdown menus — this keeps your data clean and reportable.

🎯The Source column is the single most underrated field. If you can't answer "which channel converts best?" from your CRM, your acquisition costs are flying blind. Make this a dropdown from day one.

Step 2: Auto-Capture Leads From Your Website

Manual data entry kills CRM adoption faster than anything else. The fix: when someone fills your contact or lead form, push them into the sheet automatically using Apps Script as a webhook.

In your Google Sheet: Extensions → Apps Script. Paste this code:

Code.gs — webhook for form submissions

function doPost(e) {
  const sheet = SpreadsheetApp
    .getActiveSpreadsheet()
    .getSheetByName('Leads');

  const data = JSON.parse(e.postData.contents);

  sheet.appendRow([
    new Date(),                  // Timestamp
    data.name || '',             // B
    data.phone || '',            // C
    data.email || '',            // D
    data.source || 'Website',    // E
    'New',                       // F (default status)
    '',                          // G (assigned to)
    '',                          // H (last contacted)
    nextBusinessDay(),           // I (next follow-up = tomorrow)
    data.notes || '',            // J
  ]);

  return ContentService
    .createTextOutput(JSON.stringify({ status: 'ok' }))
    .setMimeType(ContentService.MimeType.JSON);
}

function nextBusinessDay() {
  const d = new Date();
  d.setDate(d.getDate() + 1);
  if (d.getDay() === 0) d.setDate(d.getDate() + 1); // skip Sun
  if (d.getDay() === 6) d.setDate(d.getDate() + 2); // skip Sat
  return d;
}

Save (Ctrl+S). Then Deploy → New deployment → Type: Web app → Execute as: Me → Who has access: Anyone → Deploy. Copy the /exec URL.

On your website, point your form submissions at that URL. Any lead that fills your form lands in your sheet within seconds, pre-populated with timestamp and next follow-up date.

Don't want to build it yourself? We've productized this exact CRM — fully wired, WhatsApp templates included, $0/mo platform fee.

See WSD WhatsApp CRM

Step 3: Auto-Detect Cold Leads

Leads that nobody has touched in 48 hours are leaking revenue. Apps Script can scan the sheet daily and flag any lead where "Last Contacted" is too old.

Code.gs — daily cold-lead scanner

function flagColdLeads() {
  const sheet = SpreadsheetApp
    .getActiveSpreadsheet()
    .getSheetByName('Leads');

  const data = sheet.getDataRange().getValues();
  const today = new Date();

  for (let i = 1; i < data.length; i++) {
    const status = data[i][5];        // F: Status
    const lastContacted = data[i][7]; // H: Last Contacted

    if (status === 'Closed' || status === 'Lost') continue;

    const daysSince = lastContacted
      ? Math.floor((today - new Date(lastContacted)) / 86400000)
      : 99;

    if (daysSince > 2) {
      // Highlight the row in red
      sheet.getRange(i + 1, 1, 1, 10)
        .setBackground('#fce8e6');
    }
  }
}

To run this automatically every morning: in Apps Script, click the clock icon (Triggers) in the left sidebar → Add Trigger → Function: flagColdLeads → Event: Time-driven → Day timer → 6am–7am. Save.

Every morning at 6am, your sheet auto-flags every lead that hasn't been touched in 48 hours. Your team walks in to a visual punch list, not a guess.

Step 4: Wire In WhatsApp Follow-Ups

This is where the magic happens. WhatsApp Business has official APIs, but for small teams there's a faster path: pre-built WhatsApp click-to-chat links with templated messages.

Add an extra column "K: WhatsApp Link" with this formula:

Cell K2 (then copy down)

=IF(C2="", "", HYPERLINK(
  "https://wa.me/" & SUBSTITUTE(SUBSTITUTE(C2,"+",""), " ","") &
    "?text=" & ENCODEURL(
      "Hi " & B2 & ", this is " & "Your Name" &
      " from " & "Your Company" &
      ". Following up on your inquiry — when's a good time to chat?"
    ),
  "Send WhatsApp"
))

One click on "Send WhatsApp" → opens WhatsApp with the customer's number AND your message pre-typed. The rep just reviews and hits send. Response goes from "I'll get to it later" to ~5 seconds.

You can also vary the message based on lead status. Wrap the formula in an IF that picks different templates for "New" vs "Qualified" leads — first-touch script vs warm follow-up.

Step 5: Auto-Assign Leads to Team Members

If you have a team, round-robin lead assignment prevents the "but I thought *you* were calling them" problem. Apps Script handles this when a new row appears:

Code.gs — round-robin assignment on new lead

const TEAM = ['Priya', 'Raj', 'Anjali']; // your team

function onNewLead(e) {
  const sheet = e.source.getActiveSheet();
  if (sheet.getName() !== 'Leads') return;

  const row = e.range.getRow();
  if (row === 1) return; // skip header

  const assignedCell = sheet.getRange(row, 7); // G: Assigned To
  if (assignedCell.getValue()) return; // already assigned

  // Pick next team member based on row index
  const idx = (row - 2) % TEAM.length;
  assignedCell.setValue(TEAM[idx]);
}

Set this up via Triggers → Add Trigger → Function: onNewLead → Event: From spreadsheet → On change. Every new lead gets auto-assigned in seconds.

Step 6: Pipeline Dashboard

Add a second tab called "Dashboard". Drop these formulas in:

Dashboard formulas

Total Leads:        =COUNTA(Leads!B2:B)
New:                =COUNTIF(Leads!F2:F, "New")
Contacted:          =COUNTIF(Leads!F2:F, "Contacted")
Qualified:          =COUNTIF(Leads!F2:F, "Qualified")
Closed:             =COUNTIF(Leads!F2:F, "Closed")
Conversion Rate:    =COUNTIF(Leads!F2:F,"Closed") / COUNTA(Leads!B2:B)

Leads by Source (use a pivot or):
Meta:               =COUNTIF(Leads!E2:E, "Meta")
Google:             =COUNTIF(Leads!E2:E, "Google")
Referral:           =COUNTIF(Leads!E2:E, "Referral")

For visual reporting: Insert → Chart → Pie chart on the source breakdown. You now have an MIS dashboard that updates in real time.

Common Pitfalls (And How to Avoid Them)

  • Apps Script triggers stop firing silently after 6 months if the deployment owner removes their Google account. Use a dedicated business Google account, not a personal one.
  • WhatsApp click-to-chat doesn't work if the number isn't in international format. Always store phone numbers with country code (e.g., +14155552671).
  • If your sheet exceeds 50,000 rows, formulas slow to a crawl. Archive closed/lost leads to a separate tab quarterly.
  • Data validation dropdowns are case-sensitive. "new" and "New" count as different statuses in COUNTIF. Lock down with strict validation.
  • Don't share the sheet "anyone with link". Use specific email permissions — leads contain PII.

Skip the setup. Grab the template we use with clients.

Get our pre-built Google Sheets CRM template — complete with the Apps Script automations from this post already wired in. Auto-capture, cold-lead flags, WhatsApp links, round-robin assignment, and a live dashboard. Free, forever.

When You Need Real WhatsApp API (not just click-to-chat)

Everything above uses WhatsApp's click-to-chat URLs — your rep clicks a link, WhatsApp opens with the message pre-filled, they hit send. Free, simple, works perfectly for 1-50 messages a day.

But if you want true automation — AI-generated personalized templates, scheduled sends, inbound replies logged automatically to your sheet, delivery + read tracking, optional AI chatbot for first-touch qualification — you need Meta's official WhatsApp Business Cloud API.

Most teams reach for AiSensy, Wati, Interakt, or DoubleTick at this point. They charge ₹2,000–₹15,000/month forever, and your lead data lives in their cloud.

We built the alternative: WSD WhatsApp CRM. One-time setup, zero platform fee forever, runs entirely inside YOUR Google + Meta + OpenAI accounts. Same architecture as the template you just built, but with real Meta API + AI template generation + inbound webhook + status tracking wired in.

Ready for the production version?

WSD WhatsApp CRM extends the architecture in this post with Meta WhatsApp Business Cloud API, AI template generation, and full automation — at a one-time fee with zero monthly platform cost. We set it up in your accounts. You own the data. See the full breakdown.

See WSD WhatsApp CRM

🚀The right system is the one your team uses every day without complaining. Build the lightest version that captures leads, prompts follow-ups, and shows pipeline. Iterate from there. Don't over-engineer.

Frequently Asked Questions

Is Google Sheets really viable as a CRM?

For small teams (under ~10 people) and under ~100 leads per month, yes — comfortably. With Apps Script automations, it does 90% of what paid CRMs do, with none of the lock-in or recurring cost. Beyond that scale, you should migrate to a database-backed tool.

Do I need to know how to code?

No. Every code snippet in this post can be copy-pasted directly into Apps Script and will work as-is. The only customization needed is swapping in your team names and Source values.

How does the WhatsApp automation work exactly?

It uses WhatsApp's standard click-to-chat URL (wa.me/) with the message pre-populated as a query parameter. When your rep clicks "Send WhatsApp" in the sheet, WhatsApp Web or the desktop app opens with the customer's number and a fully-typed message. They review and hit send.

Can I use WhatsApp Business API for full automation?

Yes. Once you scale past ~50 outbound messages a day, the official Meta WhatsApp Business Cloud API becomes worthwhile. You have two paths: pay a SaaS like AiSensy/Wati ₹2,000-₹15,000/month forever, OR pay a one-time setup for WSD WhatsApp CRM (zero platform fee, lives in your own Google + Meta accounts, you own the data). See /services/automation for the comparison.

Does this work for service businesses, real estate, or D2C?

Yes — the structure is identical. The only difference is what you put in the Status and Source columns. Real estate uses statuses like "Site Visit Scheduled, Negotiation, Closed-Won." D2C uses "Cart Abandoned, Order Placed, Repeat Customer." Same skeleton, different labels.

What happens to the data if the Apps Script breaks?

Your data is safe — it's stored in the sheet itself, not in Apps Script. The automations stop running until you fix the code, but no leads are lost. This is the biggest reliability advantage over closed-source CRMs.

Can I integrate this with my Meta Ads or Google Ads?

Yes. Both platforms support webhook lead delivery via tools like Zapier, Make, or LeadConnector. Point them at your Apps Script doPost URL, and Meta lead form submissions land in your sheet automatically — same path as your website form.

Want to implement this for your business?

Book a free strategy call. We'll show you how to apply these insights to your specific situation.

Book Free Strategy Call

Keep reading

More from the blog

0

coffee imprint in 1970s Japan

~1 gen

the imprinting long game

70%

Nescafé's eventual share

Strategy11 min

How Nestlé Taught a Nation to Crave Coffee — And Why Most Founders Get the Lesson Backwards

In the 1970s Nestlé could not sell coffee to tea-drinking Japan. A French psychoanalyst found the reason — and the fix took a generation. The famous imprinting story, the psychology underneath it, and the one diagnostic that decides whether any of it applies to your ₹10-50 Cr brand (it probably does not, and that is the point).

June 13, 2026

🔁

60-70%

of CLTV brands never realise

40-60%

revenue from existing customers

1

number that sets your CAC ceiling

Growth15 min

The LTV Engine: Why Acquisition-Obsessed Brands Plateau — and the Retention System That Compounds Instead

Most ₹10-50 Cr Indian brands grow by acquiring harder. That is a treadmill. The brands that compound past ₹15 Cr build an LTV engine — they extract 3-5x more from each customer. Here are the four levers, the DTC-vs-B2B mechanics side by side, and why your LTV secretly sets your CAC ceiling.

June 12, 2026

📦

20-40%

COD orders lost to RTO

2.5x

the order value, lost per RTO

5

levers that actually cut it

Growth13 min

Your Returns Aren't a Logistics Problem. They're a Margin Leak Indian D2C Refuses to Diagnose.

RTO eats 20-40% of COD orders for most Indian D2C brands — and every brand treats it as a shipping problem to outsource to the courier. It isn't. RTO is a qualification, trust, and pre-delivery nurture problem. Here is the 5-lever system that cuts it, and why your highest-RTO cohort is also your lowest-LTV cohort.

June 11, 2026