<?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: themineworks</title>
    <description>The latest articles on DEV Community by themineworks (@themineworks).</description>
    <link>https://dev.to/themineworks</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%2F4056348%2Ff1cd7b45-84df-4edf-907a-cd89dac1e06e.png</url>
      <title>DEV Community: themineworks</title>
      <link>https://dev.to/themineworks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/themineworks"/>
    <language>en</language>
    <item>
      <title>Apify pay-per-event billing: four ways I charged users for nothing</title>
      <dc:creator>themineworks</dc:creator>
      <pubDate>Mon, 31 Aug 2026 18:58:08 +0000</pubDate>
      <link>https://dev.to/apify/apify-pay-per-event-billing-four-ways-i-charged-users-for-nothing-9m1</link>
      <guid>https://dev.to/apify/apify-pay-per-event-billing-four-ways-i-charged-users-for-nothing-9m1</guid>
      <description>&lt;h1&gt;
  
  
  Apify pay-per-event billing: four ways I charged users for nothing
&lt;/h1&gt;

&lt;p&gt;I run 51 scrapers on Apify behind seven MCP servers. Agents call them as tools&lt;br&gt;
over the &lt;a href="https://modelcontextprotocol.io/specification/2025-06-18" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt;:&lt;br&gt;
Claude asks for a company's SEC filings, or Reddit posts about a product, or&lt;br&gt;
open roles at a competitor, and a tool call goes out and comes back with rows.&lt;/p&gt;

&lt;p&gt;Before I shipped any of it I wrote down one rule. A tool call that returns&lt;br&gt;
nothing must never fire a billable event.&lt;/p&gt;

&lt;p&gt;It reads like a small rule. Under Apify pay-per-event billing it is the single&lt;br&gt;
hardest thing I have had to enforce, and I got it wrong four separate times, in&lt;br&gt;
four different ways, each one invisible from the outside. Every one of them was&lt;br&gt;
caught by the same check, which I will get to at the end. If you are putting a&lt;br&gt;
paid Actor behind an agent, this is the post I wanted to read first.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;None of this needs special tooling, but it assumes you are past these three&lt;br&gt;
things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Apify account.&lt;/li&gt;
&lt;li&gt;An Actor you have published with
&lt;a href="https://docs.apify.com/platform/actors/publishing/monetize" rel="noopener noreferrer"&gt;pay-per-event monetization&lt;/a&gt;
enabled, and at least one billing event registered for it in Console.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;Node&lt;/a&gt; with the &lt;code&gt;apify-client&lt;/code&gt; package and an
API token, so you can call that Actor from code rather than from the Console.
Three of the four bugs below only appear when the caller is not a browser.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why Apify pay-per-event billing breaks quietly with agents
&lt;/h2&gt;

&lt;p&gt;A person who runs your Actor and gets nothing back looks at the empty dataset&lt;br&gt;
and asks for a refund. That feedback loop is fast and it is loud.&lt;/p&gt;

&lt;p&gt;An agent does not do that. It gets an empty result, says "I could not find&lt;br&gt;
anything for that company," and moves on. The user never sees your Actor's&lt;br&gt;
name. Nobody files a complaint. If you were charging for those calls, you would&lt;br&gt;
find out from your revenue graph looking suspiciously good, which is not a&lt;br&gt;
thing anyone investigates.&lt;/p&gt;

&lt;p&gt;So the usual signal that tells you billing is broken does not arrive. You have&lt;br&gt;
to go looking.&lt;/p&gt;
&lt;h2&gt;
  
  
  Failure one: the summary row
&lt;/h2&gt;

&lt;p&gt;My scrapers append a bookkeeping row to the end of every dataset. Run stats,&lt;br&gt;
counts, that kind of thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"posts_scraped"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"charged_for"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My billing wrapper decided "did this return anything?" by counting dataset&lt;br&gt;
items. A search that found nothing still returned one item. One is more than&lt;br&gt;
zero. The call billed.&lt;/p&gt;

&lt;p&gt;Worse, one of my resolver Actors emits an explicit not-found row rather than&lt;br&gt;
staying silent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"resolved"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"asdfghjkl ltd"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same outcome. Gibberish in, a row out, a charge fired.&lt;/p&gt;

&lt;p&gt;The fix is not complicated once you see it, but you have to see it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;billable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_type&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;summary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolved&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;billable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;found&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;billed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The general shape of the bug: &lt;strong&gt;raw item count is not the same as delivered&lt;br&gt;
results.&lt;/strong&gt; Any row your own pipeline adds for its own purposes will lie to a&lt;br&gt;
naive counter.&lt;/p&gt;
&lt;h2&gt;
  
  
  Failure two: &lt;code&gt;Actor.charge&lt;/code&gt; does not throw
&lt;/h2&gt;

&lt;p&gt;This one cost real money and it is the one I would most want other people to&lt;br&gt;
know about.&lt;/p&gt;

&lt;p&gt;I shipped a new Indeed tool. The PPE event for it did not exist in Console yet,&lt;br&gt;
because the browser tab died halfway through the pricing wizard and I did not&lt;br&gt;
notice. The tool went live.&lt;/p&gt;

&lt;p&gt;It worked. It hit Indeed, came back with ten real postings, and told the caller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"billed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search_jobs_indeed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The platform recorded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"chargedEventCounts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So it served real data, over residential proxy that we pay for by the gigabyte,&lt;br&gt;
for free, while reporting that it had charged.&lt;br&gt;
&lt;a href="https://docs.apify.com/sdk/js/reference/class/Actor#charge" rel="noopener noreferrer"&gt;&lt;code&gt;Actor.charge&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
does not throw when you hand it an event name that was never registered. It&lt;br&gt;
returns. My billing code had no try/catch because there was nothing to catch.&lt;/p&gt;

