Building a No-Code CRM That Mostly Works Until It Doesn’t
1. Picking the wrong base tool ruins everything three steps later
Don’t start with the tool you like the look of. It’s probably lying. I picked Notion the first time because I liked toggles. That mistake hit about two hours in when I needed actual relation fields between contacts and deals. Linked databases look slick but they fall over the second you want to auto-sort by last interaction timestamp. There’s a delay, or worse, it doesn’t update unless you click around manually. Notion did everything… until it didn’t show up in the Make search module. Couldn’t even find the database without pasting a full block URL.
I ended up dropping into Airtable again. Not because I wanted to, but because I had a client nagging me to show last contact dates in a kanban view by stage. Airtable’s native view-switching is ugly but functional — and, critically, every record has a unique ID exposed instantly. You can see it in the URL if all else fails. That alone saved three hours later when a webhook pushed duplicate records from a rogue Zapier branching step.
The setup looks like a simple contacts → deals → history table structure. But the actual architecture moved like seven times mid-build thanks to field mismatches and lookup bugs that only show up once Make starts pulling payloads.
2. Trying to trigger updates when nothing visibly changes fails silently
I assumed Make would handle change detection gracefully. It did not. Specifically: updating a comment field in Airtable does not consistently count as a record update. Make’s Airtable “Watch Records” module occasionally just… skips it. No error, nothing. It never fetches the revision unless another field toggles. I ended up forcing a hidden checkbox to flip every time a comment was added, just to guarantee it tripped the scenario.
If you’re doing a classic CRM feedback loop — “New note → update last contacted field” — this breaks everything. The automation half-executes with stale data and drops the newly added note entirely. Notion’s changelog would at least show the edit happened. Airtable pretends like the field stayed the same if the API didn’t directly touch it.
Eventually wired a workaround based on the “Last modified time” field, but only after realizing it excludes computed fields. So I had to pipe the comment text through a manual formula just to lock it into a visible state change for Make’s polling module to detect.
Highlight:
IF(Comment & "" = '', '', NOW())
Not elegant — but it reliably updated the timestamp so I could sort by most recent interaction.
3. Team tagging relies on invisible permissions you forgot you set
We tried assigning leads in a shared Airtable base using a single-select called “Owner.” Seemed easy until one person couldn’t see half the records. Turns out, Airtable’s old shared workspace permissions don’t grant row visibility unless both:
- The user is explicitly added as a base collaborator
- The view shows every field you group or filter on
That constraint isn’t apparent anywhere until you troubleshoot with screen share and realize someone’s dragging empty columns into new groups. We later learned that dropdown values don’t sync consistently for users unless they’ve been involved in editing that field before. One person even had nulls instead of names for existing records.
Ultimately switched to using a user email field that matched against a lookup from a “Users” table. It made filtering messier, but at least it removed the invisible hell of select-field permissions that only apply half the time.
4. Google Sheets always breaks three steps into lead imports
It’s always the CSV step. At some point, someone drops a file into the wrong folder and a Zap picks it up before it finishes uploading. You get partial headers, 9 rows, and no leads. Then it runs again three minutes later with the full file, but duplicates all the ones with matching emails except the broken row with a comma in a note field. Google Sheets isn’t the failure — the file watcher in Zapier is.
Fix was surprisingly ugly. You have to insert a delay (I used a 90-second Delay After Queue) and then a second step that checks if the cell count in row 1 is more than 3. If not, halt it. Feels dumb, but it worked. The better fix was removing Sheets entirely. Went with a Make scenario that watches a dedicated Slack channel for live paste dumps, validates structure in a script module, and then parses the rows into Airtable asynchronously.
Why Slack paste? Because the team refused to fill out Airtable form views. Honestly, fair — fields reset if mobile data blips mid-entry. Slack handles quick dumps better, and Make can regex parse the message content with surprisingly few errors.
5. AI integrations say yes to everything and then silently fail
I tried building a GPT-powered contact enrichment step via Zapier’s OpenAI module. Thought I’d get fancy: take a contact name + company, ask GPT to summarize their potential business model. Kept returning “null response” — no error in Zapier, just nothing appeared in the record.
Eventually realized the prompt token count passed the model’s limit when it pulled in previous message history. Zapier’s legacy OpenAI module doesn’t handle context length; it just chops the message and sends whatever fits, no warning. Switched to Make’s HTTP module and hit OpenAI directly. There, at least, I could view the full payload and detect structure errors.
What worked:
{
"model": "gpt-3.5-turbo",
"messages": [
{ "role": "system", "content": "You are a B2B market researcher." },
{
"role": "user",
"content": "Given this: Name: Alice Gregg, Company: TarmacStack — what does the company likely do?"
}
]
}
This works maybe 70 percent of the time before GPT decides TarmacStack is a logistics startup with no proof. But at least the field populates.
6. Triggering automations from calendar events stays janky on every platform
You’d think creating a Google Calendar event with a specific keyword in the title could just… trigger a deal stage update. But none of the native Calendar integrations do selective matching well. Zapier sees all events, even ones you didn’t make. Filtering by “Created by me” fails when assistants create the event. Add in recurring meetings and the Zap re-triggers every week like it’s Groundhog Day.
Switched the system to push contacts into a CRM “engaged” stage manually the moment a time was selected. Had to get creative: built a tiny web form (using CognitoForms, of all things) that the sales team fills the moment someone books time — including the calendar link, person’s email, and meeting intent. Make watches the form’s webhook, greps the email, and moves the deal.
It’s a manual patch on what should be fully automated — but the automation was worse than just clicking a dropdown. Too many ghost triggers burned more deals than it helped.
7. CRM comment histories should be sortable but never are
One of our use cases was showing a quick scrollable history of contacts’ previous touchpoints. Expected timeline behavior: newest comment at top, chronologically stacked. Airtable’s workaround was a linked “Interactions” table sorted by “Date” field descending. What we got instead: if you append entries via automation, the sort isn’t respected. The view memorizes your last sort but doesn’t persist it inside lookup fields unless the view re-renders.
Discovered that by accident: edited a comment in the linked Interaction table, and the lookup order flipped. No setting toggled. Just a phantom behavior. Apparently, internal sort memory resets on any field update in that table — not well-documented but replicable every time.
My workaround: create a junction table where each deal is joined with interactions timestamps, then display that summary only in the CRM “Detail View” dashboard. Ugly but consistent.
8. Working CRM dashboards break when sharing disables button fields
If you build your CRM dashboard with button fields linking to filtered views, beware: the button does not function in shared or embedded views. You can still see it, but clicking does nothing. No error, no warning. Airtable just blocks the action silently once you’re not in edit mode.
Came up during a client demo. Tried to launch a deal inspector dashboard via shared view — button just sat there. Tapping it did nothing. Found out later this is on purpose, but not documented clearly. Airtable buttons only execute for editors. Read-only viewers see the visual element, but it’s dead.
Fixed by replacing the button with a formula field that renders a pre-filtered Airtable URL manually. Same experience, but now the link works outside of edit mode.
"https://airtable.com/tblABC456xyz123/viwXYZ123456?filter_DealID=" & [Deal ID]
The copy-paste ugliness is worth it just to avoid trying to explain to clients why their CRM buttons don’t do anything.