You Don't Need a CRM. You Need to Know Who's Emailing You

At some point every solo developer has the same realization mid-reply: I think I've talked to this person before. You scroll your inbox. Was it the billing question last month? Are they on the paid plan? Didn't they report that webhook bug — or was that someone else with a similar domain?
The textbook answer is "get a CRM." So you look at one, and you are greeted by pipelines, deal stages, lead scoring, sales sequences, and a contact form with thirty fields. You dutifully import your users, and three weeks later the data is stale, because a CRM is a database you have to maintain, and you are one person shipping a product.
Here is the thing: the textbook answer is wrong. A CRM is the wrong shape for the problem you actually have.
CRMs answer a sales question. You have a support question.
A CRM exists to answer: where is this prospect in our funnel, and what should sales do next? Everything in it — stages, deal values, activity sequences, follow-up tasks — serves converting a stranger into a customer. That is genuinely useful if you have a sales team working a pipeline.
But when a support email arrives at a one-person product, the question is completely different: who is this, and what do they need? Concretely, four things:
- Who is this person? Name, company if any, and whether you have ever talked before.
- What have they asked before? The last three tickets tell you if this is a new problem, a recurring one, or round four of the same fight — and the tone changes accordingly. "Still not working" means nothing without the thread it refers to.
- Which account is theirs in your system? Not the helpdesk's idea of a customer — your database's. Their user ID, their plan, their workspace. The email says
jana@personal-gmail.com; your production database knows her as userusr_8f3a2on the Team plan with 40k API calls yesterday. Bridging that gap is 80% of debugging any account-specific issue. - Is there anything I told myself about them? "Churned once over pricing, came back." "Runs the big migration on weekends — don't deploy their fix on a Friday." "VIP: their tweet drove half our signups." Two lines of staff-only notes save you from stepping on a rake a past version of you already found.
Notice what is not on the list: deal stage, lead source, next scheduled touchpoint, email open rates. None of the machinery that makes a CRM a CRM helps you answer a support ticket. It just sits there, unfilled, generating guilt.
The external ID is the piece everyone skips
Point three deserves its own section because it is the difference between a contact list and something actually useful to a developer.
Support tools know customers by email. Your app knows users by ID. Every account-specific ticket — "my export is empty," "billing charged me twice," "my API calls are failing" — requires translating one into the other before you can even start. Without a stored mapping, that translation is a manual query, per ticket, forever:
SELECT id, plan, created_at FROM users WHERE email = 'jana@personal-gmail.com';
Store the external ID on the customer record once, and the lookup disappears. Better, it becomes automation fuel: a webhook fires when a ticket arrives, your handler grabs the customer's external ID, pulls plan and recent errors from your own database, and posts the summary right where you will read it:
// ticket.created webhook handler
const user = await db.users.byId(customer.externalId)
await notify(
`New ticket from ${customer.email} — ` +
`${user.plan} plan, ${user.apiErrors24h} API errors in the last 24h`
)
That is the "integration with your own product" that CRMs promise via marketplaces and middleware, achieved with one foreign key and twenty lines of code.
A directory that builds itself beats one you maintain
The reason your CRM experiment died in three weeks was not discipline. It is structural: any directory that depends on manual upkeep decays, because data entry always loses to shipping. The half-filled contact records were inevitable.
So invert the model. Every support interaction already contains the customer data — an email, usually a name, a timestamp, a topic. A directory that assembles itself from those interactions is current by construction:
- First ticket from a new address → a customer record exists now.
- They give a name on a later ticket → the record fills in.
- Every message → "last seen" updates on its own.
- Their history is the record — no field called "notes from last contact" to forget to update.
Your only manual contributions are the two fields that genuinely require you: the external ID (set once, ideally by a script or at signup) and the occasional staff note. Everything else accrues as a side effect of answering email you were going to answer anyway. This is the model Helmdesk's customer directory uses — records upsert automatically from tickets and feedback, with external ID and internal notes as the developer-supplied fields — but the principle matters more than the tool: choose systems where the default state is up-to-date.
The honest comparison
| Full CRM | Self-building directory | |
|---|---|---|
| Built to answer | Where is this deal in the funnel? | Who is emailing me and what's their history? |
| Data upkeep | Manual — decays without discipline | Automatic from interactions |
| Link to your app's data | Via integrations/middleware | One external-ID field + a webhook |
| Ticket history in context | Separate tool, maybe synced | Native — it's the same system |
| Time to stale | Weeks | Never, by construction |
| Right for | Sales teams working a pipeline | Developers answering support |
To be fair to CRMs: if you do outbound sales — demos, negotiated contracts, a real pipeline — you have the problem they solve, and you should use one. The mistake is only in reaching for one because "we should keep track of customers," when the tracking you need is the support kind, not the sales kind.
The bottom line
When a ticket arrives, you need four things on screen: who this is, what they have asked before, which account is theirs in your own database, and whatever notes past-you left. That is not a CRM; it is a customer directory with a ticket history and one foreign key — and the good version of it maintains itself while you get back to building.
Do not buy the thirty-field contact form. Buy back the five minutes per ticket you currently spend scrolling your inbox asking, have I talked to this person before?
Know who's emailing you — without maintaining a CRM
A customer directory that builds itself from tickets and feedback, with external IDs to link your own app's data and staff-only notes where you need them.