&lt;p&gt;The rule I now follow without exception: &lt;strong&gt;register the event in Console before&lt;br&gt;
deploying any tool that references it.&lt;/strong&gt; Not after, not in the same sitting,&lt;br&gt;
before. When I caught this I pulled the tool out of the &lt;code&gt;tools&lt;/code&gt; array and&lt;br&gt;
redeployed within minutes, then put it back only once &lt;code&gt;GET /v2/acts/{id}&lt;/code&gt;&lt;br&gt;
showed the event in &lt;code&gt;pricingInfos&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is a hardening step I have not built yet and probably should: have the&lt;br&gt;
server refuse to register a tool whose billing event is missing from the&lt;br&gt;
Actor's own &lt;code&gt;pricingInfos&lt;/code&gt; at startup. That turns a silent revenue leak into a&lt;br&gt;
loud boot failure. Flagging it as a gap rather than pretending I solved it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Failure three: &lt;code&gt;prefill&lt;/code&gt; is not &lt;code&gt;default&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This one did not cost money. It quietly broke an Actor for every programmatic&lt;br&gt;
caller for an unknown length of time, which is arguably worse.&lt;/p&gt;

&lt;p&gt;My Google Trends Actor declared its proxy input like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"proxyConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prefill"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"useApifyProxy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"apifyProxyGroups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"RESIDENTIAL"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;prefill&lt;/code&gt; populates the form in the Console. That is all it does, and the&lt;br&gt;
&lt;a href="https://docs.apify.com/platform/actors/development/actor-definition/input-schema/specification/v1" rel="noopener noreferrer"&gt;input schema specification&lt;/a&gt;&lt;br&gt;
says so plainly once you go and read it. Open the Actor in a browser, the field&lt;br&gt;
is filled in, you hit run, it works.&lt;/p&gt;

&lt;p&gt;Call the same Actor from the API, or from a schedule, or from an MCP server,&lt;br&gt;
and &lt;code&gt;proxyConfiguration&lt;/code&gt; arrives as &lt;code&gt;undefined&lt;/code&gt;. No residential proxy, against&lt;br&gt;
an endpoint that returns 429 to datacenter IPs on sight.&lt;/p&gt;

&lt;p&gt;Every human test passed. Every programmatic caller failed, including my own MCP&lt;br&gt;
server calling my own Actor. The fix is a real &lt;code&gt;default&lt;/code&gt;, plus a fallback in&lt;br&gt;
code so the schema and the runtime cannot drift apart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;proxyConfiguration&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;useApifyProxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apifyProxyGroups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RESIDENTIAL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then swept all 96 Actors on the account for the same pattern. Sixteen had it.&lt;br&gt;
Fifteen were harmless because the code already had a fallback. One was a live&lt;br&gt;
gap on an Actor doing 146 runs a month. If you built your Actors by cloning a&lt;br&gt;
template, and most of us did, go and check. It is a ten minute grep.&lt;/p&gt;
&lt;h2&gt;
  
  
  Failure four: a successful run that delivers nothing
&lt;/h2&gt;

&lt;p&gt;Two of my Actors showed "17 of 17 runs succeeded" for weeks while returning&lt;br&gt;
zero rows to everybody.&lt;/p&gt;

&lt;p&gt;Not failing. Succeeding. The target had changed its markup, the parser matched&lt;br&gt;
nothing, the Actor wrote its summary row and exited zero. Every dashboard was&lt;br&gt;
green. The 30-day success rate on the Store listing said 100%.&lt;/p&gt;

&lt;p&gt;Billing was correct throughout, nobody was charged, which is the only reason&lt;br&gt;
this was not a refund event. But the listing was selling something that did not&lt;br&gt;
work, and the stat I would have pointed at to prove it worked was the stat&lt;br&gt;
hiding the problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run status tells you your process exited cleanly. It tells you nothing about&lt;br&gt;
whether a customer got data.&lt;/strong&gt; They are different questions and only one of&lt;br&gt;
them matters. I now alert on delivered rows per run, not on run status, and I&lt;br&gt;
would treat any Actor reporting a suspiciously perfect success rate as unproven&lt;br&gt;
rather than reliable.&lt;/p&gt;
&lt;h2&gt;
  
  
  The one check that catches Apify pay-per-event billing bugs
&lt;/h2&gt;

&lt;p&gt;Every one of these was found the same way. After a call, compare what your own&lt;br&gt;
code thinks it billed against what the platform actually recorded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;runId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// NOT the runs-list endpoint&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;platform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chargedEventCounts&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mine&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BILLING MISMATCH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;runId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;platform&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One detail that wasted an afternoon: &lt;code&gt;GET /v2/acts/{id}/runs&lt;/code&gt; returns an&lt;br&gt;
abbreviated record with &lt;code&gt;chargedEventCounts: {}&lt;/code&gt; and &lt;code&gt;pricingInfo: null&lt;/code&gt; even&lt;br&gt;
when charges definitely exist. Only the&lt;br&gt;
&lt;a href="https://docs.apify.com/api/v2/actor-run-get" rel="noopener noreferrer"&gt;get-run endpoint&lt;/a&gt;,&lt;br&gt;
&lt;code&gt;GET /v2/actor-runs/{runId}&lt;/code&gt;, has the real numbers. Do not conclude "nothing&lt;br&gt;
was charged" from the list endpoint. I did, twice.&lt;/p&gt;

