No-Code CRM for eCommerce Using Automation Tools I Barely Held Together
I’ll just say this upfront: I didn’t set out to build a CRM. I just wanted abandoned cart emails to stop slipping through the cracks and team messages not to disappear into Slack purgatory 😛
But like a lot of eCommerce setups, things ballooned. Orders were coming in from Shopify, messages across Gmail and Instagram DMs, and our customer notes were stuck in someone’s Notion folder only they had access to. So I Frankensteined it—Glide for the front-end, Airtable as the source-of-truth, and Zapier + Make to glue the chaos together. And weirdly, it mostly worked… until it didn’t.
Let me walk you through how I stitched together a no-code CRM for an eCommerce team, what broke constantly, and where the duct tape is. Hopefully this helps you not waste seven hours debugging a duplicate record trigger that only fails when the payment status is “paid” and the sky is overcast ¯\_(ツ)_/¯
1. Starting with Airtable and the fields I kept forgetting to map
Airtable was a no-brainer because everyone on the team already used it to track inventory. From there, I tried to organize everything into one base—Orders, Customers, Products, and Messages linked through relational fields. Simple enough in theory.
The funny part is how often I forgot to map key fields in automations. Like, I had a working Zap for new Shopify orders populating Airtable, but discovered two weeks in that customer email wasn’t even coming through. Turns out the Shopify trigger gives you nested line_item metadata, and Zapier handled those in a way that doesn’t flatten them unless you click into “Show All Options.” It’s not labeled clearly, and you won’t know you’re missing something unless you manually test every payload.
Real situations that absolutely happened:
– Customer orders shows up with a blank “Source” field (thanks, unrecognized referral params)
– Archived orders from over 90 days mysteriously re-trigger Zaps if you do a base re-sync
– Random SKU fields get interpreted differently depending on whether it’s via Make or Zapier
So now I keep a shared Notion doc called “FIELD MAPS I WILL BREAK AGAIN” just to avoid autofill chaos.
2. Using Make to connect Shopify and Airtable without Zapier’s limits
I originally used Zapier for everything, but once my multi-step Shopify-to-Airtable Zap started exceeding tasks because of image conversion steps (Shopify variants include media links that had to be stripped and cleaned), I migrated that Zap to Make.
Make.com is amazing—with one huge caveat: you have to understand how to handle lost executions. If your Airtable throws an error rate limit, Make retries three times over 30 minutes—quietly. Which led to orders getting duplicated with slight phone number mismatches. The error log said “Execution completed successfully,” even though two entries were created.
My workaround now:
– I add a unique order-hash once Make starts an execution
– I let Airtable reject inserts if a hash exists
– And I push error logs to a private Slack channel I regret leaving unmuted now
Also, Make’s array handling is… annoying. It unfolds nested arrays differently than Zapier, especially for Shopify checkouts that include multiple shipping lines. I wrote a router that tries to flatten all lines into one pipe-delimited string, and I STILL occasionally get a 422 error from Airtable for “invalid field type.”
Official documentation: https://make.com has more on how data structures map across modules, but even then you’ll hit undocumented behaviors when syncing rich text vs plain text.
3. Creating a Glide front-end that sales and support could actually use
The front-end was built in Glide so our support reps didn’t have to squint at Airtable grid view. Glide lets you build interfaces from Airtable or Google Sheet backends. I connected it directly to our Airtable CRM base.
Most of the work was UI cleanup:
– Making customer profile viewable with associated order history
– Adding a “Manually Flag Issue” toggle that sends a webhook to Make for internal alerts
– Creating a search bar that actually respects phone number formatting (wildly inconsistent from Shopify to Google Sheet to Airtable)
Biggest annoyance: if a rep edited a record on Glide, Airtable automations would fire again unless I filtered for “Last Modified By is not Glide App.”
Tips I wish someone told me:
1. Create a user access log using Glide’s built-in user profile system—then you’ll know who touched what.
2. Format all timestamps to UTC at ingestion, or your support team in PST will keep using the wrong ordering date.
3. Use a dummy “Internal Notes” field that’s Glide-only so you don’t accidentally overwrite primary fields in Airtable.
It became a running joke—”Don’t edit that field unless you want to trigger seven Zaps.”
4. Building a support queue with Gmail and Slack without replying twice
Our goal was to funnel all customer messages—order requests sent via Shopify, email inquiries, and DMs—into a single ticket-like view. Sounds simple. It wasn’t.
First, Gmail filtered automation-friendly emails differently when processed through the “when new email received” Zapier trigger. Sometimes, if a customer forwarded a message chain, the entire payload came blank. Blank. Not even headers.
Slack had its own unpredictability: sending threaded messages via automation depends on using a timestamp that Zapier sometimes doesn’t retrieve unless you do a real-time test. Once I figured it out, I had to manually copy a Slack timestamp into a Google Sheet lookup table to keep threading sane. It still breaks if the original message got deleted.
Eventually, here’s how I structured it:
– Zapier listens for new Gmail messages labeled “Support”
– Filters for messages with Shopify order numbers (regex match)
– Searches Airtable for that order’s customer ID
– Posts a Slack thread under a pinned internal message
Then Glide shows the Slack thread link inside the customer record. It kind of looks beautiful when it works—but then Gmail adds a 20-second delay some mornings and everything misaligns.
5. Setting up Zapier filters that broke silently after a field rename
This is the one that legitimately made me yell out loud.
You can rename a field in Airtable and Zapier won’t always pick up the change unless you re-test the entire trigger. You’ll think your Zap is working fine—filter says “Order Status contains Paid”—but that field doesn’t even exist anymore. It got renamed to “Status – Paid/Unpaid” and Zapier’s filter just returns False every time without warning.
I ended up creating a dummy record in Airtable called “Zap Test Dummy” with every possible value. Once that record fails to go through a filter, I know the condition’s broken.
Other filters that unexpectedly failed:
– Shopify “Discount Code Used” field coming in as null even when the field exists
– Multiple tag conditions (Zapier’s “Text Contains” doesn’t support arrays properly)
– Text filters that break when a value has leading whitespace (yes, for real)
And when you duplicate a Zap to reuse the filter logic? Don’t. It copies broken references silently. Rebuild it from scratch instead 🙂
6. Automating customer follow-ups and the SMS step I totally missed
Once the CRM was stable(ish), I wanted to automate follow-ups: cart abandon emails, product review requests, and refund confirmations. Most of this ran through Email by Zapier + Twilio.
But here’s the kicker—Twilio sometimes refuses to send SMS if the content is too similar to a message previously sent to the same number. No clear error, just… it doesn’t arrive. I only caught it because a customer replied, “Is this a scam? You texted me the same thing yesterday.”
Workaround:
– I added a timestamp and partial name hash to each message
– Used Make to build SMS strings like: “Hey Amanda, just checking on your order from Mar 4. Reply OK if everything arrived.”
Also discovered that “Email by Zapier” sometimes strips non-ASCII characters. Goodbye, elegantly styled product names. Had to switch to Gmail API with HTML templates stored in Google Docs fetched over webhook.
The data path for each message now:
1. Zapier: Trigger on CRM row change (e.g., Order marked “Delivered”)
2. Delay 48 hours using Delay module
3. Look up if customer has submitted feedback already
4. If not, send Email and SMS with tracking info + CTA
Glide logs whether message was sent, as long as no delay step fails. If it does, the Zap silently stops and you find out two weeks later when reviews flatline.
7. Validating eCommerce inventory before triggering automations
A bit more advanced but worth mentioning: we auto-add high-interest items (like frequently bought-with products) to a promo bundle list. But once we ran out of physical stock, customers would click through an email and get a “Sold Out” page. Classic facepalm.
Now I validate inventory before Final Send:
– Call Shopify API live through Make
– Check that target product tag group has > 5 available inventory (buffer builds)
– If not, Zap gets short-circuited and emails get rescheduled for later
Make’s Shopify module can be flaky around stock values—it sometimes caches the previous batch result for multiple calls in a scenario. I had to insert a sleep step of 2 seconds between calls and force a Get Product by ID instead of SKU to get real-time quantities.
There’s no documentation about this, just me pulling my hair out in a Slack with the product manager going “Why does this scenario say inventory is 12 when I literally see zero in the dashboard.”
It’s fragile, but we’ve avoided major promo misfires ever since.
8. Error tracking and notification loops that spiral out of control
The last piece was error handling. You’d think this stuff would be built-in or simple. It’s not. Catching failures on Make and Zapier is a mess.
Early mistake: I set up a Zap for every Zap error (using the built-in “Zap Error Occurred” trigger), which sent me an email… and created a new record in Airtable… which triggered another workflow. You can guess where this is going.
I created an infinite loop that spammed my inbox and Airtable until we hit platform task limits. There was a Slack thread titled “Aaron finally DDoSed himself with Airtable.” ¯\_(ツ)_/¯
Current setup:
1. Errors from Make push into a dedicated “Error Queue” table in Airtable with timestamp and error excerpt
2. A Glide tab shows latest errors for devs to triage during coffee breaks
3. Zapier sends a Slack message only if error is not keyword-matched against “rate limit” or “record missing” (those are common noise)
4. We batch real issues into a weekly Notion list with links to offending automations
It’s not elegant, but at least now I don’t wake up to 85 unread emails that all say “Execution failed: module 5.”
Eventually I do plan to hook this into a proper incident tracking system… or not 🙂
