Location Lisbon, Portugal
menubar mix
Bluetooth lambert's airpods ✓
now building: Kai 9:41 AM
Notes

15 min read

How I built an automated backlink CRM with Claude to raise our domain authority

The CRM I built from scratch to run Kai's backlink exchanges: one CSV, a Claude skill that works it every morning, and what it did to a domain the rebrand had put back at zero.

A prompt that asks about your product first, then adapts every step. Works in ChatGPT too.

Hey!

My name is Lambert, and I run growth at Kai. Our product used to be called Omnia, on hireomnia.ai. In April we rebranded and moved to hirekai.ai, and a domain nobody has linked to yet has a Domain Rating of 0, which is Ahrefs’ way of saying it has no standing. Zero is as bad as it gets. You can write the best article in your category and it will sit on page four.

Pointing the old domain at the new one carried the first 16 points in a week. Everything above that we had to earn. Today it reads 41, and 55 links from 49 different sites point at us. I want it past 50 before the end of October, when we launch on Product Hunt.

Ahrefs Site Explorer for hirekai.ai, last 6 months, weekly. The referring domains chart climbs from near zero at the end of March to 336 in the week of 14 to 20 September. Below it, average Domain Rating rises through the spring and reads 41 in the same week.
hirekai.ai in Ahrefs on 20 September 2026. The referring-domains number counts everything, including a tail of throwaway spam nobody asked for, which is why I watch the rating underneath it.

I didn’t buy a single one of them. About two thirds arrived without me asking. The whole thing runs out of one CSV file in our repo and a Claude skill that reads it, and it costs me 20 minutes a morning.

Here’s how it works, including the bits that went wrong.

It started because three months of SEO weren’t taking

In June, Jim, our growth lead, and I looked at everything we had done on SEO since the start and had to admit it wasn’t landing. Not one tactic that failed. The way we were working was wrong, and we had been measuring effort instead of results.

So we rebuilt the method rather than the tactics. Quality over quantity everywhere: fewer articles written properly instead of ten a week, real videos made with real people, and authority treated as its own problem rather than something that would show up on its own.

Authority is the third leg of SEO, and in practice it means backlinks. Google wants to rank pages other people vouch for, and the closest thing it can measure is a link from one site to another. Two flavours matter. A dofollow link passes authority. A nofollow link tells Google not to count it, which is what a site uses when it wants to mention you without vouching for you. If you’re negotiating a placement and nobody has said the word dofollow, you’re negotiating for a mention.

The score everyone watches is Domain Rating, Ahrefs’ 0 to 100 estimate of how trusted a domain is. Google has its own opinion and shares none of it, so DR is a proxy rather than a fact. It’s still the number that decides whether anyone will trade with you, which is exactly the problem when yours is 0.

So Jim and I asked the blunt version of the question: how do we get a lot of good backlinks, on purpose, repeatedly. Everything below is the answer I built.

I don’t offer Kai, I offer Morgen

Nobody wants a link from a domain with no authority. A new product has nothing to give the people it needs something from. That’s the wall, and it’s the honest reason most “how to get backlinks” advice doesn’t survive contact with a domain that was five months old.

We got over it because we already own the other side of the trade. Morgen, the calendar app I also work on, has been around for years and sits at DR 73, flat since 20 July.

So I don’t offer Kai. I offer a link from morgen.so, and I ask for one to Kai in return. The partner gets the link they came for, from a domain with real weight, and we spend that weight on the product that needs it. It changes nothing about the process. It just makes every conversation possible.

I want to be straight about this, because it’s the part that isn’t replicable: this play requires a second domain you already built. If Kai were our first product, none of what follows would work. What I’d do instead is at the end.

Where I can, the swap goes three ways rather than two. Morgen links to the partner, the partner links to Kai. Two sites linking to each other is a pattern Google discounts, and three-way placements keep the relationship out of the shape a filter looks for.

Three channels, and only one of them is pleasant

The first month went into building the system, not into outreach. That felt slow and it was the right call, because the volume arrived before the method would have.

LinkedIn is the biggest channel and the worst one to work. There’s an entire industry of people who manage backlinks for other companies, and once you look like someone who might say yes, they find you. A lot of it is bot-driven and most of it is junk for what we do: weak domains, wrong audience, the same target list mail-merged to everybody. It arrives every day, which is exactly why someone has to read it every day.

There’s no API for personal LinkedIn messages and no MCP, so I screenshot the conversation and paste the image into Claude. That was the whole system at the start, and it’s still the crude part today. It’s crude because LinkedIn is closed, not because I haven’t got round to it.