&lt;p&gt;That comparison is the only thing that detects this whole class of bug. Unit&lt;br&gt;
tests will not, because your code is behaving exactly as written. Manual&lt;br&gt;
Console testing will not, because the Console is the one caller that gets the&lt;br&gt;
prefills. Watching your revenue will not, because the failure mode is revenue&lt;br&gt;
that looks fine.&lt;/p&gt;

&lt;p&gt;I now run it on every tool on every server as part of the release check. It has&lt;br&gt;
caught something every single time I have added tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  One more thing, if you are building for agents
&lt;/h2&gt;

&lt;p&gt;Unrelated to billing but it will bite you in the same week:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://docs.apify.com/platform/actors/development/programming-interface/standby" rel="noopener noreferrer"&gt;Apify Standby&lt;/a&gt;&lt;br&gt;
returns &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/504" rel="noopener noreferrer"&gt;504&lt;/a&gt;&lt;br&gt;
on any response over five minutes&lt;/strong&gt;, whatever timeout you set yourself.&lt;/p&gt;

&lt;p&gt;I had a composite tool that chains an Amazon product search into a review pull.&lt;br&gt;
Amazon runs 45 to 110 seconds for a search and about 107 for reviews, so I set&lt;br&gt;
an internal budget of 420 seconds to be safe. The gateway killed it before my&lt;br&gt;
own tool ever finished. 280 seconds fits and works.&lt;/p&gt;

&lt;p&gt;If your Actor genuinely runs for 20 minutes, it cannot be a synchronous tool&lt;br&gt;
call at all. It has to return a run ID immediately and let the agent collect the&lt;br&gt;
result later. Worth designing for on day one rather than discovering at 420&lt;br&gt;
seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: what I would tell someone starting
&lt;/h2&gt;

&lt;p&gt;Write the invariant down before you write the billing code. Mine is one&lt;br&gt;
sentence and it has paid for itself repeatedly, mostly by making it obvious&lt;br&gt;
which of my assumptions were wrong.&lt;/p&gt;

&lt;p&gt;Then assume you have broken it, and go and check against the platform's own&lt;br&gt;
numbers rather than your own. Four for four, that is where I found it.&lt;/p&gt;

&lt;p&gt;If you want to test your own Actor for this today, there are three things worth&lt;br&gt;
doing in order. Call one tool you already ship with an input you know returns&lt;br&gt;
nothing, then read the run back from the get-run endpoint and compare&lt;br&gt;
&lt;code&gt;chargedEventCounts&lt;/code&gt; against what your code says it billed. Grep your input&lt;br&gt;
schemas for &lt;code&gt;prefill&lt;/code&gt; on any field that the runtime actually depends on, and&lt;br&gt;
give each one a real &lt;code&gt;default&lt;/code&gt;. Then take any Actor sitting at a perfect 30-day&lt;br&gt;
success rate and check its delivered rows per run, because that is the number&lt;br&gt;
the success rate is hiding. Each one is a short job. All three found something&lt;br&gt;
on my account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Author bio
&lt;/h2&gt;

&lt;p&gt;The Mine Works builds and maintains 82 web scrapers on the Apify Store, with&lt;br&gt;
seven MCP servers over them so AI agents can call the data as tools. All of it&lt;br&gt;
runs on Apify pay-per-event billing, which is why one rule sits above the rest:&lt;br&gt;
a tool call that returns nothing must never fire a billable event. Most of what&lt;br&gt;
gets published here is a record of how that rule got broken and what the fix&lt;br&gt;
looked like, with the run counts and the failure modes left in rather than&lt;br&gt;
tidied away.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>scraping</category>
      <category>automation</category>
    </item>
    <item>
      <title>How I check whether a research finding actually holds up</title>
      <dc:creator>themineworks</dc:creator>
      <pubDate>Thu, 06 Aug 2026 07:35:00 +0000</pubDate>
      <link>https://dev.to/themineworks/how-i-check-whether-a-research-finding-actually-holds-up-50gb</link>
      <guid>https://dev.to/themineworks/how-i-check-whether-a-research-finding-actually-holds-up-50gb</guid>
      <description>&lt;p&gt;Somebody sends you a study. It has a striking result, it is in a real journal,&lt;br&gt;
and it is exactly what you wanted to hear. The question nobody asks before&lt;br&gt;
repeating it is the one that matters: has anyone actually built on this, or has&lt;br&gt;
it quietly failed to replicate while everyone kept citing the original?&lt;/p&gt;

&lt;p&gt;You cannot tell that from the paper itself. A paper always sounds confident. What&lt;br&gt;
tells you whether a finding held up is what happened after it, who cited it, and&lt;br&gt;
whether the field moved forward on it or moved on from it. That is the citation&lt;br&gt;
graph, and reading it by hand means opening a paper, opening every paper that&lt;br&gt;
cites it, and reading those too. Nobody does this, which is why weak findings&lt;br&gt;
travel so far.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I actually did
&lt;/h2&gt;

