Track Donors in Google Sheets Without Expensive CRM Software
Stop paying \$100/month for Salesforce. Build a robust, free CRM in Google Sheets that tracks donors, interactions, and total giving.
Salesforce Nonprofit Success Pack (NPSP) is "free" for 10 licenses, but the implementation costs $15,000. HubSpot costs $50/month per user. For small nonprofits, CRM costs bleed resources better spent on programs.
A CRM is just a relational database. You have one in Google Sheets (Donors) linked to another (Donations) and a third (Interactions). We just need to glue them together.
Here's What We'll Build
A sidebar in Google Sheets where you can log calls, notes, and donations without scrolling through 50 columns.
The Code: The "Quick Log" Sidebar
1. Setup
- Tab 1: Donors (Col A: ID, B: Name, C: Email, D: Last Contact Date)
- Tab 2: Interactions (Col A: Donor ID, B: Date, C: Type, D: Notes)
2. The Script
We need two files: Code.gs (Server) and Sidebar.html (Client).
Code.gs
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('CRM')
.addItem('Open Logger', 'showSidebar')
.addToUi();
}
function showSidebar() {
const html = HtmlService.createHtmlOutputFromFile('Sidebar')
.setTitle('Donor Logger');
SpreadsheetApp.getUi().showSidebar(html);
}
function logInteraction(donorName, type, notes) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const interactionsSheet = ss.getSheetByName('Interactions');
const donorsSheet = ss.getSheetByName('Donors');
// 1. Log the interaction
interactionsSheet.appendRow([
new Date(),
donorName, // Ideally use ID, using Name for simplicity here
type,
notes
]);
// 2. Update "Last Contacted" on Donors tab
const data = donorsSheet.getDataRange().getValues();
for (let i = 1; i < data.length; i++) {
if (data[i][1] === donorName) { // Assuming Name is Col B (index 1)
donorsSheet.getRange(i + 1, 4).setValue(new Date()); // Update Col D
return "Success";
}
}
return "Logged (New Donor)";
}Sidebar.html (Create this file by clicking "+ > HTML")
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<body>
<div class="sidebar branding-below">
<form>
<div class="block form-group">
<label for="donor">Donor Name</label>
<input type="text" id="donor" style="width: 100%;">
</div>
<div class="block form-group">
<label for="type">Type</label>
<select id="type" style="width: 100%;">
<option>Call</option>
<option>Email</option>
<option>Meeting</option>
</select>
</div>
<div class="block form-group">
<label for="notes">Notes</label>
<textarea id="notes" rows="3" style="width: 100%;"></textarea>
</div>
<div class="block">
<button class="action" id="save">Log Interaction</button>
</div>
</form>
</div>
<script>
document.querySelector('#save').addEventListener('click', function(e) {
e.preventDefault();
const donor = document.getElementById('donor').value;
const type = document.getElementById('type').value;
const notes = document.getElementById('notes').value;
google.script.run
.withSuccessHandler(function() {
document.getElementById('notes').value = ''; // Clear notes
alert('Saved!');
})
.logInteraction(donor, type, notes);
});
</script>
</body>
</html>Why This is Better Than Excel
Excel is flat. This is interactive. You can browse your donor list, select a row, and instantly see their giving history in the sidebar (with a bit more code). You can’t do that with a static spreadsheet.
Get more tips like this
Subscribe for practical Google Workspace automation tips.
Free updates. No spam. Unsubscribe any time.
Want more help?
We're here to help. Drop us an email and let's explore how we can optimize your workflows.
Email ushello@mereth.dev