Email is the easy one. The Kai MCP reads my Gmail and my Outlook, so anything that arrives for Morgen or for Kai gets read, matched to the right row and logged without me touching it.

Slack came later, when someone invited me into channels built around link exchanges and SEO. That turned out to be the best source of the three. The people there are doing the same job I am, they know what a relevant placement looks like, and the conversations are with humans rather than with a pipeline.

The CRM is a CSV I built from scratch

The idea we landed on in June was to log every message with every person, across every channel, in one place. Not a tool. A file.

It’s outreach-log.csv in our knowledge base repo, 229 rows today, one per person or domain, 15 columns. Fourteen are what you’d expect: who, which domain, its DR and its traffic, the status, the dates. The fifteenth holds the entire conversation as a dated timeline, appended to and never overwritten.

The outreach CSV open in Numbers, about thirty rows visible. Names, domains and contact details are pixelated. The track column reads backlink on every row, the owner column reads lambert, and the Domain Rating and monthly traffic columns are readable, ranging from 45 to 91 and from 38 to over a million visits a month.
One screenful of the 229 rows. Names, domains and contacts pixelated, because a public list of who links to us is exactly what I refuse to hand to brokers.

A CSV looks primitive next to a CRM product, and every property of it is deliberate. It’s in git, so I can see who changed what and when a status moved. Jim and David can open it in Numbers or Google Sheets without asking me for a seat. I can answer “have we talked to this person” with one grep. And an agent can read the whole thing, which is the property that matters most: when a broker resurfaces after five weeks of silence, Claude reconstructs the conversation from that timeline column instead of asking me what happened.

The rules around it are short, and each one came from being wrong.

One row per person, domain or handle, searched on all three keys before anything gets added. We double-contacted people before that rule existed, which is a bad look when the two messages offer different terms.

Then two markers that exist to be grepped. PROMISED>> holds the verbatim sentence of anything I committed to a partner, with the date. SENT>> records that a message actually went out, and how I confirmed it. Those exist because on 23 August I told a broker we owed him nothing, and he replied with a screenshot of my own written promise. He was right and I was wrong. The row held both a private valuation of his link and the promise I’d sent him, one line apart, and I’d read the wrong one. An internal opinion never cancels an external promise, and the only way to keep those apart in a field that runs to thousands of characters is to mark them.

The skill, and how it grew

My way of working with Claude is simple: it takes the boring half. Reading the messages, understanding what’s being proposed, checking whether it’s worth anything, keeping the file straight. I keep the judgement and the replies.

There was no skill at first. I pasted screenshots and typed the same instructions every morning, which works until it doesn’t.

The first version only checked state. It read the latest messages, compared them against what the CSV already held, flagged anything new, and ran the same analysis on every proposal: is there real traffic behind this domain, what’s its authority, is the topic close enough to what we do, does this placement make sense for the reader. Opportunity or not, with a reason.

The version I run now starts one step earlier. Before it touches a single message it pulls Ahrefs and asks what moved since the last run: did the rating change, did we gain links, did we lose any. Then it goes through everything that came in and everything that went out, updates the rows, and drafts the replies.

Around that I’ve been wiring in whatever the platforms allow. The Kai MCP for email. The Slack MCP on the channels worth watching, so it reads new arrivals and hands me the ones whose domains actually fit. LinkedIn still gets screenshots. And all of it sits on our knowledge base, which is the part people skip: the skill is only good because everything it needs to know about Morgen, about Kai, about what we’ve already promised and to whom, is written down somewhere it can read.

The morning run, top to bottom. What comes in: LinkedIn as pasted screenshots with no API, email through the Kai MCP on Gmail and Outlook, the Slack exchange rooms through the Slack MCP. What the skill does, in order: Ahrefs before any message for what moved since the last run, link_check.py fetching every placed link and reading the HTML, qualifying every proposal on traffic, authority, topical fit and who is really asking, then writing the CRM. What comes back: drafted replies, the placement written into a Morgen article through the Webflow MCP, any lost link named with its page and its owner, and the rule that I send and it does not. Every step reads the knowledge base.
The loop as it runs today. The only thing it cannot do is send.

Twenty minutes in the morning

That’s the routine. I open LinkedIn, read what came in overnight, hand it to the skill and let it run in the background for 20 or 30 minutes. It comes back with the CRM updated, the day’s analysis, and the replies drafted for me to send.