&lt;p&gt;There is a public record of which papers cite which, from OpenCitations. Here is&lt;br&gt;
the call I run on a paper's DOI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tools/call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;citation_graph&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"dois"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10.1038/nature12373"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"citations"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That returned 20 citation records in a few seconds, each one a paper that built&lt;br&gt;
on the original. The direction matters: "citations" gives you who cited this&lt;br&gt;
paper, which is the forward trail, what happened after the claim. You can also&lt;br&gt;
ask for references, the backward trail, what the claim was built on.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to read it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Follow the forward trail.&lt;/strong&gt; Pull the papers that cite the finding. If the&lt;br&gt;
citing work is replicating, extending, or applying the result, the finding is&lt;br&gt;
doing real work in the field. That is a good sign.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Watch for the citation that never moves.&lt;/strong&gt; The warning sign is a finding&lt;br&gt;
that gets cited constantly but always in the same shallow way, an&lt;br&gt;
introduction line, never actually built on. When everyone is citing the same&lt;br&gt;
original paper and nobody has reproduced it, that is a finding coasting on its&lt;br&gt;
own reputation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check the backward trail on the claims you rely on.&lt;/strong&gt; Ask for references to&lt;br&gt;
see what a paper stands on. A striking result built on one thin source is a&lt;br&gt;
different bet than one built on a decade of converging work.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;Science is supposed to be self-correcting, but the correction is buried in the&lt;br&gt;
citation record, not stated anywhere. A paper will never tell you it failed to&lt;br&gt;
replicate. The papers that came after it will, if you read who cited it and how.&lt;br&gt;
Walking that graph is the actual work of checking a finding, and it is the part&lt;br&gt;
everyone skips because it is tedious. Making it one call removes the excuse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;This is citation metadata, not the full text of every paper, so it tells you who&lt;br&gt;
cited what, not the nuance of why. Citation coverage differs between databases&lt;br&gt;
because their corpora differ. And a high citation count is not the same as a&lt;br&gt;
replicated result, which is exactly the trap this helps you avoid rather than&lt;br&gt;
one it falls into. You still have to read the important citing papers. The graph&lt;br&gt;
tells you which ones those are.&lt;/p&gt;

&lt;p&gt;The tool is the &lt;a href="https://apify.com/themineworks/academic-research-mcp" rel="noopener noreferrer"&gt;Academic Research MCP&lt;/a&gt;&lt;br&gt;
from The Mine Works, on Apify with your own account. Every source here is a free&lt;br&gt;
public API, so it is the cheapest server in the suite to run, and a DOI with no&lt;br&gt;
citations returns empty and costs nothing.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rent it long-term or list it on Airbnb? I stopped guessing and ran one call</title>
      <dc:creator>themineworks</dc:creator>
      <pubDate>Wed, 05 Aug 2026 10:45:00 +0000</pubDate>
      <link>https://dev.to/themineworks/rent-it-long-term-or-list-it-on-airbnb-i-stopped-guessing-and-ran-one-call-fk</link>
      <guid>https://dev.to/themineworks/rent-it-long-term-or-list-it-on-airbnb-i-stopped-guessing-and-ran-one-call-fk</guid>
      <description>&lt;p&gt;Anyone who has owned a property has had this argument with themselves. Do I take&lt;br&gt;
the steady long-term tenant, or do I furnish it and put it on Airbnb for more per&lt;br&gt;
night but more hassle and more empty nights? Most people decide it on a feeling,&lt;br&gt;
or on one Airbnb listing they saw once, which is not data, it is an anecdote.&lt;/p&gt;

&lt;p&gt;The honest version of this decision needs four numbers for the same area: what is&lt;br&gt;
for sale, what recently sold, what long-term rents ask, and what short-term&lt;br&gt;
rentals actually earn. Those normally live in four different tools. I put them in&lt;br&gt;
one call.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually did
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tools/call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;market_report&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Austin, TX"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Austin that came back in about 19 seconds with all four sides. The two&lt;br&gt;
numbers I put next to each other were a recently sold 3 bed, 1,984 square feet at&lt;br&gt;
a $648,000 estimate in ZIP 78739, and a downtown condo renting on the short-term&lt;br&gt;
market at $808 for three nights, rated 4.97 across 387 reviews.&lt;/p&gt;

&lt;p&gt;Those are different ZIPs and different property types, so it is not a direct&lt;br&gt;
swap. But it is the exact comparison the decision requires, and having both sides&lt;br&gt;
in the same object means the arithmetic is right there instead of scattered&lt;br&gt;
across four tabs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to actually decide with it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pull the four sides for your specific area.&lt;/strong&gt; Not a national average, your&lt;br&gt;
ZIP. Real estate is local and averages lie.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Anchor on the sold price, not the asking price.&lt;/strong&gt; What is listed is a hope.&lt;br&gt;
What sold is what the market paid. Your yield math has to start from the real&lt;br&gt;
number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read the review count on the short-term side, not just the nightly rate.&lt;/strong&gt;&lt;br&gt;
A high nightly price on an empty calendar earns nothing. 387 reviews at 4.97&lt;br&gt;
is a property that is genuinely getting booked, which is a completely&lt;br&gt;
different thing from one that is merely listed at a high price.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do the yield both ways.&lt;/strong&gt; Long-term rent times twelve, against nightly rate&lt;br&gt;
times realistic occupancy. Now you are deciding on two numbers you trust&lt;br&gt;
instead of a feeling.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;The reason people get this wrong is that the four data points live in four&lt;br&gt;
places, so nobody assembles all four before deciding. They look at one Airbnb&lt;br&gt;
listing, get excited by the nightly number, and forget that empty nights and&lt;br&gt;
cleaning turn it into a job. Seeing supply, sold comps, long-term rent and real&lt;br&gt;
short-term performance together is what turns a hunch into a decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;Coverage is US only. The sold estimates are model output, not appraisals, and&lt;br&gt;
they come back labelled as such. A thin market returns fewer records. The&lt;br&gt;
short-term side reflects what is listed publicly, so it is a supply and pricing&lt;br&gt;
picture, not a landlord's actual tax return. But for making the rent-versus-list&lt;br&gt;
call with real numbers instead of a story, it is the fastest honest look I have&lt;br&gt;
found.&lt;/p&gt;

