← Back to Work
Automation[TOOL][AUTOMATION][REAL BUILD SHOWN]
Relay
Two-way CRM-to-spreadsheet sync engineA two-way CRM-to-spreadsheet sync built for messy real data: updates in both directions, conflict detection for out-of-order edits, and failures that surface instead of disappearing.
- My role
- Built both sync directions in n8n, the conflict detection, and the failure logging.
- Built with
- GoHighLevel, n8n, Webhooks, Google Sheets
- Status
- Built and running
- 2-wayCRM and spreadsheet updates in both directions
- Conflicts caughtolder edits flagged and logged, never written
- Failures surfacedlogged before bad data spreads downstream
Before
The problem
Contacts lived in two systems with no sync, so every addition was re-entered by hand. Inconsistent real-world data broke simple sync attempts, so the fix had to survive messy input.
The system
How the pieces connect
- GoHighLevelContact or status change
- n8nWebhook, both directions
- n8nConflict check
- Google SheetsRow written back
- Failure logSurfaced, not silent
Proof
The real build
Real buildn8n execution
Step by step
How it works
- 1A new CRM contact creates a matching spreadsheet row automatically.
- 2Unsynced sheet rows go the other way, creating or updating the CRM contact.
- 3Status changes sync through dedicated logic per state, not one catch-all update.
- 4An update older than the record's last edit is flagged and logged, never written over newer data.
- 5Failures are logged where someone will see them, before bad data spreads downstream.
Two-Way Sync
GoHighLevel / New Contact
NameDana Whitfield
Emaildana@voltframe.io
StageNew Lead
→
via n8n
Google Sheets / Row Added
NameDana Whitfield
Emaildana@voltframe.io
StageNew Lead
Synced At09:41:03 AM
✓ Synced
SIM: a simplified illustration of how the system behaves, with invented data. Not a capture of the real build.
After
What changed
› Manual re-entry between systems eliminated. One update now populates both.
› Sync failures surface proactively instead of being discovered after someone downstream notices bad data.
› Status tracking consolidated to a single accurate view instead of two systems that could silently drift apart.
Stack
For technical readers
Technical detail
The problem, in detail
› Contact records lived in two systems with no sync between them. Adding someone in one meant manually re-entering them in the other.
› Status updates had to be checked by opening each system separately. No single view showed what stage a record was actually in.
› Inconsistent real-world data (missing fields, mismatched formatting) broke naive sync attempts, so any fix needed to survive messy input, not just clean test cases.
Build notes
A two-way sync between a CRM and a spreadsheet, built to handle production-messy data in both directions.
› New CRM contacts create a matching spreadsheet row automatically, no manual re-entry.
› Status changes in the CRM sync back to the spreadsheet through dedicated logic per state, not a single catch-all update.
› Built-in monitoring surfaces sync failures before they become a production problem, instead of failing silently.
› Handled a subtle row-offset bug where the sync tool's row-reference indexing didn't match the spreadsheet's actual row numbers, a bug that would have silently corrupted the wrong row's data if it had shipped uncaught.