It didn’t start daily. At the beginning, once a week was enough for the volume. What changed is who’s on the other end: most of these people manage links for several companies at once, and the moment they see you answer quickly, they send you more. Being reactive is itself a source of proposals, so the pipeline grew until a weekly pass stopped covering it. Twenty minutes every morning is less work than one long session a week, and it keeps the conversations warm.

The best part is the losses. If a link disappears, it tells me which one, from which page, and who’s responsible for it. So the same day I can write to the person: you took our link down, what happened. A week later that conversation is impossible to have, because they’ve moved on and so have I.

When a swap is agreed, the placement is the easy end. Claude has Morgen’s knowledge base, Kai’s knowledge base and the Webflow MCP, so it writes the partner’s link into the right Morgen article, in the right paragraph, and I review and publish without ever opening Webflow.

Saying no is the job

106 of the 229 rows are dead. That ratio is the programme working, not failing.

Three rules, in the order I apply them.

Does the conversation survive a fact check. People open with a list of domains and inflated traffic and DR numbers. I run those through Ahrefs before replying. If the numbers don’t match, that’s the end of it, and not because of the numbers. Someone who opens with a false claim to get a better deal is not someone who’ll leave your link up in six months.

Is the site topically close. One offer was a domain that hosts QuickBooks for accountants. Real site, real traffic, real audience, and no reading of that where those people want an AI executive assistant. A link from there tells Google we’re adjacent to accounting software, which is a signal we don’t want. Being productivity-shaped isn’t automatically enough either. I’ve walked away from sites that qualified on every metric because the content was thin.

Is it an exchange, not an invoice. A lot of inbound is “we’ll place you for $200”. That’s a real market and I’m not in it. I say so before a price appears, not after.

Past those three, two checks have done most of the actual rejecting, and both are cheap.

Read the top ten organic keywords, never the traffic total. One DR 66 site with 51,000 monthly visits turned out to rank for movie piracy and gambling terms. Another had 272,000 visits, 266,000 of them on its own brand name, which tells you nothing about whether a link from it means anything.

Then fetch the page they’re proposing and read its outbound links. On one offer, 33 of the page’s 65 external links were nofollow, and they were exactly the ones a broker hands you. If a broker quotes an “original paragraph” they’ve written about us, grep the page for it. When it isn’t there, they’re mail-merging over a target list and have read none of it.

And then there’s the category those checks don’t catch, which is the one I care about most: a domain that passes everything, attached to a request that isn’t really the sender’s. Someone once asked me for a link to NordVPN. He didn’t work there. He had a commercial partnership with them, he owed them a link, and he was using our exchange to deliver it. Put every metric you like against that domain and it passes. The ask is still dishonest, because what I’d actually be doing is spending Morgen’s authority on someone else’s contract, in an article about an AI assistant, for readers who came for something entirely different. So the qualification step doesn’t only score the domain. It asks who is really asking and what they get out of it, and it flags the good-looking ones too.

This is the piece I’d copy first, before any of the outreach.

A partner saying the link is live and the link being live are two different claims, and Ahrefs lags by weeks, so the only reliable check is fetching the page and reading the HTML. A Python script does that for every link we’ve placed, and it’s the first thing the skill runs.

Terminal output of link_check.py: 55 live links across 49 domains, 64 of 66 dofollow, made up of 19 negotiated, 34 unasked-for and 2 editorial or directory. Three lost or stripped. Under Needs attention, one page returning 404 marked as not a loss, two links live but passing nothing because a page-level robots nofollow overrides the anchor, and three gone from the page. Under Changed since the last run, two links that could not be verified last time now read live, and two that were fine now read gone. Partner names and domains are blacked out.
Tonight's run, as it came out. Three links gone since the last one, and two that were unverifiable last time turned out to be fine. Partner names and domains blacked out.

It catches three things you cannot see in a browser.

A partner who keeps our paragraph, keeps the anchor words, and removes only the <a> tag. The page returns 200 at the same size it always did. One partner did exactly that, and nothing about the page looks wrong until you read the source.

A clean link on a page that carries noindex and nofollow in its head, which passes nothing at all. We have two of those, one of them on a domain with a DR of 91. The guest post is real, the link is real, and it’s worth zero. Sampling one article’s anchor before accepting a platform is not enough: read the page-level robots tag on the published URL.

And bot walls, which are the trap in the other direction. One domain answers a plain request with an 11 KB “One moment, please” page, another serves a truncated body on roughly one request in two. A single empty fetch is not a loss, so the script retries three times and reports those as unverifiable rather than gone. We once told a partner their link had been removed when it was fine. Now nothing gets reported to anyone until it has failed twice and I’ve opened it in a browser myself.

The rule I got backwards