&lt;p&gt;The tool is the &lt;a href="https://apify.com/themineworks/real-estate-mcp" rel="noopener noreferrer"&gt;Real Estate MCP&lt;/a&gt;&lt;br&gt;
from The Mine Works, on Apify with your own account. It bills by outcome, so a&lt;br&gt;
location with no listings returns an empty report and costs nothing.&lt;/p&gt;

</description>
      <category>realestate</category>
      <category>investing</category>
    </item>
    <item>
      <title>How I stopped my cold emails from bouncing and wrecking my domain</title>
      <dc:creator>themineworks</dc:creator>
      <pubDate>Tue, 04 Aug 2026 05:05:00 +0000</pubDate>
      <link>https://dev.to/themineworks/how-i-stopped-my-cold-emails-from-bouncing-and-wrecking-my-domain-4h1a</link>
      <guid>https://dev.to/themineworks/how-i-stopped-my-cold-emails-from-bouncing-and-wrecking-my-domain-4h1a</guid>
      <description>&lt;p&gt;The first cold campaign I ever sent tanked my domain. I had a list of names and I&lt;br&gt;
had guessed the emails with the usual &lt;a href="mailto:first.last@company.com"&gt;first.last@company.com&lt;/a&gt; pattern. A third of&lt;br&gt;
them bounced, the mail provider noticed, and suddenly even my normal email was&lt;br&gt;
landing in spam. It took weeks to recover the sending reputation.&lt;/p&gt;

&lt;p&gt;The lesson is that a bounce is not a small miss. Every dead address you email&lt;br&gt;
teaches the mail providers that you are a spammer, and they treat your whole&lt;br&gt;
domain accordingly. So the real skill in cold outreach is not writing, it is&lt;br&gt;
making sure every address you send to is actually alive before you send.&lt;/p&gt;
&lt;h2&gt;
  
  
  The mistake everyone makes
&lt;/h2&gt;

&lt;p&gt;People verify their list at the end, if at all, as a separate cleanup step. By&lt;br&gt;
then the guessed addresses are already baked in. The fix is to make discovery and&lt;br&gt;
verification the same step, so the list you export has already been checked.&lt;/p&gt;

&lt;p&gt;Here is the call I run on a company now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tools/call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;prospect_dossier&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Notion"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"notion.so"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It finds the people, pulls contact channels off the company's own site, and then&lt;br&gt;
does the thing that matters: it runs a live check on every email it found,&lt;br&gt;
chained onto the discovery. The verification is not against a list I typed. It is&lt;br&gt;
against whatever the discovery just surfaced, so by the time I read the output,&lt;br&gt;
every address has already been tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the verdicts honestly
&lt;/h2&gt;

&lt;p&gt;The check returns a verdict per address, and the useful part is that it does not&lt;br&gt;
round everything up to "valid." In my runs it returned &lt;code&gt;invalid&lt;/code&gt; for a dead&lt;br&gt;
address, &lt;code&gt;risky&lt;/code&gt; for a role mailbox, and &lt;code&gt;unknown&lt;/code&gt; for one behind a catch-all&lt;br&gt;
server.&lt;/p&gt;

&lt;p&gt;That &lt;code&gt;unknown&lt;/code&gt; is the one to understand. A catch-all server accepts every&lt;br&gt;
address you throw at it and tells you nothing, so any tool that reports catch-alls&lt;br&gt;
as valid is inventing a number to make its accuracy look good. Honest is&lt;br&gt;
&lt;code&gt;unknown&lt;/code&gt;, and knowing an address is unknowable is itself worth having, because&lt;br&gt;
you send to it at your own risk rather than blind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Discover and verify in one call.&lt;/strong&gt; Do not treat verification as a later&lt;br&gt;
cleanup. Chain it, so nothing enters your list unchecked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Drop everything marked invalid.&lt;/strong&gt; These are the ones that bounce. Removing&lt;br&gt;
them is the single action that protects your domain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decide on risky and unknown deliberately.&lt;/strong&gt; Role mailboxes and catch-alls&lt;br&gt;
are judgement calls, not automatic sends. At least now you are making the&lt;br&gt;
call with eyes open.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;An invalid verdict is a real result, and worth paying for, because knowing an&lt;br&gt;
address is dead before you send is exactly what saves your domain. The only&lt;br&gt;
thing you should not pay for is a guess dressed up as a fact, which is what a&lt;br&gt;
pattern-generated list is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;Verification cannot see past a catch-all server, and it says &lt;code&gt;unknown&lt;/code&gt; rather&lt;br&gt;
than pretending. Discovery quality depends on how much a company publishes about&lt;br&gt;
itself, so pass a domain rather than a bare name, it materially improves the&lt;br&gt;
result. This is public data for outreach, nothing from a private database.&lt;/p&gt;

&lt;p&gt;The tool is the &lt;a href="https://apify.com/themineworks/lead-generation-mcp" rel="noopener noreferrer"&gt;Lead Generation MCP&lt;/a&gt;&lt;br&gt;
from The Mine Works, on Apify with your own account. It bills per result, and a&lt;br&gt;
company where it finds nothing costs nothing.&lt;/p&gt;

