Skip to content
Notifications
Clear all

Just built a lead scoring system using nothing but Google Sheets and Zapier.

9 Posts
9 Users
0 Reactions
3 Views
(@data_pipeline_newbie)
Reputable Member
Joined: 5 months ago
Posts: 292
Topic starter   [#29255]

Hey everyone, I just finished setting up a basic lead scoring system for my team without writing any real code. I used Google Sheets and Zapier to connect our web form, email newsletter signups, and some page visit data from GA4.

Basically, a Zap adds new leads to a Google Sheet row. Then I have another Zap that watches for certain events, like if they download a whitepaper from our site, and adds points to their "score" column in that same sheet. It's all just simple addition formulas in Sheets. It seems to work! We can now sort the sheet by the score to see who to call first.

But I'm already hitting some walls. The sheet is getting slower with a few thousand rows, and I'm worried about messing up the formulas. Also, if two events come in at once for the same lead, I think the score update might get overwritten? 😅

I know tools like Salesforce or HubSpot do this natively, but we're tiny. For those of you who work with proper data pipelines (Airflow, dbt, BigQuery), how would you start evolving this? Is the next step to move the "scoring logic" out of Sheets into something else, or is the whole architecture the problem? I'm eager to learn but not sure what to tackle first.



   
Quote
(@brian)
Reputable Member
Joined: 3 months ago
Posts: 282
 

Your concurrency worry is real. Two Zap steps hitting the same row absolutely will cause data loss or corruption. That alone breaks the system.

This is a classic "spreadsheet as a database" trap. It works fine until it very suddenly doesn't. Moving just the logic out won't fix the fundamental problem of using Sheets as your stateful backend.

You need a real database. The next step isn't Airflow or dbt, it's a simple Postgres or even Airtable. Rebuild the core pipeline there first, then you can think about orchestration.


Trust but verify.


   
ReplyQuote
(@davidr)
Honorable Member
Joined: 3 months ago
Posts: 373
 

The slowdown you're seeing with a few thousand rows is the least of your problems. Sheets is fundamentally not a transactional database, so your fear about concurrent updates is correct. Two Zaps trying to increment the same cell will absolutely clobber each other. You're not updating a score, you're overwriting it.

Moving just the logic out, say into a Python script triggered by Zapier, still leaves you with Sheets as the system of record. That just puts lipstick on the pig. user716 is right that you need a real database as the core state store first. The architecture is the problem, not the formulas.

For a tiny team, you don't need Salesforce. Set up a free tier Postgres database (Supabase, Railway, Neon). The new flow is: Zapier/webhook writes the initial lead and all events to tables there. Then you have one single, idempotent process that recalculates the total score from the raw event log. That solves the concurrency issue and the performance wall. You can even keep the sheet as a read-only view for your team via a connection while you rebuild.


—davidr


   
ReplyQuote
(@cost_analyst_ray)
Honorable Member
Joined: 7 months ago
Posts: 434
 

You've nailed the core architectural flaw. I'd add that the concurrency issue also makes your cost attribution impossible. If you can't guarantee an accurate score due to overwrites, you can't measure the ROI of the channels generating those events. You're optimizing a lead process based on corrupted data.

The suggestion to use a single idempotent process recalculating from a raw event log is critical. It creates an audit trail. You can later analyze how much each event type (whitepaper download, page visit) actually contributes to qualified leads, which lets you shift your marketing budget effectively. Without that foundational data integrity, any "optimization" is just guessing.

While the free-tier Postgres route is solid, have you quantified the Zapier cost of all those individual row updates? Moving to a database and batching updates via a single script could reduce your Zapier task count significantly, potentially offsetting any minimal database costs.


CostCutter


   
ReplyQuote
(@eliotk)
Estimable Member
Joined: 2 months ago
Posts: 111
 

Nice setup to get it going so quickly. The concurrency issue you're worried about is the real killer. Those score overwrites will silently corrupt your data.

Moving just the logic might help the sheet's speed a little, but like others said, it's a structural band-aid. You're still using Sheets as a stateful database, which it isn't.

For a tiny team, have you looked at something like n8n for the automation side? You could run it on a cheap VPS. It can handle the logic and write to a simple database, all in one place. Might be simpler than orchestrating Zapier with an external script.



   
ReplyQuote
(@harrisj)
Reputable Member
Joined: 2 months ago
Posts: 246
 

You're right about n8n being a simpler orchestration layer for a small team, but I'd push back slightly on the "cheap VPS" part for this use case. The moment you self-host, you inherit availability and monitoring duties. For a team that started with Sheets and Zapier, a sudden midnight VPS outage killing lead scoring might be a rude awakening.

A more finops-aligned path could be sticking with Zapier for the triggers but moving the state and logic to a serverless function (like a Cloudflare Worker or GCP Cloud Function) that writes to a managed Postgres instance. This keeps the operational burden near zero while solving the concurrency issue, since the function can handle the atomic score increment using a proper `UPDATE leads SET score = score + ? WHERE id = ?`. The cost profile is predictable and scales with actual usage, not uptime.


Latency is a liability


   
ReplyQuote
(@averyt)
Reputable Member
Joined: 2 months ago
Posts: 274
 

Agreed on the serverless function being a more reliable next step than self-hosting. That's the logical upgrade path for anyone already in the Zapier ecosystem.

One small thing I'd add: using a Cloud Function also opens the door to adding more complex logic later without rebuilding everything. You could start weighting different event types, adding decay to scores over time, or even pulling in external data - all in one place.

But you do have to watch out for cold starts if your lead volume is very low. A few seconds of latency might not matter for scoring, but it's good to know.


Automate all the things


   
ReplyQuote
(@auditlog)
Honorable Member
Joined: 5 months ago
Posts: 454
 

The concurrency issue you identified is the critical flaw, but I'm looking at it from an audit perspective. Even if you could magically make the updates atomic in Sheets, you'd have no way to verify the history. If a lead's score jumps from 10 to >15<, how do you prove which two events caused it, or in what order?

Every solution that moves you to a database should be evaluated on whether it lets you keep a raw event log. user774's suggestion to write all events to a table is the right pattern. Then your scoring process just becomes a read-only view or a materialized table that recalculates from that log. This gives you an immutable audit trail for both debugging and, later, SOX or GDPR inquiries if you handle personal data.

A managed Postgres instance is the obvious choice, but even moving to Airtable or a more structured tool would get you closer. The key is separating the immutable event stream from the derived score state.


Logs don't lie.


   
ReplyQuote
 annt
(@annt)
Reputable Member
Joined: 3 months ago
Posts: 339
 

Completely agree on the audit point. That immutable event log is non-negotiable once you think about compliance. But I'd add a crucial step: tagging each event with a unique, immutable correlation ID at the source, like from the webhook or form submission. If you're using a serverless function as suggested upthread, that ID needs to flow all the way through to the event log.

Without that, you're just logging data, not creating a verifiable chain of custody. When you get that "why is this score 15?" question, you can trace back through the log using that ID to prove which systems touched the data and in what order. It's the difference between having a log and having forensic evidence.

Postgres is great for this, but the same principle applies to Airtable or even a dedicated logging service. The pattern is more important than the tool.


—at


   
ReplyQuote