When a link comes down and no explanation comes with it, my response is a seven-day notice, and if it doesn’t go back up, Morgen’s side comes down too.

That clock only starts when we placed first. If the partner published before us, our link is the payment for a delivery that already happened. It has no clock, it doesn’t come off if they later owe us something else, and it stays up even if their own editor removes theirs.

I got that backwards once, on 10 August, and threatened to pull a link that was paying a debt we’d already incurred. It cost real credibility with someone who had done nothing wrong. Now every outbound link in our ledger names the inbound placement it pays for, so the question can’t come up again.

Every number I quote gets re-pulled

The figure I give brokers is Morgen’s traffic, and it’s the one number they can check in ten seconds.

For weeks we quoted “around 39,000 organic visits a month” because that number sat in our playbook and nobody re-checked it. It was a 48% overstatement, and it went to every broker we spoke to. That’s the kind of error that ends a conversation with the honest ones and hands the dishonest ones an argument.

It got stranger after we fixed it. Ahrefs keeps recomputing its own history. The same call for the same past date has returned 26,000, then 36,700, then 42,100, then 46,400, and today it reads 30,600, with no change to the site behind it. So a figure copied forward can be wrong high or wrong low, and the only defence is to re-pull both sides of the trade on every run and quote what comes back today.

One small thing in the same family: DR is Ahrefs’ Domain Rating and DA is Moz’s Domain Authority. Different metric, different scale. Half the people you’ll talk to use Moz, and writing one when you mean the other quietly changes what you promised.

Is this against Google’s rules?

Worth answering rather than dodging, because Google’s link spam policy names “excessive link exchanges” in the same list as buying links.

Here’s my honest position. What I run is exchanges, never payment. Every placement has to make sense for the reader of the host page, which is why the VPN went in the bin and why I turn down sites that pass every metric with nothing worth reading on them. Anchors stay natural, “Kai” or “AI executive assistant”, never stuffed with the exact phrase we want to rank for. Where a partner can take a three-way placement, they get one. And I don’t hand anyone a list of our target pages and anchors: a broker who asks for one is a vendor, not a partner, and a list like that is what turns a link profile into a footprint.

I keep the receipts for all of it in the CSV, which also means a bad decision is on the record with my name against it. That’s the part that keeps me honest more reliably than any policy reading.

The grey is real and I’m not going to pretend otherwise. If Google decides tomorrow that this whole category is worthless, we lose the links and keep the articles, which is roughly the trade I made going in.

What it moved, and what I can’t prove yet

DR was 0 until the rebrand, then 16 on 13 April once the redirects from the old domain landed, 24 on 4 May, 29 through June, 31 in late July, 34 on 17 August, 39 on 31 August, 41 on 14 September. Referring domains went from 0 to 336, though a good share of that tail is throwaway .shop spam nobody asked for and all of it nofollow.

Now the part that doesn’t flatter the programme. Kai has 11 ranking keywords, 5 of them in the top 3, on about 26 organic visits a month. That is a tiny number. Referral traffic from the placed links exists and is also small.

And I can’t isolate the effect. DR is a lagging, whole-profile metric on a logarithmic scale, and Ahrefs re-indexes on its own schedule, so crediting a single placement for a jump is a story, not a measurement. The rebuild of how we work, the articles, the free tools and the links all landed in the same few months. What we’re actually buying is ranking, and the evidence I have for that is second-hand: on Morgen I’ve watched positions move within a week or two of links landing on a page. I’m betting the same mechanism works on a domain this young.

The directories are the other half and they’re still shut. G2, Capterra, Crunchbase and the rest want a launched product, not a beta. The accounts and the copy are prepared, and those links land the week we launch.

What I’d do with no Morgen to trade

If I started a company tomorrow with one new domain and nothing to offer, I wouldn’t run this.

I’d put the early effort into YouTube, Reddit and short-form video, which is also where AI answers increasingly get sourced from, and let search come in behind it. We worked with one creator who talked about Kai, and their video is now what you find when you search the product. A brand people mention earns links without asking, and that’s the version of this that actually scales.

The exchange programme is what you run when you have an asset sitting idle and a domain that needs a shove.

What I want it to do next

Work the Slack rooms on its own: read them, find the people whose domains actually fit, open the conversation and hand me the draft.

The replies stay mine. The whole filter is whether the person on the other end is negotiating honestly, and I’m not handing that judgement to a model.

Want to run this on your own product?

A prompt that asks about your product first, then adapts every step. Works in ChatGPT too.
  • Backlinks
  • SEO
  • Growth
  • Claude Code