</description>
      <category>sales</category>
      <category>marketing</category>
    </item>
    <item>
      <title>The Reddit thread that warned me about a product before the numbers did</title>
      <dc:creator>themineworks</dc:creator>
      <pubDate>Mon, 03 Aug 2026 08:50:00 +0000</pubDate>
      <link>https://dev.to/themineworks/the-reddit-thread-that-warned-me-about-a-product-before-the-numbers-did-2jdl</link>
      <guid>https://dev.to/themineworks/the-reddit-thread-that-warned-me-about-a-product-before-the-numbers-did-2jdl</guid>
      <description>&lt;p&gt;Dashboards are always late. By the time churn shows up in a chart, the decision&lt;br&gt;
that caused it was made weeks ago, by users who had already made up their minds&lt;br&gt;
and were talking about it somewhere you were not looking. I got tired of finding&lt;br&gt;
out about problems after they were expensive, so I started reading the places&lt;br&gt;
people actually complain, on a schedule.&lt;/p&gt;

&lt;p&gt;The insight is simple. A sentiment score going down tells you something is wrong.&lt;br&gt;
It does not tell you what, and by the time you go find out, the thread has 300&lt;br&gt;
comments. The actual complaint, in the user's own words, is worth more than any&lt;br&gt;
score, and it shows up days before the metric moves.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I actually did
&lt;/h2&gt;

&lt;p&gt;I run one call that pulls a topic across Reddit, Threads, LinkedIn, news, X and&lt;br&gt;
Google Trends at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tools/call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;brand_pulse_report&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"topic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Notion"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the run I am describing, four of the six sources returned and two came back&lt;br&gt;
empty, so it billed the partial price and told me which two were empty rather&lt;br&gt;
than quietly dropping them. The Reddit section is what I read first, and the top&lt;br&gt;
thread was titled "How Notion is losing its credibility with the Notion AI&lt;br&gt;
pricing mess."&lt;/p&gt;

&lt;p&gt;That sentence is the whole point. It is specific, it has a cause, and it was&lt;br&gt;
written by someone who cared enough to post it. No dashboard produces that.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I turn it into an early warning
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pick the topic.&lt;/strong&gt; Your product, a competitor, or a category. Whatever you&lt;br&gt;
need to not be surprised about.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run it daily and read the top threads, not the counts.&lt;/strong&gt; The number of&lt;br&gt;
posts is noise. The content of the loudest thread is the signal. You are&lt;br&gt;
looking for a specific complaint that keeps recurring.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Watch for a complaint that gains traction.&lt;/strong&gt; One angry post is nothing.&lt;br&gt;
The same complaint, phrased slightly differently, showing up across Reddit&lt;br&gt;
and Threads and LinkedIn in the same week, is a churn driver forming in&lt;br&gt;
public, and you are reading it while there is still time to respond.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;People do not fill out your exit survey. They post on Reddit. The most honest&lt;br&gt;
feedback about any product is written by users with no reason to be polite, in&lt;br&gt;
places the company is not officially watching. Getting those posts into a tool&lt;br&gt;
you can read every morning means you find the problem while it is still a&lt;br&gt;
thread, not after it is a trend in your revenue.&lt;/p&gt;

&lt;p&gt;The same call points at a competitor works in reverse. Their unhappy users are&lt;br&gt;
describing, for free, exactly the thing you should build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;This reads public posts only. No private groups, no DMs. On the run above, X and&lt;br&gt;
Google Trends came back empty, which happens, and the tool says so rather than&lt;br&gt;
pretending otherwise. And it hands you the posts rather than a sentiment score&lt;br&gt;
on purpose, because your own reading of a real complaint beats a lexicon&lt;br&gt;
counting positive and negative words.&lt;/p&gt;

&lt;p&gt;The tool is the &lt;a href="https://apify.com/themineworks/social-research-mcp" rel="noopener noreferrer"&gt;Social &amp;amp; Market Research MCP&lt;/a&gt;&lt;br&gt;
from The Mine Works, on Apify with your own account. It bills only for the&lt;br&gt;
sources that return, so a quiet topic costs almost nothing and an empty one&lt;br&gt;
costs nothing at all.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>marketing</category>
    </item>
    <item>
      <title>How I check out a company in the time it takes to make coffee</title>
      <dc:creator>themineworks</dc:creator>
      <pubDate>Sun, 02 Aug 2026 06:10:00 +0000</pubDate>
      <link>https://dev.to/themineworks/how-i-check-out-a-company-in-the-time-it-takes-to-make-coffee-1eco</link>
      <guid>https://dev.to/themineworks/how-i-check-out-a-company-in-the-time-it-takes-to-make-coffee-1eco</guid>
      <description>&lt;p&gt;I got burned once by a vendor that looked fine on the website and turned out to&lt;br&gt;
be in the middle of a lawsuit and registered in a completely different name than&lt;br&gt;
the one on the contract. After that I started checking companies before I signed&lt;br&gt;
anything or got on a first call. The problem was doing it properly takes an hour&lt;br&gt;
of opening the same six websites, so I mostly skipped it, which is exactly how&lt;br&gt;
you get burned again.&lt;/p&gt;

&lt;p&gt;Then I collapsed the whole check into one call, and now I run it on everyone.&lt;/p&gt;
&lt;h2&gt;
  
  
  What the check actually covers
&lt;/h2&gt;

&lt;p&gt;Proper due diligence means the legal entity (is this a real registered company,&lt;br&gt;
and which one), the filings, any litigation, whether they take government money,&lt;br&gt;
and their reputation. Those live on SEC EDGAR, the GLEIF registry, state business&lt;br&gt;
registries, CourtListener and USAspending. Five sites, five different search&lt;br&gt;
boxes.&lt;/p&gt;

