<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Axel Freeman </title>
    <description>The latest articles on DEV Community by Axel Freeman  (@axelfreeman).</description>
    <link>https://dev.to/axelfreeman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4049663%2F40d321c1-a6e5-4394-80c9-5bf88babea27.jpg</url>
      <title>DEV Community: Axel Freeman </title>
      <link>https://dev.to/axelfreeman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/axelfreeman"/>
    <language>en</language>
    <item>
      <title>A marketing playbook is the second step — almost nobody asks for it at the right time</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Tue, 22 Sep 2026 15:31:08 +0000</pubDate>
      <link>https://dev.to/axelfreeman/a-marketing-playbook-is-the-second-step-almost-nobody-asks-for-it-at-the-right-time-3ch0</link>
      <guid>https://dev.to/axelfreeman/a-marketing-playbook-is-the-second-step-almost-nobody-asks-for-it-at-the-right-time-3ch0</guid>
      <description>&lt;p&gt;Every week someone asks me for a marketing playbook. Almost nobody asking has a working hypothesis yet.&lt;/p&gt;

&lt;p&gt;That is the problem, and it is worth being blunt about it: &lt;strong&gt;a playbook is the second step, never the first.&lt;/strong&gt; Compiling one does not move you closer to sales. It is what you write &lt;em&gt;after&lt;/em&gt; something works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a playbook actually is
&lt;/h2&gt;

&lt;p&gt;A written set of client-acquisition moves that already work — simple, primitive, repeatable:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bought an ad from a blogger in segment A — it produced clients.&lt;br&gt;
Segment B gave the numbers in three months.&lt;br&gt;
This targeting converts a client at break-even or better.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One proven move, one line. Not a strategy deck, not a framework, not "our methodology". Instructions somebody can follow next Monday.&lt;/p&gt;

&lt;p&gt;You build it yourself, by hand, or with your two or three closest people. Nobody hands it to you — a borrowed playbook is a wish list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it is the second step
&lt;/h2&gt;

&lt;p&gt;The order is fixed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You find a working hypothesis &lt;strong&gt;by hand&lt;/strong&gt; (for most B2B that means cold outreach, free).&lt;/li&gt;
&lt;li&gt;You press it until you know where its ceiling is.&lt;/li&gt;
&lt;li&gt;Only then do you write it down — and what you write down is the playbook.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A playbook assembled before step 3 is a notebook of guesses, and the most expensive way to feel productive. If you have zero clients, the honest answer is not a playbook — it is that the job is still the search.&lt;/p&gt;

&lt;h2&gt;
  
  
  The moment a playbook changes anything
&lt;/h2&gt;

&lt;p&gt;Written down, the working moves stop being founder-only knowledge. They can be handed to a marketing hire, a department, any person who follows a procedure — or to an agent, if the work is genuinely repeatable.&lt;/p&gt;

&lt;p&gt;This is where the mode changes. Search is free exploration: hunt, guess, try the strange thing. Once you delegate a proven move, you leave free search behind and switch to &lt;strong&gt;regular management&lt;/strong&gt; — goals, volume, cadence, reporting. Draining a hypothesis to the bottom is not an exploration task, it is an operating task, and it needs the basics of regular management to survive contact with a schedule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The critical mass is around six working hypotheses.&lt;/strong&gt; At roughly six proven, repeatable moves there is something real to hand over, and you can hire marketing. Before that there is nothing to delegate — you would be hiring someone to keep guessing, which is what you were already doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part people get wrong: failed hypotheses
&lt;/h2&gt;

&lt;p&gt;A negative result gets one line in the archive: what was tried, and that the numbers were zero. Nothing more.&lt;/p&gt;

&lt;p&gt;Two practical reasons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There is nothing to learn from a zero.&lt;/strong&gt; Marketing — especially the first-clients stage — is not a mathematical craft yet. A zero does not tell you which variable was wrong, because you usually changed five things at once and the market did not answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Handing a new person your failures is toxic.&lt;/strong&gt; A marketer does not resume from the previous person's pause point — they start from zero. Old data genuinely gets in their way, and failed old data gets in the way worst of all. You will spend their first month arguing about a channel that died for reasons that no longer apply.&lt;/p&gt;

&lt;p&gt;Keep negative experiments as &lt;em&gt;historical context&lt;/em&gt; for whoever asks (an agent, a new hire) — a separate record, never a starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it as a command
&lt;/h2&gt;

&lt;p&gt;With the npm package installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx marketing-mindset playbook &lt;span class="nt"&gt;--hypotheses&lt;/span&gt; 0
&lt;span class="c"&gt;# stage: search    -&amp;gt; no proven move; the job is still the hunt&lt;/span&gt;

npx marketing-mindset playbook &lt;span class="nt"&gt;--hypotheses&lt;/span&gt; 3
&lt;span class="c"&gt;# stage: draining  -&amp;gt; write them down and press each to its ceiling&lt;/span&gt;

npx marketing-mindset playbook &lt;span class="nt"&gt;--hypotheses&lt;/span&gt; 7 &lt;span class="nt"&gt;--written&lt;/span&gt;
&lt;span class="c"&gt;# stage: delegate  -&amp;gt; there is something real to hand over; hire marketing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The one-line version
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find a working move by hand -&amp;gt; drain it -&amp;gt; write it down -&amp;gt; delegate it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full write-up with the rules and the archive policy: &lt;a href="https://axelfreeman.github.io/marketing-mindset/qa/what-is-a-marketing-playbook.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=mindset" rel="noopener noreferrer"&gt;What is a business sales and marketing playbook?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole mindset is open source (MIT) and installable as an agent skill: &lt;a href="https://github.com/axelfreeman/marketing-mindset" rel="noopener noreferrer"&gt;https://github.com/axelfreeman/marketing-mindset&lt;/a&gt;&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>growth</category>
      <category>startup</category>
      <category>saas</category>
    </item>
    <item>
      <title>Your B2B list is worth its address share, not its row count</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 10:16:23 +0000</pubDate>
      <link>https://dev.to/axelfreeman/your-b2b-list-is-worth-its-address-share-not-its-row-count-5717</link>
      <guid>https://dev.to/axelfreeman/your-b2b-list-is-worth-its-address-share-not-its-row-count-5717</guid>
      <description>&lt;p&gt;A 10,000-row list is not 10,000 chances to get a reply. It is however many of those rows publish an address on their own domain — and that second number is a property of the source, not of the file. We keep a working file of company domains and count that share for every source family we pull from. Here is what it looks like after 9,756 domains, 1,714 public addresses and one honest question: where did the domain come from?&lt;/p&gt;

&lt;h2&gt;
  
  
  Two ways to get a domain, and only one of them is clean
&lt;/h2&gt;

&lt;p&gt;A domain can be read out of text where someone mentioned their company, or read out of a field the company itself filled in a directory. The second one is cleaner by construction.&lt;/p&gt;

&lt;p&gt;On a job board the domain has to be dug out of the vacancy body. Roughly half of those attempts land on the job board itself, on a recruiting platform, or on a company already in the file. On an application marketplace or a package registry the domain is a named field filled by the vendor, and the reject rate drops to single digits.&lt;/p&gt;

&lt;p&gt;Our largest single pass came from an application marketplace: &lt;strong&gt;3,000 applications → 2,377 new domains → 1,798 live sites with product signals (76%) → 1,538 rows kept (65%)&lt;/strong&gt;. The filter that did the cutting was not a blacklist but a product test: pricing, a sign-up, a demo request, integrations. Documentation sites, personal pages and framework homepages go out there.&lt;/p&gt;

&lt;h2&gt;
  
  
  The field that gave the domain gave nothing else
&lt;/h2&gt;

&lt;p&gt;Those 1,538 rows came with an address share of &lt;strong&gt;zero&lt;/strong&gt;. The field is a website, not a contact. We had grown the file by 1,538 rows and the number of sendable rows by nothing at all — which is exactly the trap of measuring a campaign by file size.&lt;/p&gt;

&lt;p&gt;So we stopped counting domains and started walking sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  300 "contactless" rows, walked
&lt;/h2&gt;

