Most write-ups about paid acquisition for developer tools are written by people selling paid acquisition for developer tools. This one is a record of money we spent and did not get back, published because the arithmetic underneath it is more useful than the result.
Here is the whole ledger.
| Platform | Spend | Impressions | Clicks | Signups |
|---|---|---|---|---|
| Microsoft Ads | $30.05 | 10,367 | 52 | 0 |
| Google Search | $67.63 | — | 14 | 0 |
| Total | $97.68 | — | 66 | 0 |
No paying customers came from either. We stopped both.
The number that ended the experiment
Google billed us $4.83 per click. That is the single most important figure here, because it is the one that makes the rest of the plan impossible rather than merely disappointing.
Run it forward. A $300 monthly budget at $4.83 a click buys about 62 clicks a month. Those clicks have to become signups first, and only some fraction of signups ever become paying customers — at which rate, we genuinely do not know, because 66 clicks produced zero signups and you cannot compute a conversion rate from a numerator of nothing. That is the actual finding, and it is worse than a bad rate: we bought a sample too small to measure anything with.
Pick any plausible funnel you like and the conclusion survives, because the first stage already failed. We did not learn that our landing page converts badly, or that our keywords were wrong, or that the price is too high. We learned nothing at all, which is precisely what $97.68 buys at this click price.
That is the real cost. Not the $97.68. The two months of attention spent watching a signal too small to read.
We had a kill-line and it never triggered
To our credit, the campaign was set up with a stopping rule written in advance: kill it at 150 clicks with zero signups. That is a sound instinct and we would do it again.
It did not help. At $4.83 a click, the $100 lifetime budget cap was always going to arrive at around 20 clicks — long before the 150-click kill-line could fire. The experiment was structurally incapable of reaching its own decision threshold. We had designed a test whose result was predetermined to be "inconclusive."
The lesson generalises past advertising: if your stopping rule is denominated in a unit your budget cannot buy enough of, you do not have a stopping rule. Check that the two numbers are compatible before you start. It takes one division.
The advice was already public, and we ran the ads anyway
Y Combinator's growth material is blunt about this. Gustaf Alströmer's Startup School talk puts it in six words: don't do paid growth if you don't have revenue.
We had no revenue. We ran paid growth. Reading that line and running the campaign anyway is a more interesting failure than not knowing, and worth being specific about the reasoning, because it is seductive: the budget was small, the downside looked capped, and a cheap test felt strictly better than no information. But a test that cannot reach significance is not information at a discount. It is a cost with a story attached.
A detour worth knowing about if you automate this
We build our own tooling, so the plan was to drive campaigns programmatically. Google's Ads API declines to serve non-test accounts until your Cloud project is granted access, and answers everything else with CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION. We applied in September. It has not been granted, and there is no published queue or ETA.
The way through, if you need one, is Google Ads Scripts — first-party, hosted inside the Ads account, no developer token and no access review. One structural consequence to design around: a script polls, so nothing can call into it. Your kill switch arrives at the next scheduled run, up to an hour later. The hard safety is the campaign's own budget, not your pause call. Set the budget as though the switch will be late, because it will be.
What we are doing instead
Paid search is off, and not as a pause waiting for a better quarter — the arithmetic does not improve until revenue does. The channels we are putting the same attention into are the ones that are free to enter and compound: directory and registry listings where a developer tool is discovered on purpose, documentation that answers questions people are already searching, and writing like this one.
This post exists partly to test a format. Every factual claim in it is registered with a source, verified before publishing, and re-checked on a schedule — the block above the article is generated from that record, not typed by hand. If one of these numbers stops being true, the post will say so at this same URL rather than quietly aging.
We would rather be publicly wrong on the record than privately right.