&lt;p&gt;Here is the single call I run instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tools/call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;full_diligence_report&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Palantir Technologies"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ticker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PLTR"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Palantir that came back in about 50 seconds. The part that stopped me was the&lt;br&gt;
entity section: alongside the US parent it returned the India subsidiary,&lt;br&gt;
Palantir Shakti Technologies. Nobody types that name into a search box, because&lt;br&gt;
nobody knows it exists. It shows up because the legal-entity lookup returns the&lt;br&gt;
whole corporate family from the one name you asked about.&lt;/p&gt;

&lt;p&gt;The rest came with it: the SEC identity (CIK 0001321655), the ten most recent&lt;br&gt;
filings, ten court cases including one at the Delaware Supreme Court, and ten&lt;br&gt;
federal contracts topped by a single Army task order worth $442,883,216.67.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I use it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run it on the name before the first call.&lt;/strong&gt; By the time I am on the call I&lt;br&gt;
know their real corporate structure, whether they are in litigation, and how&lt;br&gt;
much of their revenue is government contracts. That changes what questions I&lt;br&gt;
ask.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read the court and contract sections first.&lt;/strong&gt; Those are the two that&lt;br&gt;
actually change a decision and the two that take longest to find by hand. A&lt;br&gt;
company with heavy government revenue concentration is a different risk than&lt;br&gt;
one without, and you want to know that before you are dependent on them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Watch the entity section for surprises.&lt;/strong&gt; Subsidiaries, a registered agent&lt;br&gt;
that does not match, a formation state that makes no sense. The structure&lt;br&gt;
tells you things the marketing site never will.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;Every piece of this is a public record that a company is required to file. The&lt;br&gt;
information was always there. The only thing stopping people from using it is&lt;br&gt;
that it is spread across five government databases with bad search. Put them&lt;br&gt;
behind one call and a proper check costs less than the coffee you make while it&lt;br&gt;
runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;It reads public records, so it is only as good as the public record. A private&lt;br&gt;
company in a state with thin disclosure returns less than a public one. The&lt;br&gt;
court search covers US federal and state opinions in CourtListener, not every&lt;br&gt;
county filing. If the answer is not in a public database, it tells you it found&lt;br&gt;
nothing rather than guessing, which is the point.&lt;/p&gt;

&lt;p&gt;The tool is the &lt;a href="https://apify.com/themineworks/company-diligence-mcp" rel="noopener noreferrer"&gt;Company Diligence MCP&lt;/a&gt;&lt;br&gt;
from The Mine Works, on Apify with your own account. It bills only when a section&lt;br&gt;
returns something, so a clean company with no litigation costs nothing for the&lt;br&gt;
empty court check.&lt;/p&gt;

</description>
      <category>business</category>
      <category>security</category>
    </item>
    <item>
      <title>How I see every ad my competitor is running, without any inside access</title>
      <dc:creator>themineworks</dc:creator>
      <pubDate>Sat, 01 Aug 2026 03:44:00 +0000</pubDate>
      <link>https://dev.to/themineworks/how-i-see-every-ad-my-competitor-is-running-without-any-inside-access-468g</link>
      <guid>https://dev.to/themineworks/how-i-see-every-ad-my-competitor-is-running-without-any-inside-access-468g</guid>
      <description>&lt;p&gt;For a long time I assumed knowing what a competitor was advertising required&lt;br&gt;
some tool I could not afford, or a friend on the inside. It turns out the whole&lt;br&gt;
thing is public, and most people never look because they do not know where.&lt;/p&gt;

&lt;p&gt;Meta runs an Ad Library. By law, every ad running on Facebook and Instagram is&lt;br&gt;
listed there, searchable by brand, with the creative, the format, and the dates&lt;br&gt;
it has been live. It is open to anyone. The catch is the interface is slow and&lt;br&gt;
built for one-ad-at-a-time browsing, so nobody uses it for real analysis. I wired&lt;br&gt;
it to pull the whole picture in one call.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I actually did
&lt;/h2&gt;

&lt;p&gt;Here is the call I run against a competitor's name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tools/call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;competitor_ads&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"search_terms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Nike"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"all"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Nike that came back in about ten seconds with live ads, including a&lt;br&gt;
Spanish-language birthday promotion running across Facebook, Instagram, Audience&lt;br&gt;
Network and Messenger. Each ad comes back with its creative text, its media type,&lt;br&gt;
the advertiser page, and the dates it has been running.&lt;/p&gt;

&lt;p&gt;That last field is the one that matters, and I will explain why.&lt;/p&gt;

&lt;h2&gt;
  
  
  The step that turns ads into intelligence
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pull all active ads for the competitor.&lt;/strong&gt; You now have their entire live&lt;br&gt;
creative in front of you, not a guess.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sort by how long each ad has been running.&lt;/strong&gt; This is the tell. A brand&lt;br&gt;
kills ads that do not perform, fast, because they cost money every day. So an&lt;br&gt;
ad that has been live for four months is not luck. It is their best&lt;br&gt;
performer, the one they have tested against everything else and kept.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read the long-runners, ignore the rest.&lt;/strong&gt; The ad that has survived since&lt;br&gt;
March is telling you which message, which offer, and which audience is&lt;br&gt;
working for them right now. You just got their best-tested marketing angle&lt;br&gt;
for free.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Watch for new entrants.&lt;/strong&gt; Run it weekly. A brand-new ad that suddenly gets&lt;br&gt;
heavy placement is a launch or a new campaign. You are seeing it on day one.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;Advertisers pay by the day. That single fact makes their spending honest in a&lt;br&gt;
way their marketing never is. They will tell you anything in a press release,&lt;br&gt;
but they will not pay to keep running an ad that does not sell. Duration is a&lt;br&gt;
vote they place with real money, every day, and it is all public record.&lt;/p&gt;