&lt;p&gt;We took 300 rows with no address and opened the pages companies publish for contact: home page, &lt;code&gt;/contact&lt;/code&gt;, &lt;code&gt;/about&lt;/code&gt;, an imprint page where the law requires one. Only addresses whose domain matched the company's own domain were kept.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rows walked&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domains with a published address on their own site&lt;/td&gt;
&lt;td&gt;172&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kept after the address-to-domain rule&lt;/td&gt;
&lt;td&gt;169&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Answering MX&lt;/td&gt;
&lt;td&gt;169 of 169&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spot-check against the live page&lt;/td&gt;
&lt;td&gt;4 of 4 confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A source that looks contactless at intake is more than half contactable if you read the pages the company actually maintains. The three rejected addresses are the other half of the rule: one mis-split token and two strings that only looked like addresses in raw HTML. They were dropped, not repaired. An address that has to be guessed is not a contact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yield by source family
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where the domain came from&lt;/th&gt;
&lt;th&gt;Domains taken&lt;/th&gt;
&lt;th&gt;Live with product signals&lt;/th&gt;
&lt;th&gt;Rows kept&lt;/th&gt;
&lt;th&gt;Publish an address&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Application marketplaces (vendor-filled &lt;code&gt;external_url&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;td&gt;1,798 (76%)&lt;/td&gt;
&lt;td&gt;1,538 (65%)&lt;/td&gt;
&lt;td&gt;0% at intake → 56% after walking contact pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agency directories&lt;/td&gt;
&lt;td&gt;59 hosts per pass&lt;/td&gt;
&lt;td&gt;full pass&lt;/td&gt;
&lt;td&gt;492&lt;/td&gt;
&lt;td&gt;~60%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Package registries (&lt;code&gt;projectUrl&lt;/code&gt;, &lt;code&gt;homepage_uri&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;3,821&lt;/td&gt;
&lt;td&gt;140 (29%)&lt;/td&gt;
&lt;td&gt;140&lt;/td&gt;
&lt;td&gt;~15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository &lt;code&gt;homepage&lt;/code&gt; (GitHub repos and orgs)&lt;/td&gt;
&lt;td&gt;2,429&lt;/td&gt;
&lt;td&gt;553&lt;/td&gt;
&lt;td&gt;553&lt;/td&gt;
&lt;td&gt;~11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WordPress.org (plugin homepage, theme author URL)&lt;/td&gt;
&lt;td&gt;9,785&lt;/td&gt;
&lt;td&gt;600 of 695 themes&lt;/td&gt;
&lt;td&gt;486 plugins + 490 theme authors&lt;/td&gt;
&lt;td&gt;~34% for theme authors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job-description text (boards, "who is hiring")&lt;/td&gt;
&lt;td&gt;~1,100 vacancies&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;8 of 16 confirmed&lt;/td&gt;
&lt;td&gt;half the rows never reach the contact step&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Theme authors sit in between, and for a reason: 8,695 themes in the WordPress.org directory resolve to 729 unique author domains, and a theme shop is a company selling a product, so it publishes pricing, support and a contact page — 600 of 695 answered, 490 were kept, and a third of those handed over an address.&lt;/p&gt;

&lt;p&gt;That table is the whole argument. A vendor who sells you 10,000 rows is selling you the left column; the column that decides whether the list is work or decoration is the right one. At 11% the same file is 1,100 addresses, at 56% it is 5,600.&lt;/p&gt;

&lt;h2&gt;
  
  
  How each row is counted
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Domain from a filled field.&lt;/strong&gt; No row enters without a domain that belongs to the company and a URL where it was published.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live site with product signals.&lt;/strong&gt; A 200 is not enough: pricing, sign-up, demo request or integrations must be present.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address matched to its own domain.&lt;/strong&gt; A role address on someone else's domain is not a contact for that company, however it appeared on the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MX before sending.&lt;/strong&gt; Every address domain answers MX; the ones that do not are marked, not hidden.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The reject reason is kept.&lt;/strong&gt; Removed rows stay in a reject file with the reason, which is how the numbers above can be checked.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Three questions for a list vendor
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What share of rows publish an address on their own domain — not "has a contact field"?&lt;/li&gt;
&lt;li&gt;How many domains answer MX, and what happened to the ones that did not?&lt;/li&gt;
&lt;li&gt;Which addresses came from a field the company filled, and which were assembled by a tool?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A vendor who cannot answer the third question is selling the 0% column. Building the file is not romantic work; it is counting, and then walking the pages.&lt;/p&gt;

&lt;p&gt;The full method, the checks and the numbers are on the site: &lt;a href="https://axelfreeman.com/contact-data-source-yield.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=source-yield" rel="noopener noreferrer"&gt;The address is the only number that matters in a B2B list&lt;/a&gt; — that page also carries the six list checks and the pre-send audit, in case your file is fine and your sending is not.&lt;/p&gt;

</description>
      <category>b2b</category>
      <category>sales</category>
      <category>marketing</category>
      <category>growth</category>
    </item>
    <item>
      <title>Deliverability is a list problem before it is a sending problem</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 09:56:10 +0000</pubDate>
      <link>https://dev.to/axelfreeman/deliverability-is-a-list-problem-before-it-is-a-sending-problem-5eob</link>
      <guid>https://dev.to/axelfreeman/deliverability-is-a-list-problem-before-it-is-a-sending-problem-5eob</guid>
      <description>&lt;p&gt;Most outbound teams I look at have bought their infrastructure before they have looked at the list. Domains, mailboxes,&lt;br&gt;
warm-up calendars, sending tools, a spreadsheet of sequences. The list — the thing that decides whether the first day of&lt;br&gt;
a campaign produces replies or complaints — is checked last, if at all.&lt;/p&gt;

&lt;p&gt;Authentication is the cheapest check in the stack: SPF, DKIM, a DMARC policy, a live address for the aggregate reports.&lt;br&gt;
Google and Yahoo made it a requirement for bulk senders rather than a competitive edge, together with a complaint rate&lt;br&gt;
under 0.3% and one-click unsubscribe. An afternoon of DNS work, and it is done.&lt;/p&gt;

&lt;p&gt;After that, the failures stop announcing themselves. They arrive as bounces, as complaints, as a reply rate that looks&lt;br&gt;
like a market problem but is a list problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The nine checks, in the order that removes risk
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SPF and DKIM alignment&lt;/strong&gt; — both records exist and the sending domain matches the From domain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DMARC policy and reporting&lt;/strong&gt; — a published policy with reports going somewhere a person reads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracking-domain separation&lt;/strong&gt; — clicks are rewritten to a CNAME on your own domain, not a shared vendor host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One domain, one purpose&lt;/strong&gt; — cold outreach, marketing and transactional mail on separate subdomains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root-domain folding&lt;/strong&gt; — everything folded to the registrable domain before counting, or one company appears four
times as &lt;code&gt;www&lt;/code&gt;, as &lt;code&gt;app&lt;/code&gt;, as a regional subdomain and as the root.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MX check per domain&lt;/strong&gt; — a domain with no mail exchanger cannot receive the email being prepared for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address-to-domain match&lt;/strong&gt; — the address must belong to the domain it is filed under. This is the check that
removes &lt;code&gt;hello@world.com&lt;/code&gt; and addresses lifted from another company's page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role and pattern rejection&lt;/strong&gt; — &lt;code&gt;info@&lt;/code&gt;, &lt;code&gt;support@&lt;/code&gt;, &lt;code&gt;noreply@&lt;/code&gt; separated rather than sent to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suppression and send caps&lt;/strong&gt; — unsubscribes, bounces and previous non-replies subtracted before the batch is built,
and a per-domain cap so the same company is not hit twice in a week.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What the numbers look like
&lt;/h2&gt;

&lt;p&gt;These are our own prospecting numbers, not a client's. The working file holds 9,266 company domains, refreshed&lt;br&gt;
19 September 2026. 1,358 of them carry a public address at all — 15%. Behind those addresses sit 1,358 domains, of&lt;br&gt;
which 1,350 answer an MX lookup. The eight that do not would have gone out as part of a "verified" list.&lt;/p&gt;

&lt;p&gt;The gap between 9,266 and 1,358 is the part people skip. Domain count is a sourcing metric. Address count is a sending&lt;br&gt;
metric. They differ by a factor of seven.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the rows come from matters more than how many
&lt;/h2&gt;

&lt;p&gt;Same checks, same budget, four source families, and the share of kept rows that carry a public address:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;agency directories — &lt;strong&gt;60%&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;package registries (NuGet, RubyGems, npm) — &lt;strong&gt;15%&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;GitHub repository homepages — &lt;strong&gt;11%&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;hiring feeds (Arbeitnow, HN &lt;em&gt;Who is hiring&lt;/em&gt;) — &lt;strong&gt;11%&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An agency site is built to be contacted. An open-source project page links GitHub, not a sales team. The extraction rule&lt;br&gt;
is identical in all four cases — take the domain from the post, never from the text — so the difference is the source,&lt;br&gt;
not the method.&lt;/p&gt;

&lt;p&gt;Yesterday's run added a new family to the file: application marketplaces. The Zapier directory exposes each app with a&lt;br&gt;
structured vendor URL, which makes it the cleanest version of the rule so far. 3,000 applications gave 2,377 domains&lt;br&gt;
that were not already in the file, 1,798 of them answered with a live site showing at least two product signals (76%),&lt;br&gt;
and 1,538 survived once the threshold went to three signals (65%). That single pass was larger than any directory gave&lt;br&gt;
us in a day — and it is also the weakest family on contacts, because the field is a website, not a mailbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit is a set of files, not an opinion
&lt;/h2&gt;

&lt;p&gt;What comes out: an authentication report per sending domain, an MX report, three reject files (no MX, address-domain&lt;br&gt;
mismatch, placeholder or role), a send plan with batch sizes and caps, a suppression list, and one call on the numbers.&lt;br&gt;
Nothing in it is a promise about replies. A clean list removes bounces and complaints; whether a segment replies is a&lt;br&gt;
question about the offer, and that is what a pilot is for.&lt;/p&gt;

&lt;p&gt;The nine checks are written out, with the measured yields and the reject files, here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://axelfreeman.com/cold-email-deliverability-audit.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=deliverability" rel="noopener noreferrer"&gt;Cold email deliverability audit — nine checks before the first send&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>emailmarketing</category>
      <category>marketing</category>
      <category>b2b</category>
      <category>sales</category>
    </item>
    <item>
      <title>The reject file: every row my B2B list threw away, and the check that killed it</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 09:30:20 +0000</pubDate>
      <link>https://dev.to/axelfreeman/the-reject-file-every-row-my-b2b-list-threw-away-and-the-check-that-killed-it-58dd</link>
      <guid>https://dev.to/axelfreeman/the-reject-file-every-row-my-b2b-list-threw-away-and-the-check-that-killed-it-58dd</guid>
      <description>&lt;h1&gt;
  
  
  The reject file: every row my B2B list threw away, and the check that killed it
&lt;/h1&gt;

&lt;p&gt;A list is usually sold by what is in it. This is a post about what came out of mine, and why — because the count that&lt;br&gt;
survives the checks is the only number you can audit, while "100% verified" is a number you can only believe.&lt;/p&gt;

&lt;p&gt;I keep one working file for outbound segments. As of today it holds &lt;strong&gt;7 728 company domains&lt;/strong&gt; collected from&lt;br&gt;
&lt;strong&gt;49 public sources&lt;/strong&gt;, of which &lt;strong&gt;1 381&lt;/strong&gt; publish an address of their own (18%), and &lt;strong&gt;1 350 of the 1 358&lt;/strong&gt; domains behind&lt;br&gt;
those addresses answer an MX lookup right now. Everything below is counted from that file, not estimated.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that decides everything: where the domain comes from
&lt;/h2&gt;

&lt;p&gt;Before any technical check, one sourcing rule does most of the work. A domain enters the file only if it sits in a field&lt;br&gt;
the owner filled in about itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a company directory's &lt;code&gt;website&lt;/code&gt; field,&lt;/li&gt;
&lt;li&gt;a package's &lt;code&gt;projectUrl&lt;/code&gt; (NuGet) or &lt;code&gt;homepage_uri&lt;/code&gt; (RubyGems), &lt;code&gt;homepage&lt;/code&gt; (npm, crates.io),&lt;/li&gt;
&lt;li&gt;a repository's homepage field,&lt;/li&gt;
&lt;li&gt;a launch post's canonical URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A domain dug out of the body of a job ad or a sentence in a post is &lt;em&gt;inferred&lt;/em&gt;, and inference is where invented&lt;br&gt;
addresses come from. Job feeds are the clearest example: the vacancy mentions the employer, a customer, an ATS and a&lt;br&gt;
cloud host in the same paragraph, and half the candidate domains have to be thrown away by hand. Hiring threads yield&lt;br&gt;
addresses about &lt;strong&gt;11%&lt;/strong&gt; of the time. Package registries, the same idea one ecosystem over, yield &lt;strong&gt;15%&lt;/strong&gt;. Agency and&lt;br&gt;
SaaS catalogues yield &lt;strong&gt;60%&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The six checks, in this order
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Domain from a structured field.&lt;/strong&gt; As above. No field, no row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fold to the root, then de-duplicate.&lt;/strong&gt; &lt;code&gt;blog.&lt;/code&gt;, &lt;code&gt;app.&lt;/code&gt;, &lt;code&gt;shop.&lt;/code&gt; and &lt;code&gt;demo.&lt;/code&gt; subdomains collapse into one company,
otherwise a single vendor arrives as four rows. After folding: 7 728 rows, 7 728 unique domains, zero rows without a
domain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fetch the host live.&lt;/strong&gt; Not answering &lt;code&gt;200&lt;/code&gt; on HTTPS and then HTTP means it is dropped — parked domains and dead
projects included. Cheapest filter, biggest pile of removed weight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does the site behave like a product company?&lt;/strong&gt; At least two of: pricing or plans, sign-up or free trial, a
"book a demo" or "contact sales" path, integrations or API documentation. This is what keeps blogs, documentation
sites and academic pages out of a B2B segment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does the address belong to the domain it sits on?&lt;/strong&gt; Addresses are kept only when the mail domain matches the site
they were found on, or a subdomain of it. Agency catalogue pages publish third-party addresses and placeholders like
&lt;code&gt;hello@world.com&lt;/code&gt; often enough that this check is not optional — a row with someone else's address is a complaint
scheduled for later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does the domain answer for its mail?&lt;/strong&gt; An MX lookup. Of the 1 358 domains behind published addresses, 1 350 answer
and 8 do not; those rows are marked and kept out of batches rather than counted as contacts.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What each family yields, measured instead of claimed
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Family of sources&lt;/th&gt;
&lt;th&gt;Rows&lt;/th&gt;
&lt;th&gt;Published an address&lt;/th&gt;
&lt;th&gt;Yield&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agency and SaaS directories&lt;/td&gt;
&lt;td&gt;876&lt;/td&gt;
&lt;td&gt;522&lt;/td&gt;
&lt;td&gt;60%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Company directories (YC dump)&lt;/td&gt;
&lt;td&gt;548&lt;/td&gt;
&lt;td&gt;265&lt;/td&gt;
&lt;td&gt;48%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Package registries&lt;/td&gt;
&lt;td&gt;328&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Launch feeds and product posts&lt;/td&gt;
&lt;td&gt;745&lt;/td&gt;
&lt;td&gt;88&lt;/td&gt;
&lt;td&gt;12%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hiring threads and job feeds&lt;/td&gt;
&lt;td&gt;4 012&lt;/td&gt;
&lt;td&gt;432&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository homepage fields&lt;/td&gt;
&lt;td&gt;553&lt;/td&gt;
&lt;td&gt;59&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things only show up because the table is published.&lt;/p&gt;

&lt;p&gt;First, the ecosystems are not comparable. Directories built for selling arrive with the contact already on the page;&lt;br&gt;
hiring feeds are written to attract candidates, not to be harvested.&lt;/p&gt;

&lt;p&gt;Second, a structured field is a guarantee about the &lt;em&gt;domain&lt;/em&gt;, not about the &lt;em&gt;contact&lt;/em&gt;. Repository homepages come from a&lt;br&gt;
field its owner filled in and still yield 11% — a package registry's &lt;code&gt;projectUrl&lt;/code&gt; yields 15%, an agency directory 60%.&lt;br&gt;
If you buy rows by the thousand, the family they came from is a better predictor of what reaches a human than the word&lt;br&gt;
"verified" on the invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reject file
&lt;/h2&gt;

&lt;p&gt;What fails is not deleted. It is written out with a reason column, so the count can be audited instead of trusted, and&lt;br&gt;
it comes in three parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dropped at sourcing&lt;/strong&gt; — the domain was not in a structured field, or the host never answered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dropped at the product test&lt;/strong&gt; — the site behaves like a blog, a docs site or another directory rather than a vendor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dropped at the mail test&lt;/strong&gt; — no MX, or an address belonging to a different domain than the page it was found on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reject file is handed over with the segment. A batch is built from the working file, and a row that is not in the&lt;br&gt;
file is not in the batch — no purchased lists are mixed in, because a purchased row has no source column to audit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I do with this
&lt;/h2&gt;

&lt;p&gt;I build outbound segments for SaaS teams, agencies and local B2B companies, and the reject file is part of the&lt;br&gt;
deliverable. The checks above, the yield table, and the three reject lists are published on&lt;br&gt;
&lt;a href="https://axelfreeman.com/lead-list-verification.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=reject-file" rel="noopener noreferrer"&gt;the verification page&lt;/a&gt;,&lt;br&gt;
together with the current numbers of the working file. If you want the same six checks run against a list you already&lt;br&gt;
own, that is the fastest way to find out whether it is worth sending at all — and the&lt;br&gt;
&lt;a href="https://axelfreeman.com/pricing.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=reject-file" rel="noopener noreferrer"&gt;scopes and prices&lt;/a&gt;&lt;br&gt;
are published the same way: $900 for the fourteen-day pilot, $1 900/month for the ongoing engine, $2 900 for the full&lt;br&gt;
build.&lt;/p&gt;

&lt;p&gt;One line to take away, whether or not you hire anyone: measure a list by what it throws out. The proportion that&lt;br&gt;
survives six checks is a fact about the file. "Verified" is a fact about the seller's confidence.&lt;/p&gt;

</description>
      <category>b2b</category>
      <category>marketing</category>
      <category>sales</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>The fourteen days of an outbound pilot, written down before you pay</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 08:58:35 +0000</pubDate>
      <link>https://dev.to/axelfreeman/the-fourteen-days-of-an-outbound-pilot-written-down-before-you-pay-301a</link>
      <guid>https://dev.to/axelfreeman/the-fourteen-days-of-an-outbound-pilot-written-down-before-you-pay-301a</guid>
      <description>&lt;h1&gt;
  
  
  The fourteen days of an outbound pilot, written down before you pay
&lt;/h1&gt;

&lt;p&gt;Most pilots are sold as a wager: give us money, give us a month, and we will see what happens. The wager is not the&lt;br&gt;
problem. The problem is that nothing in the arrangement lets you check the work while it is being done, and nothing in&lt;br&gt;
the read-out lets you tell a bad segment from bad copy. So here is the pilot I run, day by day, before anyone pays for&lt;br&gt;
it — and the numbers each day actually produces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Days 1–3: where the domain comes from
&lt;/h2&gt;

&lt;p&gt;A segment is only as honest as the field the domain was read out of. That is the rule I hold to, and it is stricter&lt;br&gt;
than it sounds: the domain has to sit in a field its owner filled in, not be extracted from prose.&lt;/p&gt;

&lt;p&gt;The best version of that rule is a package registry. A library's &lt;code&gt;projectUrl&lt;/code&gt; on NuGet or its &lt;code&gt;homepage_uri&lt;/code&gt; on&lt;br&gt;
RubyGems is written by the vendor about itself, and it is machine-readable, which means it can be audited rather than&lt;br&gt;
trusted. The last pass over two registries looked at &lt;strong&gt;483 candidate domains&lt;/strong&gt; and found &lt;strong&gt;138 live sites that passed a&lt;br&gt;
product test&lt;/strong&gt; (pricing, a signup path, a demo request, integrations) — a 29% survival rate.&lt;/p&gt;

&lt;p&gt;Compare that with a job feed, where the company domain has to be dug out of the body of a vacancy. On hiring threads&lt;br&gt;
the same pipeline yields about 11%. The rows are not worse because job posts are dishonest; they are worse because the&lt;br&gt;
domain is inferred rather than declared. Inference is where invented addresses come from.&lt;/p&gt;

&lt;p&gt;The working file now holds &lt;strong&gt;7,641 company domains from 48 public sources&lt;/strong&gt;, and &lt;strong&gt;1,355 of them publish an address&lt;/strong&gt;&lt;br&gt;
(18%). That last number is the one I would want if I were buying: the majority of companies with a live product site do&lt;br&gt;
not publish an email address on it, so a list sold as "100% verified" is either smaller than claimed or has been&lt;br&gt;
completed by guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Days 3–5: verification, and what is handed back
&lt;/h2&gt;

&lt;p&gt;Verification is not a single check. It is a sequence, and each step drops rows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Domains folded to their root, so a blog or an app subdomain does not become a second company.&lt;/li&gt;
&lt;li&gt;Duplicates collapsed on the root domain, not on the string.&lt;/li&gt;
&lt;li&gt;Rows without a domain dropped outright — no domain, no row.&lt;/li&gt;
&lt;li&gt;Each host fetched live. A 404 is a dead company, not an unverified one.&lt;/li&gt;
&lt;li&gt;Each address matched to the domain it claims to sit on. &lt;code&gt;hello@takt.com&lt;/code&gt; on the page of &lt;code&gt;taktstudios.ca&lt;/code&gt; is not an
address for the company on the page.&lt;/li&gt;
&lt;li&gt;An SMTP check before anything is sent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What does not survive is not deleted quietly. It is handed over as a separate file with the reason attached: which step&lt;br&gt;
dropped the row, and what the row looked like when it went in. An agency reselling this needs that file more than it&lt;br&gt;
needs the good rows, because it is the only way to explain to a client why the count changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Days 5–7: the domain that is not the main domain
&lt;/h2&gt;

&lt;p&gt;Sending happens from a separate domain, warmed in the open, with SPF, DKIM and DMARC in place. This is the part of the&lt;br&gt;
pilot that is deliberately not clever: if deliverability is going to be damaged, it gets damaged in a domain built for&lt;br&gt;
outbound, never in the one the company answers email on.&lt;/p&gt;

&lt;p&gt;The infrastructure is the deliverable here, not a service you rent forever. Records, warm-up history and the sending&lt;br&gt;
domain stay with the client at the end of the fourteen days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Days 7–14: one batch and a read-out that does not flatter
&lt;/h2&gt;

&lt;p&gt;One segment, one batch, replies worked as they arrive. The read-out counts replies and conversations. It does not count&lt;br&gt;
opens, and it does not report an "engagement rate" assembled from pixels.&lt;/p&gt;

&lt;p&gt;It also does not promise meetings. A pilot is a measured test: if the reply rate is zero, the read-out says zero and&lt;br&gt;
then says which family the segment came from, how many addresses survived the SMTP check, what was delivered and what&lt;br&gt;
bounced. A zero with a reason beats a promised pipeline with none, and it costs less to find out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the pilot is not
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Not a guarantee of meetings. Reply rate depends on the segment and the offer, and it is measured rather than assumed.&lt;/li&gt;
&lt;li&gt;Not sending from your main domain.&lt;/li&gt;
&lt;li&gt;Not a scraped list with invented addresses.&lt;/li&gt;
&lt;li&gt;Not a retainer in disguise: fourteen days, one batch, one read-out, then a separate decision.&lt;/li&gt;
&lt;li&gt;Not a channel that reads your inbox — replies arrive at an address you can see at any time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What you hold at the end is a verified segment with its source column intact, a warmed domain in your name, the copy&lt;br&gt;
that went out, and the method. That is the deliverable. Meetings are the outcome, and they are earned rather than&lt;br&gt;
promised.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The pilot is published at $900, written down day by day, here:&lt;br&gt;
&lt;a href="https://axelfreeman.com/outbound-pilot.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=pilot-page" rel="noopener noreferrer"&gt;the $900 outbound pilot&lt;/a&gt;.&lt;br&gt;
The three scopes and prices are on &lt;a href="https://axelfreeman.com/pricing.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=pilot-page" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;,&lt;br&gt;
and the sourcing rule behind the numbers is described in &lt;a href="https://axelfreeman.com/b2b-lead-list-building.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=pilot-page" rel="noopener noreferrer"&gt;B2B lead list building&lt;/a&gt;.&lt;br&gt;
The Telegram link on any of those pages is prefilled if you want the first segment priced.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>sales</category>
      <category>b2b</category>
      <category>startup</category>
    </item>
    <item>
      <title>White-label lead generation: an agency should buy capacity, not lists</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 08:42:20 +0000</pubDate>
      <link>https://dev.to/axelfreeman/white-label-lead-generation-an-agency-should-buy-capacity-not-lists-2o0l</link>
      <guid>https://dev.to/axelfreeman/white-label-lead-generation-an-agency-should-buy-capacity-not-lists-2o0l</guid>
      <description>&lt;h1&gt;
  
  
  White-label lead generation: an agency should buy capacity, not lists
&lt;/h1&gt;

&lt;p&gt;Every agency I have watched buy data has bought the wrong thing. Not a bad list — the wrong &lt;em&gt;unit&lt;/em&gt;. A list is an&lt;br&gt;
inventory purchase: you pay for rows, you discover on the first send which ones were real, and the discovery cost&lt;br&gt;
arrives as bounces on a client's sending domain. Capacity is a different unit of purchase. You buy a production run&lt;br&gt;
with a known failure rate, and the failure rate is measured before the send.&lt;/p&gt;

&lt;p&gt;That distinction is the whole partner conversation, and it is countable, so let me count it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The file this is built on
&lt;/h2&gt;

&lt;p&gt;Working file as of 19 September 2026: &lt;strong&gt;7,503 company domains&lt;/strong&gt; collected from &lt;strong&gt;46 public sources&lt;/strong&gt;, of which&lt;br&gt;
&lt;strong&gt;1,305&lt;/strong&gt; have a public address on the company's own pages or in the listing itself. The file was assembled with one rule that decides everything downstream:&lt;br&gt;
a domain comes from a &lt;em&gt;structured field&lt;/em&gt; — an API website field, a hiring post's own URL, a catalogue's outbound&lt;br&gt;
link — never from the body text of a post. A row without a domain is dropped rather than guessed.&lt;/p&gt;

&lt;p&gt;The second rule is that nothing ships unchecked. Every host gets requested live and has to answer with product&lt;br&gt;
signals (pricing, signup, demo, trial) before the row stays. Every address has to sit on the domain it claims. The&lt;br&gt;
address is SMTP-checked before the send. In practice that pass removes roughly a third of a purchased list — and&lt;br&gt;
agencies keep asking me to leave that third in, because a bigger number looks better in a proposal. It does not&lt;br&gt;
look better three weeks later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yield by source family is the number that matters
&lt;/h2&gt;

&lt;p&gt;Different source families fail at very different rates, and that difference is what an agency should be buying on:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source family&lt;/th&gt;
&lt;th&gt;Rows kept&lt;/th&gt;
&lt;th&gt;With a published address&lt;/th&gt;
&lt;th&gt;Yield&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agency directories&lt;/td&gt;
&lt;td&gt;492&lt;/td&gt;
&lt;td&gt;492&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hiring threads ("Who is hiring", 2024 → Sep 2026)&lt;/td&gt;
&lt;td&gt;2,792&lt;/td&gt;
&lt;td&gt;304&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YC company directory (website field)&lt;/td&gt;
&lt;td&gt;548&lt;/td&gt;
&lt;td&gt;265 (pulled from the companies' own pages)&lt;/td&gt;
&lt;td&gt;48%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Agency directories come in at 100% because the listing itself publishes the contact row — the directory's business&lt;br&gt;
model &lt;em&gt;is&lt;/em&gt; publishing an address. Hiring threads sit at 11% because a job post carries a domain and no mailbox; you&lt;br&gt;
get a company to research, not a person to write to. The YC directory gives 548 valid companies in a single pull and ships no contact field at all — the 265 addresses&lt;br&gt;
below that line were collected afterwards from those companies' own pages, which is exactly the shape of a source you&lt;br&gt;
use for reach first and contactability second.&lt;/p&gt;

&lt;p&gt;If an agency is buying volume by the row, it is buying the 11% column and calling it 100%. That is the entire reason&lt;br&gt;
white-label production runs beat list purchases: the yield is measured per family, before the client sees anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a partner run actually contains
&lt;/h2&gt;

&lt;p&gt;The four steps are the same whether the end client is a SaaS company, an agency's client, or a local B2B:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Segment from public structured sources.&lt;/strong&gt; Families above, with the source column preserved so a later audit
can answer "where did this row come from" without asking me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify before anything is sent.&lt;/strong&gt; Live host check, address-to-domain match, SMTP check, and a separate file for
what did not survive — so the count change can be explained to the client instead of hidden from them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send under the agency's brand.&lt;/strong&gt; Sending domains, mailboxes, throttling and warm-up belong to the client
relationship, not to the vendor. Copy is written to the segment; the reply loop is worked, not just opened.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A read-out that can be forwarded.&lt;/strong&gt; Sent, delivered, replies, positive replies, booked conversations, per
segment, with the raw rows attached as CSV and JSON.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nothing in that list is exotic. The part agencies actually buy is that all four are already built and measured, so a&lt;br&gt;
client promise that needs 2,000 more touches this month does not require hiring or a migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pricing model, published
&lt;/h2&gt;

&lt;p&gt;This is the part that usually stays hidden behind a "book a call" button, and it is the reason this post exists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;$900&lt;/strong&gt; — one-off Sprint: one segment, verification pass, copy, sends, first read-out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$1,900/month&lt;/strong&gt; — Engine: a monthly loop, new segment each cycle, replies worked, forwardable read-out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$2,900&lt;/strong&gt; — Full Build: the machinery as the deliverable, handed over so an in-house team runs it afterwards.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the cost basis for a white-label run, not a reseller licence fee with a markup ladder on top. An agency&lt;br&gt;
invoices its client at its own price; the margin between that and the cost basis is the agency's, and there is no&lt;br&gt;
separate "partner tier" priced above the public number. Exclusivity is per vertical and per sending domain, agreed in&lt;br&gt;
one line before the first run, because the sending domain is the part that actually collides.&lt;/p&gt;

&lt;h2&gt;
  
  
  The uncomfortable honest part
&lt;/h2&gt;

&lt;p&gt;Bounces are not a guarantee anybody can make. They depend on the sending domain, the daily volume and the age of the&lt;br&gt;
row. What can be guaranteed is the method: check before the send, match the address to its own domain, feed every&lt;br&gt;
bounce back into the file. An agency that has been sold a bounce-rate promise has been sold something the vendor does&lt;br&gt;
not control — and when it fails, the agency is the one standing in front of the client.&lt;/p&gt;

&lt;p&gt;Buy capacity with a measured failure rate. It is a smaller number and a longer relationship.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cost basis, scope and the three plug-in modes are published here:&lt;br&gt;
&lt;a href="https://axelfreeman.com/agency-partner-program.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=agency-partner" rel="noopener noreferrer"&gt;agency partner program&lt;/a&gt;&lt;br&gt;
— and the engagement itself is described at&lt;br&gt;
&lt;a href="https://axelfreeman.com/marketing-engineer.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=agency-partner" rel="noopener noreferrer"&gt;marketing engineer&lt;/a&gt;.&lt;br&gt;
If you run an agency and want the first segment priced, the Telegram link on either page is prefilled.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>agency</category>
      <category>b2b</category>
      <category>sales</category>
    </item>
    <item>
      <title>I enriched 6,955 company domains. Only 1,040 of them publish an address</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 08:07:14 +0000</pubDate>
      <link>https://dev.to/axelfreeman/i-enriched-6955-company-domains-only-1040-of-them-publish-an-address-2kj4</link>
      <guid>https://dev.to/axelfreeman/i-enriched-6955-company-domains-only-1040-of-them-publish-an-address-2kj4</guid>
      <description>&lt;h1&gt;
  
  
  I enriched 6,955 company domains. Only 1,040 of them publish an address
&lt;/h1&gt;

&lt;p&gt;Six thousand nine hundred fifty-five company domains, forty-five public sources, one working day. That is the&lt;br&gt;
file behind this post. The number worth arguing about is not the total — it is &lt;strong&gt;1,040&lt;/strong&gt;: the rows where the&lt;br&gt;
company itself published an address you can write to. Fifteen percent.&lt;/p&gt;

&lt;p&gt;That gap is the whole business of B2B data enrichment, and most vendors fill it with the wrong thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the domains came from, and what each family actually yields
&lt;/h2&gt;

&lt;p&gt;Every row in the file carries its source and the live check it passed. Counted row by row, not estimated:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source family&lt;/th&gt;
&lt;th&gt;Domains&lt;/th&gt;
&lt;th&gt;Published an address&lt;/th&gt;
&lt;th&gt;Yield&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hacker News "Who is hiring?" threads (2024 → Sep 2026)&lt;/td&gt;
&lt;td&gt;2,792&lt;/td&gt;
&lt;td&gt;304&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Y Combinator open-source hiring directory&lt;/td&gt;
&lt;td&gt;736&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;remoteintech/remote-jobs public catalog&lt;/td&gt;
&lt;td&gt;531&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agency directories (DAN / Semrush listings)&lt;/td&gt;
&lt;td&gt;492&lt;/td&gt;
&lt;td&gt;492&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show HN launches — domain taken from the post URL&lt;/td&gt;
&lt;td&gt;407&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SaaSHub category listings (catalog outbound link)&lt;/td&gt;
&lt;td&gt;351&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WordPress plugin directory homepage fields&lt;/td&gt;
&lt;td&gt;350&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub repository and organisation website fields&lt;/td&gt;
&lt;td&gt;466&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dev.to posts whose canonical is a company domain&lt;/td&gt;
&lt;td&gt;220&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;18%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job feeds (WeWorkRemotely, Jobicy, Arbeitnow, RemoteOK, Remotive)&lt;/td&gt;
&lt;td&gt;215&lt;/td&gt;
&lt;td&gt;92&lt;/td&gt;
&lt;td&gt;43%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm, crates.io and package-registry homepage fields&lt;/td&gt;
&lt;td&gt;190&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reddit, Mastodon, Product Hunt and HN signal threads&lt;/td&gt;
&lt;td&gt;142&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6,955&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,040&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two readings matter more than the total.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hiring threads give you companies, not contacts.&lt;/strong&gt; 2,792 domains — 40% of the file — and 304 mailboxes,&lt;br&gt;
because the post names the employer and not the person. That is the raw material an enrichment step has to work&lt;br&gt;
with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Directories give you contacts, not prospects.&lt;/strong&gt; Agency directories publish an address for 492 of 492 rows,&lt;br&gt;
because agencies put one on their own site on purpose. A list built only from job feeds is a list of companies; a&lt;br&gt;
list built only from directories is a list of competitors.&lt;/p&gt;

&lt;h2&gt;
  
  
  What public sources can append — and what they cannot
&lt;/h2&gt;

&lt;p&gt;Appendable, because it is observable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;company identity — name, root domain, and the exact page the domain was taken from;&lt;/li&gt;
&lt;li&gt;what they sell — product category, whether a pricing page and a self-serve sign-up exist;&lt;/li&gt;
&lt;li&gt;hiring signal — open roles and titles, the cheapest honest intent signal;&lt;/li&gt;
&lt;li&gt;public addresses — role and generic mailboxes published on their own domain;&lt;/li&gt;
&lt;li&gt;channel hints — blog, docs, changelog, marketplace listing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sold as enrichment, but not observable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;personal mobiles&lt;/strong&gt; — not public; anything sold as such is scraped, stale or invented;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;revenue and headcount&lt;/strong&gt; — third-party estimates with no published method;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;intent and "in-market" scores&lt;/strong&gt; — a vendor model, not an observation;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;technographics&lt;/strong&gt; — guessed from headers and script tags, right often enough to be dangerous.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you accept that split, the pricing model of the market flips. What is worth money cannot be bought in bulk,&lt;br&gt;
so it has to be observed one row at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three checks a row survives before it counts as enriched
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The domain comes from the source, not from the text.&lt;/strong&gt; A structured field, a post URL, a package homepage,&lt;br&gt;
a catalog's outbound link. Text mining is where the junk enters: on the first pass over job feeds about half of&lt;br&gt;
the extracted domains were the board itself, an ATS (greenhouse.io, lever.co, ashbyhq.com) or a link inside the ad&lt;br&gt;
rather than the employer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The host answers and looks like a company.&lt;/strong&gt; Every candidate is requested live and kept only if the page&lt;br&gt;
carries product signals — pricing, sign-up, demo, contact. On the SaaSHub pull this pass took 909 candidates down&lt;br&gt;
to 351 usable rows. Without it the file fills with university course pages, docs sites and parked domains.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The address belongs to the domain it sits on, then it is checked.&lt;/strong&gt; Domain match first, SMTP check second.&lt;br&gt;
On one agency pull two addresses out of thirty-five were placeholder text and three belonged to a different&lt;br&gt;
domain than the page they sat on — five rows that would have shipped as working data.&lt;/p&gt;

&lt;p&gt;Underneath all three sits deduplication: 45 sources produced 6,955 rows and 6,955 unique root domains, no&lt;br&gt;
duplicates and no row without a domain. Subdomains are folded into their root (&lt;code&gt;app.&lt;/code&gt;, &lt;code&gt;shop.&lt;/code&gt;, &lt;code&gt;blog.&lt;/code&gt;) unless&lt;br&gt;
the root is a platform — then the candidate is dropped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the honest yield is 15% and not 100%
&lt;/h2&gt;

&lt;p&gt;Because 1,040 addresses come from the companies themselves, not from a purchased database or a guessed pattern.&lt;br&gt;
The rest of the rows are still useful: they are companies with a live site, a product and a hiring signal, and&lt;br&gt;
their mailbox is a phone call or a form away. What they are not is a send queue.&lt;/p&gt;

&lt;p&gt;That distinction is the reason the first test in the engagement is &lt;strong&gt;100 verified contacts&lt;/strong&gt; rather than a&lt;br&gt;
monthly volume. A strict two-variant test needs 13,914 contacts per arm — 56 days at 500 a day. Below that&lt;br&gt;
volume, the honest output is not a conversion rate; it is a reading list: which segment answers, which sentence&lt;br&gt;
earns a reply, which objection comes back first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scopes, published:&lt;/strong&gt; $900 Sprint (segment, checked rows, first touches), $1,900/month Engine (the loop keeps&lt;br&gt;
running), $2,900 Full Build (offer, landing page, free tool, distribution). The arithmetic behind the numbers is&lt;br&gt;
on the site: &lt;a href="https://axelfreeman.com/b2b-data-enrichment-service.html" rel="noopener noreferrer"&gt;https://axelfreeman.com/b2b-data-enrichment-service.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are staring at a file you already bought, the useful question is not "how many rows" but "how many of&lt;br&gt;
these rows would survive the three checks". Usually about a third do not — and that is the finding, not a&lt;br&gt;
failure.&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>dataengineering</category>
      <category>b2b</category>
      <category>sales</category>
    </item>
    <item>
      <title>I ran 521 Show HN launch URLs through a lead filter: 86 companies survived</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 07:22:26 +0000</pubDate>
      <link>https://dev.to/axelfreeman/i-ran-521-show-hn-launch-urls-through-a-lead-filter-86-companies-survived-2bcp</link>
      <guid>https://dev.to/axelfreeman/i-ran-521-show-hn-launch-urls-through-a-lead-filter-86-companies-survived-2bcp</guid>
      <description>&lt;h1&gt;
  
  
  I ran 521 Show HN launch URLs through a lead filter: 86 companies survived
&lt;/h1&gt;

&lt;p&gt;Every "B2B lead list" problem starts with the same question: &lt;em&gt;where did the domain come from?&lt;/em&gt; On job boards the employer's domain sits inside the body copy of an ad, which is why roughly half of what gets extracted turns out to be the board itself, an ATS, or a link in the text. &lt;strong&gt;Show HN is the opposite&lt;/strong&gt;: the post has a structured &lt;code&gt;url&lt;/code&gt; field, and that field is the maker's own site.&lt;/p&gt;

&lt;p&gt;So I pulled Show HN and ran it through a filter. Here is the whole pipeline and every number, including the ones that did not survive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pull
&lt;/h2&gt;

&lt;p&gt;Hacker News has a public search API (Algolia). Twelve pages of &lt;code&gt;search_by_date&lt;/code&gt; with &lt;code&gt;tags=show_hn&lt;/code&gt;, 100 hits per page, gave &lt;strong&gt;521 hosts that came from the &lt;code&gt;url&lt;/code&gt; field of a post&lt;/strong&gt; — no text parsing, no guessing. Each candidate kept the HN item id as its provenance, so a row can always be traced back to the launch it came from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filter 1 — remove what is not a company
&lt;/h2&gt;

&lt;p&gt;A launch URL is often not a company's own site: GitHub repos, YouTube demos, Medium posts, news stories, and free PaaS subdomains (&lt;code&gt;*.vercel.app&lt;/code&gt;, &lt;code&gt;*.pages.dev&lt;/code&gt;, &lt;code&gt;*.onrender.com&lt;/code&gt;, and friends). After a blocklist of those, &lt;strong&gt;223 of the 521 hosts were new&lt;/strong&gt; against an existing file of 6,518 company domains. The other 298 were already known — which is itself a signal that this source is not a duplicate of job feeds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filter 2 — a domain is not a company until it answers
&lt;/h2&gt;

&lt;p&gt;Every host was requested live, and kept only if it answered 200 &lt;strong&gt;and&lt;/strong&gt; the page looked like a product rather than a document: pricing, sign-up, "get started", a demo link. That left &lt;strong&gt;112&lt;/strong&gt;. The 111 that dropped out were mostly one-page demos, portfolios, and blog posts about a tool rather than the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filter 3 — the subdomain trap
&lt;/h2&gt;

&lt;p&gt;This is the step I would keep even if I deleted every other one. A launch URL is frequently a &lt;em&gt;page&lt;/em&gt;, not a domain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app.oghmere.com&lt;/code&gt;, &lt;code&gt;shop.lumnika.com&lt;/code&gt;, &lt;code&gt;demo.plutus-cloud.com&lt;/code&gt; → three rows for what is one company each&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blog.codacy.com&lt;/code&gt; → a content subdomain of a company already in the file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;what-are-you-working-on-62u6b.reachpad.app&lt;/code&gt; → an app instance on someone else's PaaS, not a company domain at all&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Normalising to the registrable domain and re-checking the root took &lt;strong&gt;112 → 105 unique candidates → 86 that answered 200 at the root&lt;/strong&gt;. Nineteen were deep links whose root did not carry the product signals, and a handful were PaaS subdomains with no company behind them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the file looks like now
&lt;/h2&gt;

&lt;p&gt;The filter above is one source family in a file I keep building from public sources only. Current state, counted row by row:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source family&lt;/th&gt;
&lt;th&gt;Domains&lt;/th&gt;
&lt;th&gt;Publish an address&lt;/th&gt;
&lt;th&gt;Yield&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hacker News "Who is hiring?" threads (2024 → Sep 2026)&lt;/td&gt;
&lt;td&gt;2 792&lt;/td&gt;
&lt;td&gt;304&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Y Combinator open hiring catalog&lt;/td&gt;
&lt;td&gt;736&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;remoteintech/remote-jobs public catalog&lt;/td&gt;
&lt;td&gt;531&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agency directories&lt;/td&gt;
&lt;td&gt;525&lt;/td&gt;
&lt;td&gt;522&lt;/td&gt;
&lt;td&gt;99%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub repositories and organisations (website field)&lt;/td&gt;
&lt;td&gt;466&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show HN launches (domain from the post URL)&lt;/td&gt;
&lt;td&gt;407&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WordPress plugin catalog (homepage field)&lt;/td&gt;
&lt;td&gt;350&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dev.to posts whose canonical is a company domain&lt;/td&gt;
&lt;td&gt;220&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;18%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Package registries (npm, PyPI, crates.io)&lt;/td&gt;
&lt;td&gt;190&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hacker News other threads&lt;/td&gt;
&lt;td&gt;106&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;21%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job feeds (WWR, Jobicy, Arbeitnow, RemoteOK, Remotive, LaunchingNext, Working Nomads)&lt;/td&gt;
&lt;td&gt;182&lt;/td&gt;
&lt;td&gt;62&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reddit and Mastodon threads&lt;/td&gt;
&lt;td&gt;58&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product Hunt launches&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Applicant tracking systems&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6 604&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1 040&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;16%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two numbers in that table are worth more than the total:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Directory rows publish an address 99% of the time. Hiring threads do it 11% of the time.&lt;/strong&gt; A hiring post gives you the company, not the contact.&lt;/li&gt;
&lt;li&gt;Only &lt;strong&gt;16% of rows&lt;/strong&gt; publish an address at all. The rest are either checked one by one over SMTP or left out of the send queue — which is the actual cost of outbound, and the reason a list is an input rather than a product.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this is a lead-generation post and not a data-hoarding post
&lt;/h2&gt;

&lt;p&gt;Collecting domains is the cheap half. The expensive half is what happens after: four checks before a row is ever sent (domain from the post, host answers live, published address matched to its own domain, mailbox checked where it will be used), then the volume question. A strict two-variant test needs 13,914 contacts per arm — 56 days at 500 a day. Below that, the honest output of outbound is not a conversion rate, it is a reading list: which segment answers, which sentence earns a reply, which objection comes back first.&lt;/p&gt;

&lt;p&gt;Anyone quoting appointments per month before the segment has been read is quoting the report, not the meetings.&lt;/p&gt;

&lt;p&gt;If you want the list, the checks and the sending run owned by someone else: &lt;strong&gt;&lt;a href="https://axelfreeman.com/marketing-engineer.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=appointment-setting" rel="noopener noreferrer"&gt;appointment setting, scoped at $900 / $1,900/month / $2,900&lt;/a&gt;&lt;/strong&gt;. The full source table and the four checks live on the canonical page for this article: &lt;a href="https://axelfreeman.com/appointment-setting-service.html" rel="noopener noreferrer"&gt;appointment-setting-service.html&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>sales</category>
      <category>b2b</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I collected 6,032 B2B company domains in a day. Only 998 publish an address</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 06:40:10 +0000</pubDate>
      <link>https://dev.to/axelfreeman/i-collected-6032-b2b-company-domains-in-a-day-only-998-publish-an-address-e2p</link>
      <guid>https://dev.to/axelfreeman/i-collected-6032-b2b-company-domains-in-a-day-only-998-publish-an-address-e2p</guid>
      <description>&lt;p&gt;I spent one working day collecting B2B company domains from public sources. Not "scraping the web" — 41 specific sources, each one a place where a company published its own link, and each row carrying the source it came from.&lt;/p&gt;

&lt;p&gt;The file ended at &lt;strong&gt;6,032 company domains&lt;/strong&gt;. Of those, &lt;strong&gt;998 publish a contact address of their own&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That ratio — one address per six companies — is the number nobody puts on a sales page, and it is the only one that decides whether a list is worth buying.&lt;/p&gt;

&lt;h2&gt;
  
  
  The yield of every source family
&lt;/h2&gt;

&lt;p&gt;All numbers below are counted from the file, one row at a time.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source family&lt;/th&gt;
&lt;th&gt;Domains&lt;/th&gt;
&lt;th&gt;Published an address&lt;/th&gt;
&lt;th&gt;Yield&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hacker News "Who is hiring?" threads (2024 → Sep 2026)&lt;/td&gt;
&lt;td&gt;2,792&lt;/td&gt;
&lt;td&gt;304&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Y Combinator open-source hiring directory&lt;/td&gt;
&lt;td&gt;736&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;remoteintech/remote-jobs public catalog&lt;/td&gt;
&lt;td&gt;531&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub repository homepage fields&lt;/td&gt;
&lt;td&gt;330&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agency directories (DAN, Semrush listings)&lt;/td&gt;
&lt;td&gt;525&lt;/td&gt;
&lt;td&gt;522&lt;/td&gt;
&lt;td&gt;99%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show HN launches — domain taken from the post URL&lt;/td&gt;
&lt;td&gt;343&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;td&gt;13%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dev.to posts whose canonical is a company domain&lt;/td&gt;
&lt;td&gt;220&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm and crates.io package homepage fields&lt;/td&gt;
&lt;td&gt;190&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Job feeds (WeWorkRemotely, Jobicy, Arbeitnow, RemoteOK, Remotive, LaunchingNext)&lt;/td&gt;
&lt;td&gt;182&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reddit, Mastodon and HN signal threads&lt;/td&gt;
&lt;td&gt;142&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product Hunt launches&lt;/td&gt;
&lt;td&gt;37&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6,032&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;998&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;17%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two readings matter more than the total.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The biggest family publishes almost no mailboxes.&lt;/strong&gt; 2,792 rows came from hiring threads, and only 304 of them expose an address. A "Who is hiring?" post gives you the company and the role — it does not give you the inbox. That is not a flaw of the source, it is what the source is for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The only family with near-total contact data is agencies.&lt;/strong&gt; 522 of 525 rows carry an address, because an agency puts one on the page on purpose. Which also means: a list built only from job feeds is a list of companies, and a list built only from directories is a list of competitors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 1: the domain comes from the post, not from the text
&lt;/h2&gt;

&lt;p&gt;On job feeds the employer's domain sits inside the body copy. When you pull it out of the text, roughly half the rows are wrong — the job board itself, an ATS (greenhouse.io, lever.co, ashbyhq.com), a link inside the ad, or the same company under two ccTLDs.&lt;/p&gt;

&lt;p&gt;When the domain comes from a structured field or from the post's own URL — Show HN, package registries, dev.to canonicals — the reject rate falls from about 50% to somewhere between 5% and 12%.&lt;/p&gt;

&lt;p&gt;That difference is the whole reason this file counts 41 sources instead of 4,000 scraped pages. Fewer sources, better rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 2: a domain is not a company until it answers
&lt;/h2&gt;

&lt;p&gt;Every host got a live request before it entered the file, and only pages that behave like a product were kept: pricing, sign-up, demo, integrations.&lt;/p&gt;

&lt;p&gt;Skip that step and the file fills with university course pages, documentation sites and personal blogs. It happened on my first pass: 21 candidates reduced to 10 usable rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 3: a published address is not a verified address
&lt;/h2&gt;

&lt;p&gt;Of 6,032 rows, 998 expose an address. The rest are either SMTP-checked one by one, or left out of the send queue entirely.&lt;/p&gt;

&lt;p&gt;In the agency pull, two addresses out of 35 were placeholder text (&lt;code&gt;hello@world.com&lt;/code&gt;, &lt;code&gt;johnsmith@yourbrand.com&lt;/code&gt;) and three belonged to a different domain than the page they sat on. Five rows out of 35 would have gone out as working data without a domain match.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the list is actually for
&lt;/h2&gt;

&lt;p&gt;The list is the cheap half of outbound. The expensive half is the sentence that earns a reply, and the reading of what came back.&lt;/p&gt;

&lt;p&gt;Which is why the work is scoped as work, not as a spreadsheet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;$900 Sprint, one-off&lt;/strong&gt; — segment and definition, the checked contact list, the first touches sent, and the measurement that says what the channel owns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$1,900/month Engine&lt;/strong&gt; — the loop keeps running: list refreshed, sends going out, replies worked to a booked conversation, a read-out each cycle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$2,900 Full Build&lt;/strong&gt; — offer, landing page, a free tool, distribution and measurement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first test is &lt;strong&gt;100 verified contacts&lt;/strong&gt;, so the list is judged before a month is committed to.&lt;/p&gt;

&lt;p&gt;The full write-up, with the yield table and the source rules, is on my site: &lt;a href="https://axelfreeman.com/b2b-lead-list-building.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=lead-list-building" rel="noopener noreferrer"&gt;B2B lead list building&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;If you have pulled a list from public sources recently, I would like to know which source gave you the best address-per-domain ratio — that number is the only one that survives contact with a real inbox.&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>b2b</category>
      <category>sales</category>
      <category>data</category>
    </item>
    <item>
      <title>I pulled 91 remote job posts to price an outsourced SDR</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 06:21:29 +0000</pubDate>
      <link>https://dev.to/axelfreeman/i-pulled-91-remote-job-posts-to-price-an-outsourced-sdr-488n</link>
      <guid>https://dev.to/axelfreeman/i-pulled-91-remote-job-posts-to-price-an-outsourced-sdr-488n</guid>
      <description>&lt;p&gt;I pulled nine remote job feeds on 19 September 2026 and counted what was in them. Not to make a point about hiring — to answer a question buyers keep asking in a way neither side can win: &lt;strong&gt;is an outsourced SDR cheaper than hiring one?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer is not a price. It is a denominator.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the job feeds actually showed
&lt;/h2&gt;

&lt;p&gt;The pull was WeWorkRemotely's general feed plus its eight category feeds: 91 unique posts carried the company's own domain in the post body. 65 of those domains answered with HTTP 200. Of the 65 live ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;19 were sales, growth or marketing roles&lt;/strong&gt; — demand generation, inside sales, heads of marketing and sales, affiliate and lifecycle marketing;&lt;/li&gt;
&lt;li&gt;3 of those were revenue leadership titles, i.e. a company that has already decided to staff the function and is only choosing how;&lt;/li&gt;
&lt;li&gt;across the entire pull, &lt;strong&gt;exactly two posts printed money&lt;/strong&gt;: $40,000/year (a support role) and $170/hour (a contractor).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last line is the market's real condition. Almost nobody publishes a price, so buyers compare shapes instead: who writes the list, who owns the copy, what gets reported, what happens when it stops.&lt;/p&gt;

&lt;h2&gt;
  
  
  The denominator nobody quotes
&lt;/h2&gt;

&lt;p&gt;A strict two-variant test at a 3% base rate with a +20% relative lift needs &lt;strong&gt;13,914 contacts per arm&lt;/strong&gt; — 27,828 in total — at 80% power and alpha 0.05. At 500 contacts a day that is 56 days. At 1,000 a day, 28 days.&lt;/p&gt;

&lt;p&gt;So the only comparable number between two quotes is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cost per finished reading = (fee + data + tooling + mailboxes) / verdicts per quarter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two vendors and one verdict means the second invoice bought nothing. Adding a person does not change the number of readings either, until the volume itself changes — below roughly 2,000 contacts a day, the constraint is the funnel, not the staffing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Six rows, of which most services sell three
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;th&gt;Outsourced service&lt;/th&gt;
&lt;th&gt;Who must own it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List&lt;/td&gt;
&lt;td&gt;builds, verifies, suppresses&lt;/td&gt;
&lt;td&gt;definition of a qualified account is yours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Copy&lt;/td&gt;
&lt;td&gt;drafts sequences and variants&lt;/td&gt;
&lt;td&gt;approval is yours; without it the clock never starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sending infrastructure&lt;/td&gt;
&lt;td&gt;mailboxes, warmup, rotation&lt;/td&gt;
&lt;td&gt;ideally your domains, so reputation stays with you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conversations&lt;/td&gt;
&lt;td&gt;first reply, qualification&lt;/td&gt;
&lt;td&gt;qualification criteria are yours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product context&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;td&gt;yours — nobody external can price or promise for you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reporting unit&lt;/td&gt;
&lt;td&gt;sends, opens, replies&lt;/td&gt;
&lt;td&gt;yours to set: the readable unit, the owned number, the stop rule&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The failure mode is a service that sells the first three rows, reports on them, and leaves the last two empty. You end up owning a dashboard of activity and no verdict.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ten questions that separate two SDR quotes
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Who is the named person on my account, and how many accounts do they hold?&lt;/li&gt;
&lt;li&gt;What is a qualified conversation, in words I can point at? ("A reply" is not an answer.)&lt;/li&gt;
&lt;li&gt;Which number does the channel own, and what volume does it need before that number can be read?&lt;/li&gt;
&lt;li&gt;What is the stop rule — at what cost per qualified conversation do we stop?&lt;/li&gt;
&lt;li&gt;Who owns the domains, mailboxes and sending reputation if we part ways?&lt;/li&gt;
&lt;li&gt;Who owns the list, and can I export it with verification results and dates?&lt;/li&gt;
&lt;li&gt;Are data, tooling and mailbox costs inside the fee or outside it?&lt;/li&gt;
&lt;li&gt;What is the reporting unit — sends, replies, meetings, or finished readings with volume attached?&lt;/li&gt;
&lt;li&gt;What does the first week produce that I keep even if we stop on day seven?&lt;/li&gt;
&lt;li&gt;Which of my definitions did you have to invent because I never wrote them?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Question 10 is the useful one. The honest answer is a list of the things the engagement should have started with.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the first week should hand over
&lt;/h2&gt;

&lt;p&gt;Four artifacts, keepable even if the engagement ends immediately: the qualified-account definition, the number the channel owns, the volume that number needs before it can be read, and the stop rule. Everything after that is execution, and execution is cheap to replace.&lt;/p&gt;

&lt;p&gt;I run this on my own domain, which is why the numbers above are countable rather than claimed. If you want the same page of definitions written for your funnel before you take another quote, that is the fixed-scope entry point: &lt;a href="https://axelfreeman.com/marketing-engineer.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=outsourced-sdr" rel="noopener noreferrer"&gt;marketing engineering engagements, $900 Sprint / $1,900 Engine / $2,900 Full Build&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The canonical version of this piece, with the full table of the feed pull and the FAQ, is on my site: &lt;a href="https://axelfreeman.com/outsourced-sdr.html" rel="noopener noreferrer"&gt;Outsourced SDR: what you are actually buying&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>sales</category>
      <category>b2b</category>
      <category>saas</category>
    </item>
    <item>
      <title>Foundations before amplification: the order AI marketing skips</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 05:29:29 +0000</pubDate>
      <link>https://dev.to/axelfreeman/foundations-before-amplification-the-order-ai-marketing-skips-4hj7</link>
      <guid>https://dev.to/axelfreeman/foundations-before-amplification-the-order-ai-marketing-skips-4hj7</guid>
      <description>&lt;h1&gt;
  
  
  Foundations before amplification: the order AI marketing skips
&lt;/h1&gt;

&lt;p&gt;Almost every AI-marketing engagement I get asked to price starts at the wrong end. The brief is amplification: more posts, more citations, more ads, more agents. Amplification is step five. When it is step one, it multiplies a number nobody has defined yet, and the result is a busier month with the same amount of information in it.&lt;/p&gt;

&lt;p&gt;I wrote the five steps down on my own domain, with what each one has to produce before the next one is allowed to start: &lt;a href="https://axelfreeman.com/freeman-framework.html" rel="noopener noreferrer"&gt;the FREEMAN framework&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  F — Foundations: the audit that decides everything after it
&lt;/h2&gt;

&lt;p&gt;Before any channel work there is an unglamorous week: what is tracked, what is duplicated, which conversions are double-counted, which form fields never reach the CRM, what the actual baseline is. The deliverable is not a slide. It is a short document that states, in numbers, what the funnel currently does and which of its numbers are trustworthy.&lt;/p&gt;

&lt;p&gt;This is the step that gets skipped because it produces nothing visible. It is also the step that decides whether the next four produce readings or noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  R — Relevance: the message that survives contact with a list
&lt;/h2&gt;

&lt;p&gt;Relevance means one formulation per channel, tested against a defined audience, with the reply rate as the reading — not impressions. If nobody can say which message is currently winning, there is no relevance step, there is copywriting.&lt;/p&gt;

&lt;h2&gt;
  
  
  I — Integration: schema, discovery, one system
&lt;/h2&gt;

&lt;p&gt;This is where the machine-readable layer goes in: structured data, an &lt;code&gt;llms.txt&lt;/code&gt;, a sitemap that matches reality, pages that answer a question in the first paragraph because that is the part an answer engine quotes. Integration is not an integration project. It is the decision that the system reads from one set of definitions.&lt;/p&gt;

&lt;h2&gt;
  
  
  M — Measurement: one owned number per channel, monthly
&lt;/h2&gt;

&lt;p&gt;Each channel gets exactly one number it owns, stated before the month starts, plus a stop rule expressed as a cost per qualified conversation checked on a fixed date. A channel that reports four numbers owns none of them.&lt;/p&gt;

&lt;p&gt;The arithmetic here is unfriendly and worth knowing in advance: one strict two-variant test at a 3% base rate with a +20% relative lift needs &lt;strong&gt;13,914 contacts per arm — 27,828 in total&lt;/strong&gt; at 80% power. At 500 contacts a day that is &lt;strong&gt;56 days&lt;/strong&gt;. Media money is rarely the constraint; volume is. You can check it yourself with a &lt;a href="https://axelfreeman.github.io/marketing-mindset/tools/email-test-planner.html" rel="noopener noreferrer"&gt;free test planner&lt;/a&gt; and a &lt;a href="https://axelfreeman.github.io/marketing-mindset/tools/test-queue-planner.html" rel="noopener noreferrer"&gt;queue planner&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A — Amplification: only what already proved itself
&lt;/h2&gt;

&lt;p&gt;External signals last: distribution, listings, posts, PR, archive snapshots. By the time you get here you know which message to amplify and which number is supposed to move — so amplification has a kill rule instead of a content calendar.&lt;/p&gt;

&lt;h2&gt;
  
  
  The order is the product
&lt;/h2&gt;

&lt;p&gt;The steps are cheap to name and expensive to reorder. A team that starts at A will spend the quarter learning that its baseline was wrong; a team that starts at F and R will finish the quarter with one verified message and a channel that can be scaled or stopped on evidence. Neither quarter costs more. Only one of them ends with a decision.&lt;/p&gt;

&lt;p&gt;I run this as a fixed-scope engagement: &lt;strong&gt;Sprint $900&lt;/strong&gt; one-off (foundations, definitions, tracking, stop rules — yours whether or not you continue), &lt;strong&gt;Engine $1,900/month&lt;/strong&gt; (one channel end to end, a written record and an owned number each month), &lt;strong&gt;Full Build $2,900&lt;/strong&gt; (the whole loop including the pipeline). Prices and deliverables are published on the &lt;a href="https://axelfreeman.com/marketing-engineer.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=freeman-framework" rel="noopener noreferrer"&gt;offer page&lt;/a&gt;, and the artifacts this produced on my own domain — packages, accepted third-party listings, archived snapshots — are on the &lt;a href="https://axelfreeman.com/proof.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=freeman-framework" rel="noopener noreferrer"&gt;proof page&lt;/a&gt;. The method also ships as an &lt;a href="https://www.npmjs.com/package/marketing-mindset" rel="noopener noreferrer"&gt;npm CLI&lt;/a&gt; and a public &lt;a href="https://github.com/axelfreeman/marketing-engineer-playbook" rel="noopener noreferrer"&gt;playbook repository&lt;/a&gt; if you would rather read the operating file than take my word for it.&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>aeo</category>
      <category>saas</category>
      <category>startup</category>
    </item>
    <item>
      <title>Hire in-house or contract? Count the readings a quarter can finish</title>
      <dc:creator>Axel Freeman </dc:creator>
      <pubDate>Sat, 19 Sep 2026 05:04:12 +0000</pubDate>
      <link>https://dev.to/axelfreeman/hire-in-house-or-contract-count-the-readings-a-quarter-can-finish-31f6</link>
      <guid>https://dev.to/axelfreeman/hire-in-house-or-contract-count-the-readings-a-quarter-can-finish-31f6</guid>
      <description>&lt;h1&gt;
  
  
  Hire in-house or contract? Count the readings a quarter can finish
&lt;/h1&gt;

&lt;p&gt;The argument about hiring a marketer in-house versus bringing in an engineer for one channel is usually had in the wrong units. Salary, retainer, "commitment", "culture fit" — none of them decide anything. What decides it is how many finished readings each option can produce this quarter, because an unread month costs the same as a decisive one and teaches you nothing.&lt;/p&gt;

&lt;p&gt;I wrote the whole comparison out on my own domain, with the arithmetic it depends on: &lt;a href="https://axelfreeman.com/marketing-engineer-vs-in-house-hire.html" rel="noopener noreferrer"&gt;marketing engineer vs an in-house hire&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The floor comes first, and it does not care who is on payroll
&lt;/h2&gt;

&lt;p&gt;One strict two-variant test at a 3% base rate and a +20% relative lift needs &lt;strong&gt;13,914 contacts per arm — 27,828 in total&lt;/strong&gt; at 80% power and alpha 0.05. At 500 contacts a day that is &lt;strong&gt;56 days&lt;/strong&gt;. At 1,000 a day, &lt;strong&gt;28 days&lt;/strong&gt;. Replies read cheaper than money: an email test reads on 1,500–2,000 sends per variant. A strict web A/B needs roughly 10,000 visitors per variant and 300+ conversions.&lt;/p&gt;

&lt;p&gt;So at moderate volume a quarter finishes one or two honest readings. That is the ceiling, and it is a property of the funnel rather than of the staffing model. Two people reading the same 500 contacts a day produce the same single verdict and twice the salary.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a hire actually pays before its first reading
&lt;/h2&gt;

&lt;p&gt;Ramp. The readable-unit clock starts when the first contact goes out, which is after the person has learned the funnel, placed the tracking and got copy approved. Before that there is a month of tooling and internal archaeology — and if nobody has written down the definitions, that archaeology is the job.&lt;/p&gt;

&lt;p&gt;The fixed-scope route starts differently: definitions, tracking and stop rules are the first artifact, copy gets approved once, and the clock starts on the first contact rather than after onboarding. That is the only structural difference between the two options, and it is worth a full quarter at 500 contacts a day.&lt;/p&gt;

&lt;p&gt;You can check the arithmetic yourself with free tools that do nothing but maths: &lt;a href="https://axelfreeman.github.io/marketing-mindset/tools/email-test-planner.html" rel="noopener noreferrer"&gt;compute your own floor&lt;/a&gt;, then &lt;a href="https://axelfreeman.github.io/marketing-mindset/tools/test-queue-planner.html" rel="noopener noreferrer"&gt;see how many verdicts your volume can finish&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When in-house is genuinely the better answer
&lt;/h2&gt;

&lt;p&gt;I would rather say this than pretend otherwise: above roughly &lt;strong&gt;2,000 contacts a day&lt;/strong&gt;, a single finished test fits inside a month, and there is enough operational surface — sequencing, data hygiene, landing pages, the queue, the approvals — to keep a full-time owner busy between readings. Context accumulating inside one head beats any external arrangement at that volume.&lt;/p&gt;

&lt;p&gt;Below it, the constraint is the funnel. Hiring does not raise the reading rate; it just adds a fixed cost to the same queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four definitions the hiring round needs anyway
&lt;/h2&gt;

&lt;p&gt;Whatever you choose, four things have to exist or nothing reads:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;what counts as a qualified account;&lt;/li&gt;
&lt;li&gt;which number the channel owns;&lt;/li&gt;
&lt;li&gt;what volume that number needs before it can be read;&lt;/li&gt;
&lt;li&gt;what the stop rule is, stated as a cost per qualified conversation checked on a fixed date.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hiring before those exist means paying someone to guess at them and then paying again when the first test contradicts the guess. Those four lines are also the most useful interview material you can have: "I would test a few subject lines and scale the winner" and "1,500–2,000 sends per variant before reading, one approved formulation per channel, stop rule at a stated cost per qualified conversation" are not the same candidate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs, in public numbers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sprint $900&lt;/strong&gt; one-off — the definitions, the tracking and the stop rules written down, usable whether the next step is a hire or a retainer. &lt;strong&gt;Engine $1,900/month&lt;/strong&gt; — one channel end to end with a written record and an owned number each month. &lt;strong&gt;Full Build $2,900&lt;/strong&gt; — the whole loop, including the pipeline the retainer would otherwise be reporting on. Media spend, tools and data are never inside those numbers.&lt;/p&gt;

&lt;p&gt;Prices and the deliverable list are on the &lt;a href="https://axelfreeman.com/marketing-engineer.html?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=vs-inhouse" rel="noopener noreferrer"&gt;offer page&lt;/a&gt;, and the artifacts produced by running this on my own domain are on the &lt;a href="https://axelfreeman.com/proof.html" rel="noopener noreferrer"&gt;proof page&lt;/a&gt;. The method ships as an &lt;a href="https://www.npmjs.com/package/marketing-mindset" rel="noopener noreferrer"&gt;npm CLI&lt;/a&gt; and a &lt;a href="https://github.com/axelfreeman/marketing-engineer-playbook" rel="noopener noreferrer"&gt;playbook repository&lt;/a&gt; if you would rather read the operating file than take my word for it.&lt;/p&gt;

</description>
      <category>career</category>
      <category>marketing</category>
      <category>b2b</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