&lt;p&gt;You are not spying. You are reading a disclosure they are legally required to&lt;br&gt;
make, in a format they hoped was too tedious to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;This is Meta only, so Facebook, Instagram and their network. It does not cover&lt;br&gt;
Google, TikTok or other channels. And you see the creative and the run dates,&lt;br&gt;
not the spend amount or the exact audience, unless the ad is political. But for&lt;br&gt;
figuring out what message a competitor believes in enough to keep paying for,&lt;br&gt;
duration is most of the answer.&lt;/p&gt;

&lt;p&gt;The tool is the &lt;a href="https://apify.com/themineworks/ecommerce-intel-mcp" rel="noopener noreferrer"&gt;E-commerce Intelligence MCP&lt;/a&gt;&lt;br&gt;
from The Mine Works, running on Apify with your own account. It bills per ad&lt;br&gt;
returned, so a competitor sweep costs a few cents and a name with no ads costs&lt;br&gt;
nothing.&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>How I started finding jobs a week before they hit LinkedIn</title>
      <dc:creator>themineworks</dc:creator>
      <pubDate>Fri, 31 Jul 2026 11:47:25 +0000</pubDate>
      <link>https://dev.to/themineworks/how-i-started-finding-jobs-a-week-before-they-hit-linkedin-3281</link>
      <guid>https://dev.to/themineworks/how-i-started-finding-jobs-a-week-before-they-hit-linkedin-3281</guid>
      <description>&lt;p&gt;I spent a job search refreshing LinkedIn like everyone else, and I kept noticing&lt;br&gt;
the same thing: by the time a role showed up in my feed, it already had 200&lt;br&gt;
applicants. The good ones were closing before I finished the cover letter.&lt;/p&gt;

&lt;p&gt;Then a recruiter friend told me something that changed how I looked for work.&lt;br&gt;
Companies do not post to LinkedIn first. They post to their own applicant&lt;br&gt;
tracking system first, the Greenhouse or Lever or Workday page that runs their&lt;br&gt;
careers site. The job boards scrape those pages later. Sometimes days later.&lt;br&gt;
So the freshest possible version of a job is the one sitting on the company's&lt;br&gt;
own ATS, before any aggregator has touched it.&lt;/p&gt;

&lt;p&gt;The problem is you would have to check dozens of career pages by hand every&lt;br&gt;
morning. I did not want to do that. So I wired it up to check for me.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I actually did
&lt;/h2&gt;

&lt;p&gt;I use a small MCP tool that reads ATS boards directly. Here is the exact call I&lt;br&gt;
run against a list of companies I want to work for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tools/call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;search_jobs_ats&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"companies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"stripe"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Remote"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Stripe that came back in a few seconds with live postings straight off their&lt;br&gt;
ATS, including "Account Executive, AI Sales (Grower)" in San Francisco, before I&lt;br&gt;
had seen it anywhere else. The output is structured: title, team, location, and&lt;br&gt;
the direct apply link. No scrolling, no login, no feed algorithm deciding what I&lt;br&gt;
get to see.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make your target list.&lt;/strong&gt; Pick 15 to 30 companies you would actually take a&lt;br&gt;
job at. Their names or ATS slugs are all you need.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run the pull once.&lt;/strong&gt; One call returns every open role across those&lt;br&gt;
companies. Read it like a table. I filter for my title and my location and&lt;br&gt;
ignore the rest.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Put it on a schedule.&lt;/strong&gt; This is the part that matters. I run the same call&lt;br&gt;
every morning at 7am and diff it against yesterday. A new row means a role&lt;br&gt;
that went live in the last 24 hours, usually before it reached the boards.&lt;br&gt;
That is the window where you are applicant number 3, not number 300.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this works
&lt;/h2&gt;

&lt;p&gt;An ATS is the source. Everything else is a copy. A role that closed yesterday is&lt;br&gt;
already gone from the company's ATS but still sitting stale on three job boards,&lt;br&gt;
which is why board listings waste your time. Run it the other way and the same&lt;br&gt;
fact helps you: the newest thing on the ATS is the newest thing that exists.&lt;/p&gt;

&lt;p&gt;The boards are optimised for their traffic, not your timing. Reading the source&lt;br&gt;
directly is the whole hack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;This only covers companies whose ATS I can read (Greenhouse, Lever, Workday,&lt;br&gt;
Ashby). A company on a different system returns nothing. And "before LinkedIn"&lt;br&gt;
is often hours, sometimes a day or two, not always a week. But being early by&lt;br&gt;
even a day on a role you want is the difference that gets you the first&lt;br&gt;
screen.&lt;/p&gt;

&lt;p&gt;The tool is the &lt;a href="https://apify.com/themineworks/recruiting-jobs-mcp" rel="noopener noreferrer"&gt;Recruiting &amp;amp; Jobs MCP&lt;/a&gt;&lt;br&gt;
from The Mine Works. It runs on Apify with your own account, and it bills per&lt;br&gt;
result, so a morning check on 20 companies costs a few cents and a search that&lt;br&gt;
finds nothing new costs nothing.&lt;/p&gt;

</description>
      <category>career</category>
      <category>jobsearch</category>
      <category>productivity</category>
      <category>careeradvice</category>
    </item>
  </channel>
</rss>
