<?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: Zakaria Blefkih</title>
    <description>The latest articles on DEV Community by Zakaria Blefkih (@7_akariae).</description>
    <link>https://dev.to/7_akariae</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%2F4111486%2F03257043-722d-41a2-9256-0f13a9f601c6.jpg</url>
      <title>DEV Community: Zakaria Blefkih</title>
      <link>https://dev.to/7_akariae</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/7_akariae"/>
    <language>en</language>
    <item>
      <title>How to build a creator emails pipeline in one Python call</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Mon, 21 Sep 2026 03:37:47 +0000</pubDate>
      <link>https://dev.to/7_akariae/how-to-build-a-creator-emails-pipeline-in-one-python-call-39eb</link>
      <guid>https://dev.to/7_akariae/how-to-build-a-creator-emails-pipeline-in-one-python-call-39eb</guid>
      <description>&lt;p&gt;Assembling a list of creator emails by hand means three browser tabs, three different column layouts and a lot of copy-paste. None of TikTok, Instagram or YouTube publishes a contact email field, so every address has to be read out of a bio or found on the website the creator links to. And once you have it, you still do not know whether the domain behind it accepts mail at all.&lt;/p&gt;

&lt;p&gt;Running three single-platform scrapers is not much better: you get three exports with three different column sets, three separate crawls over the same websites, and no way to see that a brand's TikTok row and its YouTube row are the same business. This post walks through &lt;a href="https://apify.com/flash_scraper/creator-leads-scraper" rel="noopener noreferrer"&gt;Creator Leads Scraper&lt;/a&gt;, an Apify actor by flash_scraper that scrapes TikTok, Instagram and YouTube profiles in a single run, with one row per creator and the same 54 columns on every row, and shows how to pull YouTube creator emails by keyword with one Python call. YouTube is the discovery platform here; TikTok and Instagram enrich the handles you supply.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;p&gt;Every row has the same 54 columns whichever platform it came from — 48 builder columns plus 6 derived ones appended at the end, so a header-mapped import never shifts. A column a platform cannot supply is &lt;code&gt;null&lt;/code&gt;, never missing and never an empty string. The eight columns you will filter on most:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Label&lt;/th&gt;
&lt;th&gt;What it holds&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;platform&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;tiktok&lt;/code&gt;, &lt;code&gt;instagram&lt;/code&gt; or &lt;code&gt;youtube&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;followers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Followers&lt;/td&gt;
&lt;td&gt;Followers or subscribers — the column every follower filter uses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;followers_estimated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Followers rounded&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;true&lt;/code&gt; when the platform rounds the number (YouTube always does)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;email&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;The best address found for the creator, from bio text or the linked website&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;email_source&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Email source&lt;/td&gt;
&lt;td&gt;Whether the address came from &lt;code&gt;bio&lt;/code&gt; or &lt;code&gt;website&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;email_status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Email status&lt;/td&gt;
&lt;td&gt;The verification grade of the best address: &lt;code&gt;deliverable&lt;/code&gt; / &lt;code&gt;risky&lt;/code&gt; / &lt;code&gt;undeliverable&lt;/code&gt; / &lt;code&gt;unknown&lt;/code&gt; when an email exists, &lt;code&gt;missing&lt;/code&gt; when none does&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lead_score&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lead score&lt;/td&gt;
&lt;td&gt;0–100 score, computed as points earned divided by the platform's maximum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;discovered_via&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Found via&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;input&lt;/code&gt;, &lt;code&gt;youtube_search&lt;/code&gt;, &lt;code&gt;youtube_link&lt;/code&gt; or &lt;code&gt;instagram_related&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A few more are worth knowing. &lt;code&gt;also_on_platforms&lt;/code&gt; (Also on) names every other platform this creator was found on, &lt;code&gt;matched_keyword&lt;/code&gt; records the &lt;code&gt;searchKeywords&lt;/code&gt; entry whose search returned a YouTube channel, and six social URL columns (&lt;code&gt;instagram_url&lt;/code&gt; through &lt;code&gt;linkedin_url&lt;/code&gt;) form a complete social card. Every run downloads as CSV, JSON or Excel with five saved views.&lt;/p&gt;

&lt;p&gt;The verification behind &lt;code&gt;email_status&lt;/code&gt; is four checks over DNS and none over SMTP: syntax, an MX record on the domain, a role-address check (a role alias grades &lt;code&gt;risky&lt;/code&gt;), and a bundled list of about 8,000 disposable domains that grades &lt;code&gt;undeliverable&lt;/code&gt;. No mailbox is ever probed, so read &lt;code&gt;deliverable&lt;/code&gt; as "the domain accepts mail and the address is not a known-bad shape", not as proof that the mailbox exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real run
&lt;/h2&gt;

&lt;p&gt;Here is the receipt from a throwaway run on 2026-09-21, using the actor's own "paste and run" input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input:   { "platforms": ["youtube"], "searchKeywords": ["home barista"], "maxCreators": 10 }
run:     SUCCEEDED 38.0s
status:  Done — 10 creator leads delivered for "home barista" (YouTube 10); 5 carry an email.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ten creators asked for, ten delivered, five of them with an email, in 38.0 seconds. &lt;code&gt;maxCreators&lt;/code&gt; counts creators &lt;em&gt;delivered&lt;/em&gt;, not scraped: filters run before the count, and with an email filter set the run keeps discovering in waves (at most 3 extra) until the number you asked for is delivered or every candidate was tried. A blocked or empty platform is reported in the status message by name, never silently skipped, and every run also writes a machine-readable &lt;code&gt;RUN_SUMMARY&lt;/code&gt; record to its key-value store.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Python call
&lt;/h2&gt;

&lt;p&gt;This is the "smallest useful call" from the README, using the &lt;code&gt;apify-client&lt;/code&gt; package. The same JSON works in the Console, the REST API and n8n/Make/Zapier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;APIFY_TOKEN&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flash_scraper/creator-leads-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;platforms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youtube&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;searchKeywords&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;home barista&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxCreators&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enrichEmails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;rows&lt;/code&gt; is a list of dicts, one per creator, with all 54 keys present. Two knobs turn this into a pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;enrichEmails&lt;/code&gt;&lt;/strong&gt; is &lt;code&gt;False&lt;/code&gt; above to keep the call minimal. Its default is &lt;code&gt;true&lt;/code&gt;, and it is the main email source on all three platforms: every creator's linked site is visited (home, &lt;code&gt;/contact&lt;/code&gt;, &lt;code&gt;/about&lt;/code&gt;) for emails and social profiles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;onlyWithEmail: true&lt;/code&gt;&lt;/strong&gt; drops creators with no email found, before billing. The README's keyword recipe is &lt;code&gt;{ "platforms": ["youtube"], "searchKeywords": ["vegan meal prep"], "maxCreators": 30, "onlyWithEmail": true }&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To run it as a monitor, schedule it in Apify Console and set &lt;code&gt;onlyNewCreators: true&lt;/code&gt;. The first run is your baseline; every run after it delivers, and bills, only the creators that have appeared since, and a quiet week returns zero rows and charges nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;You are charged per creator lead delivered after filtering. At the live free-plan rate (measured 2026-08-29) that is $0.002 per lead — $2 per 1,000 creator leads, so $5 buys 2,500 leads. The only other billable event is $0.002 per AI opener, which exists only when you turn &lt;code&gt;writeOpeners&lt;/code&gt; on with your own LLM key.&lt;/p&gt;

&lt;p&gt;A free Apify account's $5 monthly platform credit therefore covers up to 2,500 creator leads at this rate, less the run's own compute usage. Rows removed by your filters cost nothing, handles that were blocked or do not exist cost nothing, and a run that delivers zero rows charges nothing. The Store Pricing tab is authoritative if the rate changes, and paid plans pay less.&lt;/p&gt;

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

&lt;p&gt;The README has a section called "What this Actor does not do". Its points, in short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No TikTok or Instagram keyword/hashtag search.&lt;/strong&gt; Logged-out HTTP exposes no &lt;code&gt;/tag/&lt;/code&gt; data on TikTok and Instagram's search endpoints answer 302/401 (probed 2026-08-09). You supply the handles; YouTube keyword search is the discovery path, optionally hopping to the Instagram/TikTok profiles those channels link to via &lt;code&gt;crossPlatformDiscovery&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No phone numbers, on any platform.&lt;/strong&gt; None of the three publishes one, so no phone column exists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No engagement rate on TikTok or YouTube rows.&lt;/strong&gt; TikTok's public payload carries no play counts (28 of 28 profiles probed) and YouTube's About page carries no per-video likes or comments. Instagram rows carry real engagement metrics from ~12 recent posts; YouTube rows carry lifetime &lt;code&gt;avg_views_per_video&lt;/code&gt; instead, plus an approximate posting cadence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No guaranteed email per row.&lt;/strong&gt; Emails exist only where the creator published one (bio or linked site). In the 2026-08-09 verification runs, 3 of 9 TikTok creators, 1 of 5 Instagram creators and 6 of 9 YouTube channels on one keyword (4 of 8 on another) ended up with an email after enrichment. Those are small samples; read them as an order of magnitude.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No audience demographics, follower lists, post scraping or DM sending.&lt;/strong&gt; One row per creator profile is the entire product.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more caveat from the same README: the email behind YouTube's "View email address" button is not read. That button needs a Google login, a reCAPTCHA and a small daily reveal quota, and the actor stays keyless and logged-out. The row does say whether the button exists, in &lt;code&gt;has_business_email&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;If you want to see the output before writing any code, the example task &lt;a href="https://apify.com/flash_scraper/creator-leads-scraper/examples/fitness-youtube-creators-emails" rel="noopener noreferrer"&gt;Find fitness YouTube creators with emails&lt;/a&gt; runs a ready-made input. The actor page and pricing are at &lt;a href="https://apify.com/flash_scraper/creator-leads-scraper" rel="noopener noreferrer"&gt;apify.com/flash_scraper/creator-leads-scraper&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>python</category>
      <category>marketing</category>
      <category>api</category>
    </item>
    <item>
      <title>How to scrape local business leads with MX-verified emails in Python</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Mon, 21 Sep 2026 03:37:10 +0000</pubDate>
      <link>https://dev.to/7_akariae/how-to-scrape-local-business-leads-with-mx-verified-emails-in-python-4de0</link>
      <guid>https://dev.to/7_akariae/how-to-scrape-local-business-leads-with-mx-verified-emails-in-python-4de0</guid>
      <description>&lt;p&gt;Building a table of local business leads usually means chaining several tools: one to discover the businesses in a city, one to find each business's website, one to pull an email off that site, and a verifier so you are not loading dead mailboxes into your CRM. Each category tends to need its own scraper, each scraper needs a proxy budget, and the output columns shift every time one link in the chain changes.&lt;/p&gt;

&lt;p&gt;This post walks through one Apify actor, &lt;strong&gt;Local Business Leads Scraper&lt;/strong&gt; by flash_scraper, that collapses that stack into a single actor call. It discovers businesses on OpenStreetMap, crawls each business's own public website, MX-verifies the email it finds and scores every row 0-100, with no API key, no proxy and no login. Used as a business email finder it returns not just the address but whose mailbox that address is. Everything below comes from the actor's README, its dataset schema and one real throwaway run; nothing is estimated.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;p&gt;One row per business, 73 stable columns wide, exported as CSV, JSON or Excel. The dataset schema describes a row as "identity, location, phone, MX-verified email, socials, website platform and marketing tech, a 0-100 lead score with an A-F grade, and the OpenStreetMap provenance of the row." It covers 95 curated categories (220+ terms) in any city on earth. The eight columns you will read first:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Title&lt;/th&gt;
&lt;th&gt;What the schema says it holds&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;Business name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;phone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Phone&lt;/td&gt;
&lt;td&gt;Primary phone — the OSM tag, and only the OSM tag; never filled from the site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;email&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;Primary contact email, chosen by mailbox ownership then deliverability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;email_status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Email status&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;deliverable&lt;/code&gt; / &lt;code&gt;risky&lt;/code&gt; / &lt;code&gt;undeliverable&lt;/code&gt; when verification is on and a candidate exists; &lt;code&gt;missing&lt;/code&gt; when no email was found&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;email_type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mailbox owner&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;own_domain&lt;/code&gt; / &lt;code&gt;free_mail&lt;/code&gt; / &lt;code&gt;third_party&lt;/code&gt; / &lt;code&gt;unknown&lt;/code&gt; — &lt;code&gt;third_party&lt;/code&gt; means the address belongs to the business's marketing agency or web designer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;website_platform&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Website platform&lt;/td&gt;
&lt;td&gt;CMS / site builder: WordPress, Wix, Shopify, Squarespace, Webflow, GoDaddy, Weebly, Duda and more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lead_score&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lead score&lt;/td&gt;
&lt;td&gt;0-100 completeness/reachability score&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lead_grade&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Grade&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;A&lt;/code&gt; ≥80, &lt;code&gt;B&lt;/code&gt; ≥65, &lt;code&gt;C&lt;/code&gt; ≥50, &lt;code&gt;D&lt;/code&gt; ≥35, else &lt;code&gt;F&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two of those deserve a note. &lt;code&gt;email_type&lt;/code&gt; decides whether a lead is usable at all: the schema says a &lt;code&gt;third_party&lt;/code&gt; address "is deliverable but does not reach the business, and it is scored at half weight." &lt;code&gt;email_status&lt;/code&gt; is the result of four checks that run over DNS and never over SMTP: syntax, a mail-server lookup on the domain, a role-address check and a disposable-domain list. No mailbox is ever probed, which is what keeps verification proxy-free and included in the price.&lt;/p&gt;

&lt;p&gt;Every row also carries &lt;code&gt;google_maps_url&lt;/code&gt; (a constructed search link; nothing is scraped from Google to build it), &lt;code&gt;osm_url&lt;/code&gt; pointing at the source OpenStreetMap element, and &lt;code&gt;attribution&lt;/code&gt;, the ODbL string the licence requires you to keep with an exported CSV.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real run
&lt;/h2&gt;

&lt;p&gt;A throwaway run from 2026-09-21, minimal input, no filters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input:  category 'dentist', location 'Austin, Texas', maxItems 10
run:    SUCCEEDED 16.9s
STATUS MESSAGE: Done — 10 leads delivered for dentists in Austin, Texas. 1 with email (10%), 2 with phone (20%), 2 contactable (20%). 8 of these 10 row(s) have no phone, no email and no social profile — add requireAnyContact: true to drop them before they are charged.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The status message is the honest part. A bare API call keeps every mapped location, including the ones with nothing to contact, and the actor says so and names the switch that fixes it. The README's filter-off benchmark reports the same at larger scale: on a bare &lt;code&gt;{}&lt;/code&gt; run of 100 Austin dentists, "50 of the 52 rows with no website had no phone, no email and no social profile either." The Console form pre-fills &lt;code&gt;onlyWithWebsite&lt;/code&gt; and pre-ticks &lt;code&gt;requireAnyContact&lt;/code&gt;; API calls and schedules leave both off so existing inputs are unchanged.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;onlyWithWebsite: true&lt;/code&gt;, the README's reference run (dentist / Austin, Texas, 2026-08-08, n=55) measured a phone on 96% of rows, an MX-verified email on 55%, a detected website platform on 71% and a website on 100%. With every filter off (n=100) the same city measured 48% phone, 26% email and 34% platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Python call
&lt;/h2&gt;

&lt;p&gt;Copied from the README's "Smallest useful call"; the same JSON works in the Console, the REST API and n8n/Make/Zapier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;APIFY_TOKEN&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flash_scraper/local-business-leads&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dentist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Austin, Texas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;crawlEmails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sample sets &lt;code&gt;crawlEmails: False&lt;/code&gt;, which the README measured locally on 2026-08-29 at 10 rows in 17 s for $0.03 at the free-plan rate. For a normal run, remove that key or set it to &lt;code&gt;True&lt;/code&gt; as the README's fuller input examples do; the defaults are website crawling on, email verification on and 3 pages per website. An API call that sends no &lt;code&gt;maxItems&lt;/code&gt; gets 100; the Console form starts at 25.&lt;/p&gt;

&lt;p&gt;From there the pipeline is filters. &lt;code&gt;onlyWithWebsite&lt;/code&gt;, &lt;code&gt;onlyWithoutWebsite&lt;/code&gt;, &lt;code&gt;excludeKeywords&lt;/code&gt;, &lt;code&gt;excludeChains&lt;/code&gt; and &lt;code&gt;skipClosed&lt;/code&gt; are decided from the map data alone, before any website is crawled; &lt;code&gt;onlyWithEmail&lt;/code&gt;, &lt;code&gt;onlyVerifiedEmail&lt;/code&gt;, &lt;code&gt;requirePhone&lt;/code&gt;, &lt;code&gt;requireSocial&lt;/code&gt; and &lt;code&gt;requireAnyContact&lt;/code&gt; are applied as sites are crawled. Every one drops the row before it is pushed and before it is charged, so &lt;code&gt;maxItems&lt;/code&gt; means "this many rows I can use", and the run log names each filter and how many rows it removed. &lt;code&gt;outputFields&lt;/code&gt; narrows the columns; &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;attribution&lt;/code&gt; are always included.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;From the README's pricing section: "$5 per 1,000 delivered leads, which is $0.005 per lead on the free plan and less on paid plans." Read from the live pricing on 2026-09-14: $0.005 per delivered lead on the free plan and $0.0045 (Bronze) down to $0.0025 (Diamond) on paid plans. You are charged for delivered businesses only, not for API calls or compute, there is no subscription, and the Pricing tab is authoritative. MX verification, mailbox-ownership classification and lead scoring are included in the single per-lead rate; filtered rows are dropped before billing; a run that finds nothing charges nothing.&lt;/p&gt;

&lt;p&gt;The README's own arithmetic: the Console form as it opens (cap 25) costs at most $0.125 in leads, and 500 delivered rows cost $2.50; on the website-filtered reference run about 55% carried an email, so 500 rows is roughly 275 with an email. Since filters run before billing, &lt;code&gt;onlyWithEmail: true&lt;/code&gt; keeps the bill to rows that carry an email.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not do
&lt;/h2&gt;

&lt;p&gt;Copied from the README's own limits section:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It does not scrape Google Maps.&lt;/strong&gt; Listings come from OpenStreetMap, so there are no Google star ratings and no Google review counts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;rating&lt;/code&gt; and &lt;code&gt;review_count&lt;/code&gt; columns are sparse.&lt;/strong&gt; They exist only when a business publishes a rating in its own website markup, measured at about 7% of rows (4 of 55 on the 2026-08-08 reference run), and they are never a Google rating. Set &lt;code&gt;minRating&lt;/code&gt; or &lt;code&gt;minReviewCount&lt;/code&gt; and rows with no rating are dropped, not kept.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Van-based trades are thinly mapped.&lt;/strong&gt; OpenStreetMap held 171 dentists in the Austin bounding box but 9 plumbers and 5 electricians. A metro of a million people can return single digits for those categories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A guessed email is never sold as a verified one.&lt;/strong&gt; A pattern-guessed address stays in &lt;code&gt;email_guess&lt;/code&gt; and is never promoted into &lt;code&gt;email&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three more constraints to script around. A multi-search run is capped at 25 category x location combinations; above it the run fails before any network request and before any charge. Verification never contacts a mail server, so read &lt;code&gt;deliverable&lt;/code&gt; as "the domain accepts mail and the address is not a known-bad shape": a catch-all domain, or a mailbox deleted while the domain kept its mail servers, can still grade &lt;code&gt;deliverable&lt;/code&gt;. And the listings are ODbL data, so keep the &lt;code&gt;source&lt;/code&gt; and &lt;code&gt;attribution&lt;/code&gt; columns if you redistribute or publish the rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;One quick way to see the columns is the README's "Try it" example task, capped at 25 leads since 2026-09-01: &lt;a href="https://apify.com/flash_scraper/local-business-leads/examples/find-local-business-leads" rel="noopener noreferrer"&gt;Find local business leads with emails by category&lt;/a&gt;. The actor itself, with its Pricing tab, is at &lt;a href="https://apify.com/flash_scraper/local-business-leads" rel="noopener noreferrer"&gt;https://apify.com/flash_scraper/local-business-leads&lt;/a&gt;. Start at the form's cap of 25, read the status message, then raise &lt;code&gt;maxItems&lt;/code&gt; once the first run looks right.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>python</category>
      <category>leadgeneration</category>
      <category>api</category>
    </item>
    <item>
      <title>How to build a remote jobs scraper across 10 boards in one API call</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Mon, 21 Sep 2026 03:36:30 +0000</pubDate>
      <link>https://dev.to/7_akariae/how-to-build-a-remote-jobs-scraper-across-10-boards-in-one-api-call-1l21</link>
      <guid>https://dev.to/7_akariae/how-to-build-a-remote-jobs-scraper-across-10-boards-in-one-api-call-1l21</guid>
      <description>&lt;p&gt;Anyone who has written a remote jobs scraper by hand knows the shape of the work. RemoteOK serves JSON from &lt;code&gt;remoteok.com/api&lt;/code&gt;. We Work Remotely publishes an all-jobs RSS feed plus 13 category feeds, and no feed paginates. The Hacker News "Who is hiring?" thread is community-formatted posts (&lt;code&gt;Company | Role | Location | Salary&lt;/code&gt;) that you parse yourself. Ten sources, ten shapes, and the same posting often appears on more than one of them.&lt;/p&gt;

&lt;p&gt;This post walks through one way to skip that: &lt;code&gt;remote-job-aggregator&lt;/code&gt; by flash_scraper, an Apify actor that sweeps 10 keyless remote job boards in one run (RemoteOK, We Work Remotely, Working Nomads, DevITjobs US + UK, The Muse, Remotive, Jobicy, Himalayas and the Hacker News "Who is hiring?" thread) and returns one deduplicated feed with no API key, no proxy and no login. One opt-in board, Arbeitnow, joins only when you add it to &lt;code&gt;boards&lt;/code&gt;. Below: the columns, a real run receipt, the Python call, the price, and the limits the README lists about itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;p&gt;One row per remote job, the same columns on every row. The actor is a remote jobs aggregator rather than a single-board scraper: rows are merged across boards by canonical job URL and by &lt;code&gt;(title, company)&lt;/code&gt;, so the same role listed on two boards ships once. Eight of the columns, with titles and descriptions from the actor's dataset schema:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Schema title&lt;/th&gt;
&lt;th&gt;What it holds&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Location&lt;/td&gt;
&lt;td&gt;Exactly what the board provides, often a country restriction like "USA Only" or "Anywhere in the World".&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;salary_text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Salary&lt;/td&gt;
&lt;td&gt;Derived, always present: one readable string built from &lt;code&gt;salary_min&lt;/code&gt; / &lt;code&gt;salary_max&lt;/code&gt; / &lt;code&gt;salary_currency&lt;/code&gt; / &lt;code&gt;salary_interval&lt;/code&gt;, e.g. &lt;code&gt;$90,000–$175,000 / year&lt;/code&gt;; &lt;code&gt;""&lt;/code&gt; when the board published no figure.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;posted_at&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Posted&lt;/td&gt;
&lt;td&gt;Posting date, &lt;code&gt;YYYY-MM-DD&lt;/code&gt;, when the board provides one.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;source_board&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Source&lt;/td&gt;
&lt;td&gt;Which board this (first) copy of the job came from.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Link&lt;/td&gt;
&lt;td&gt;Direct link to the posting (for Remote OK rows this is the job's Remote OK page, as their API terms require).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;seniority&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Seniority&lt;/td&gt;
&lt;td&gt;Derived: &lt;code&gt;entry&lt;/code&gt;, &lt;code&gt;junior&lt;/code&gt;, &lt;code&gt;mid&lt;/code&gt;, &lt;code&gt;senior&lt;/code&gt;, &lt;code&gt;lead&lt;/code&gt;, &lt;code&gt;staff&lt;/code&gt;, &lt;code&gt;principal&lt;/code&gt;, &lt;code&gt;manager&lt;/code&gt;, &lt;code&gt;director&lt;/code&gt; or &lt;code&gt;unknown&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;also_on_boards&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Also on boards&lt;/td&gt;
&lt;td&gt;The other board ids this same posting was found on and merged away (&lt;code&gt;["remotive"]&lt;/code&gt;; &lt;code&gt;[]&lt;/code&gt; when none).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;job_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Job ID&lt;/td&gt;
&lt;td&gt;16-hex fingerprint of the job's canonical URL; stable across runs and the same identity &lt;code&gt;onlyNewJobs&lt;/code&gt; bills on, so use it as the upsert key.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hourly, daily, weekly, fortnightly and monthly salary figures are annualized (×2080 / ×260 / ×52 / ×26 / ×12); currency is left &lt;code&gt;null&lt;/code&gt; when the board doesn't state it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real run
&lt;/h2&gt;

&lt;p&gt;The receipt from a throwaway run on 2026-09-20 that ended up on the default input: all 10 boards, no keywords. Leaving &lt;code&gt;searchTerms&lt;/code&gt; empty is valid and returns up to &lt;code&gt;maxItems&lt;/code&gt; (default 100) of the current remote jobs across every board.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input: the schema defaults (all 10 boards, no keywords; the keys sent were not in the input schema and were ignored)
run: SUCCEEDED 6.648s
STATUS MESSAGE: Done — 100 remote job(s) delivered for all remote jobs (no keywords) from 10/10 boards (remoteok 10/99 · weworkremotely 10/100 · working_nomads 10/53 · devitjobs_us 10/72 · devitjobs_uk 10/45 · muse 10/100 · remotive 10/20 · jobicy 10/100 · himalayas 10/100 · hn_hiring 10/100); 11 cross-board duplicate(s) merged.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to read &lt;code&gt;remoteok 10/99&lt;/code&gt;: rows delivered from that board over the remote rows it offered before the keyword gate. Results are interleaved round-robin across boards, which is why each board contributed 10 rows to a 100-row order. The 11 cross-board duplicates were merged before the cap and before billing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Python call
&lt;/h2&gt;

&lt;p&gt;The README's "Smallest useful call", with &lt;code&gt;apify-client&lt;/code&gt;. The same JSON works in the Console, the REST API and n8n / Make / Zapier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;APIFY_TOKEN&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flash_scraper/remote-job-aggregator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;searchTerms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;boards&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;remoteok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jobicy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;remotive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;working_nomads&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details before you change the input. &lt;code&gt;boards&lt;/code&gt; here is restricted to the four single-request boards: the README measured 20 rows in 2 s on a local run on 2026-08-29, against 84 s across all ten boards that day, because Himalayas and The Muse are paginated feeds. And an API input that omits &lt;code&gt;matchDescriptions&lt;/code&gt; matches titles only; send &lt;code&gt;"matchDescriptions": true&lt;/code&gt; to also match tags and the first 500 characters of the description. &lt;code&gt;searchTerms&lt;/code&gt; is capped at 10 terms per run; &lt;code&gt;maxItems&lt;/code&gt; accepts 1–4000 and defaults to 100.&lt;/p&gt;

&lt;p&gt;To turn the call into a pipeline, set &lt;code&gt;onlyNewJobs: true&lt;/code&gt; and schedule it. Every later run delivers, and bills, only postings this exact search has never delivered before; a run where nothing is new finishes SUCCEEDED with zero rows and zero cost. Memory lives in a named key-value store in your own Apify account (&lt;code&gt;remote-job-monitor&lt;/code&gt;), pruned after 90 days. A ready-made example task: &lt;a href="https://apify.com/flash_scraper/remote-job-aggregator/examples/remote-new-jobs-alert-data-analyst" rel="noopener noreferrer"&gt;Daily new remote data analyst jobs alert (only new postings)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;$0.003 per deduplicated job, $3 per 1,000, with no per-run start fee. That is the actor's live pricing record read on 2026-09-14; the Pricing tab on the Store page is always authoritative. So 500 jobs = $1.50, and $5 buys 1,666 jobs (1,666 × $0.003 = $4.998). Apify's free plan needs no card, and its monthly usage credit ($5 at the time of writing) covers about 1,666 deduplicated jobs from this actor if spent on it alone. Paid plans pay less per row: $0.0027 on Bronze down to $0.0015 on Diamond.&lt;/p&gt;

&lt;p&gt;Duplicates merge before billing, filtered rows are never charged, and a nothing-new monitoring run or zero-match run charges nothing at all. The four-board call above is at most $0.06 (20 rows × $0.003).&lt;/p&gt;

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

&lt;p&gt;Taken from the README's own limits section and FAQ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No LinkedIn, Indeed or Glassdoor.&lt;/strong&gt; Those aren't remote-only boards, and this actor does not cover them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feed-limited depth.&lt;/strong&gt; These are public feeds, not archives: RemoteOK serves its ~100 newest rows, WeWorkRemotely ~100 per feed, Working Nomads ~50 curated rows, Jobicy 200 per call. The Muse and Himalayas paginate deeply (~1,980 and ~2,000 rows, measured 2026-08-19). A run cannot paginate years back; the ceiling is 4,000 deduplicated jobs per run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyword matching is client-side.&lt;/strong&gt; In title-only mode a Python job titled "Backend Engineer" won't match &lt;code&gt;"python"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Salary coverage varies by board:&lt;/strong&gt; 35% of rows on the measured 2026-08-15 default run. DevITjobs ~100% of its rows, RemoteOK ~3%, The Muse and Working Nomads none.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DevITjobs contributes remote rows only&lt;/strong&gt; (~8% of its inventory). Boards change: a board that is down or blocked on a given run is named in that run's status message, never silently, its rows are never billed, and its failure never poisons the other nine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HN rows are parsed from community-formatted posts.&lt;/strong&gt; Expect the occasional imperfect company/title split; only posts that explicitly say "remote" are included.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arbeitnow is opt-in for a reason.&lt;/strong&gt; A German city board; only rows it flags remote are delivered (34 remote among its first 450 rows, measured 2026-08-25) and it publishes no salary field. Jobspresso is not offered (HTTP 403 to Apify IPs, measured 2026-08-27).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schedule at most hourly; daily is what the boards justify.&lt;/strong&gt; Jobicy asks for at most one automated poll an hour and Remotive advises at most 4 requests a day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The boards' data terms pass through to you.&lt;/strong&gt; Remotive and Himalayas ask that listings not be resubmitted to third-party job sites or aggregators; Jobicy asks you to keep it as the source; Remote OK asks for a link back. Every row links to the board's own posting in &lt;code&gt;url&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where to run it
&lt;/h2&gt;

&lt;p&gt;Paste &lt;code&gt;{ "searchTerms": ["python"], "maxItems": 100 }&lt;/code&gt; or the four-board call above, and you have a deduplicated remote jobs feed without writing ten parsers.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>python</category>
      <category>remotework</category>
      <category>api</category>
    </item>
    <item>
      <title>How to build a multi job board scraper feed in one Python call</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Mon, 21 Sep 2026 03:35:53 +0000</pubDate>
      <link>https://dev.to/7_akariae/how-to-build-a-multi-job-board-scraper-feed-in-one-python-call-1375</link>
      <guid>https://dev.to/7_akariae/how-to-build-a-multi-job-board-scraper-feed-in-one-python-call-1375</guid>
      <description>&lt;p&gt;If you have ever tried to assemble a jobs dataset by hand, you know the shape of the problem. LinkedIn, Indeed and Glassdoor each have their own search page, their own paging and their own idea of what a "location" or a "salary" field looks like. Running three scrapers and reconciling them is glue work, and the same role posted on all three lands in your table three times. A multi job board scraper that does the merge for you is the obvious answer, as long as it is honest about what it can and cannot reach.&lt;/p&gt;

&lt;p&gt;This article walks through one such tool: the Apify actor &lt;code&gt;flash_scraper/multi-jobboard-scraper&lt;/code&gt;. Its README states the pitch plainly: "One search. Up to twelve job boards. One deduplicated row per role — so a job posted to LinkedIn, Indeed &lt;em&gt;and&lt;/em&gt; Glassdoor bills you once, not three times." Everything below comes from that README, the actor's dataset schema and one logged run. Where the README says a board is blocked or a column is blank, this article says so too.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get: the same 65 columns on every row
&lt;/h2&gt;

&lt;p&gt;Per the README, every row carries "the same 65 columns on every row of every run — a field a board did not publish is &lt;code&gt;null&lt;/code&gt;, never a missing column." Eight of them, with the titles and notes from the dataset schema:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Title in the Output tab&lt;/th&gt;
&lt;th&gt;What the schema says&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Title&lt;/td&gt;
&lt;td&gt;example: &lt;code&gt;Software Development Engineer, ML Systems, Annapurna Labs&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;company&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Company&lt;/td&gt;
&lt;td&gt;Filled from: all boards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Location&lt;/td&gt;
&lt;td&gt;Filled from: all boards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;salary_text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Salary&lt;/td&gt;
&lt;td&gt;example: &lt;code&gt;$158,100–$213,800 / year&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;salary_min_annual&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Salary min (yearly)&lt;/td&gt;
&lt;td&gt;example: &lt;code&gt;158100&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;found_on_sites&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Found on boards&lt;/td&gt;
&lt;td&gt;example: &lt;code&gt;glassdoor&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;duplicate_count&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Listings for this role&lt;/td&gt;
&lt;td&gt;example: &lt;code&gt;1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;td&gt;Filled from: Indeed + Glassdoor always; LinkedIn only with detail fetching&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;found_on_sites&lt;/code&gt; and &lt;code&gt;duplicate_count&lt;/code&gt; are the dedup evidence. Company names are normalized before matching, so &lt;em&gt;Wipro&lt;/em&gt; and &lt;em&gt;Wipro Limited&lt;/em&gt; collapse together, and the merge works across boards only: "five genuinely different openings one employer posted to one board stay five rows."&lt;/p&gt;

&lt;p&gt;Hourly, weekly and monthly pay is normalized into &lt;code&gt;salary_min_annual&lt;/code&gt; / &lt;code&gt;salary_max_annual&lt;/code&gt; (hourly ×2080, weekly ×52, monthly ×12), and &lt;code&gt;salary_text&lt;/code&gt; renders the raw salary columns as one readable string.&lt;/p&gt;

&lt;p&gt;Seven saved Output views ship with it (Overview, Salary, Cross-board, Remote &amp;amp; location, Company info, Standard table, All columns), exports are CSV, JSON or Excel, and every run writes a &lt;code&gt;RUN_SUMMARY&lt;/code&gt; record to its key-value store naming each board's outcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real run
&lt;/h2&gt;

&lt;p&gt;The log of a throwaway run from 2026-09-20, reproduced as written:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## multi-jobboard-scraper — throwaway run 2026-09-20 13:07 UTC, input: searchTerm 'software engineer', location 'New York, NY', boards linkedin+indeed+glassdoor+muse (other keys sent were not in the input schema and were ignored, so the run used the default cap of 20 per board)
Total: 59 jobs - indeed: 20, linkedin: 19, glassdoor: 20
9 of 59 delivered rows mention none of ['software engineer'] in their title or description: {'indeed': 3, 'glassdoor': 6}. LinkedIn in particular never answers 'nothing matched' - it returns loosely related postings. Set strictKeywordMatch=true to drop them before they are billed.
Pushed 59 items to Apify dataset
Done. 59 jobs delivered to the dataset.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read it honestly: three boards hit or nearly hit the default cap of 20, and The Muse, the fourth board in the input, returned no rows for this search and is absent from the per-board line. The log is shown as written, not tidied. The middle line is the actor's own off-topic warning, and the fix it names, &lt;code&gt;strictKeywordMatch&lt;/code&gt;, is "opt-in, off by default" and removes rows before billing, so a filtered row is never charged.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Python call
&lt;/h2&gt;

&lt;p&gt;The README's "Smallest useful call", copied verbatim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;APIFY_TOKEN&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flash_scraper/multi-jobboard-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;searchTerm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data analyst&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;New York, NY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a complete run. Per the README, everything else has a working default: LinkedIn + Indeed + Glassdoor + The Muse, 20 job postings per board, full LinkedIn job details on, Apify datacenter proxy. The same JSON works in the Console, the REST API and n8n/Make/Zapier.&lt;/p&gt;

&lt;p&gt;To make it a pipeline, tighten the input with the README's own example:&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;"searchTerm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data analyst"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sites"&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;"linkedin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"indeed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"glassdoor"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxResults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hoursOld"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;168&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"requireSalary"&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;"excludeTitleKeywords"&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;"senior"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"intern"&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;hoursOld&lt;/code&gt; is a board-side recency filter. &lt;code&gt;requireSalary&lt;/code&gt; and &lt;code&gt;excludeTitleKeywords&lt;/code&gt; run inside the actor after scraping and before billing, and &lt;code&gt;RUN_SUMMARY.filter_removed&lt;/code&gt; records how many rows each one took. &lt;code&gt;maxResults&lt;/code&gt; accepts 1–500 per board.&lt;/p&gt;

&lt;p&gt;For a recurring feed, the README's recipe is &lt;code&gt;onlyNewJobs&lt;/code&gt;: the actor "remembers every job this exact search has already delivered (in a private named store in your own account) and delivers — and bills — only postings it has not seen before. Identical reruns bill zero (measured: 15 rows, then 0)." Memory is kept per search for 90 days. Add a &lt;code&gt;webhookUrl&lt;/code&gt; and each run that delivers rows POSTs a digest to Slack, Discord or any JSON catch hook; quiet runs send nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;The README's pricing table, with its own caveat that the Store page's &lt;strong&gt;Pricing&lt;/strong&gt; tab is always authoritative:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Free plan&lt;/th&gt;
&lt;th&gt;Paid plans&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Deduplicated job delivered&lt;/td&gt;
&lt;td&gt;$0.005 ($5 per 1,000)&lt;/td&gt;
&lt;td&gt;$0.0045 on Bronze down to $0.0035 on Diamond (live pricing record read 2026-08-29)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run start&lt;/td&gt;
&lt;td&gt;$0.00005&lt;/td&gt;
&lt;td&gt;$0.00005&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two worked costs at the free-plan rate, from the same section: an untouched form (the four default boards, up to 20 rows each) delivers at most 80 deduplicated jobs for at most $0.40, and a 500-job sweep costs $2.50. A job found on three boards bills once, rows removed by a filter bill nothing, and a failed or empty run bills only the $0.00005 start. Apify's free plan needs no card on file, and its monthly usage credit covers several default-size searches.&lt;/p&gt;

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

&lt;p&gt;Copied from the README's own "What it does not do" section: it never logs in anywhere and never auto-applies; every row is public data. It cannot reach behind login walls. For LinkedIn it reads the pay span on the public search card when a posting carries one, plus posting text; the fuller base-pay block that LinkedIn's public job page shows on some postings (measured 2 of 6 on 2026-08-29) is not parsed yet. It is not a historical archive: each run reads the boards' current listings. And five selectable boards, Google Jobs, ZipRecruiter, Bayt, BDJobs and Naukri, are blocked at the source today.&lt;/p&gt;

&lt;p&gt;From the Board status table and the field notes: Glassdoor "403s some runs entirely" and "tops out around ~28-30 rows per query — a board-side cap, not a bug." The Muse carries no salary data: 0 salary fields in 220 measured rows. DevITjobs UK was "discontinued upstream (2026-08-29)", so eleven of the twelve working boards deliver rows today. The seven remote-only boards join remote searches automatically but are deliberately not added to location searches. Three columns, &lt;code&gt;experience_range&lt;/code&gt;, &lt;code&gt;vacancy_count&lt;/code&gt; and &lt;code&gt;company_reviews_count&lt;/code&gt;, are only ever published by Naukri, so expect them blank. And the keyless boards carry licensing terms: Remotive rows "must not be republished on another job board", and Remote OK requires a visible dofollow link back naming Remote OK.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to start
&lt;/h2&gt;

&lt;p&gt;If you want a job board scraper that is a single API call away and tells you per board what it actually returned, the actor page carries the live pricing, the Board status table and the full 65-column field list: &lt;a href="https://apify.com/flash_scraper/multi-jobboard-scraper" rel="noopener noreferrer"&gt;apify.com/flash_scraper/multi-jobboard-scraper&lt;/a&gt;. Run the Python call above once, open &lt;code&gt;RUN_SUMMARY&lt;/code&gt;, and decide from the counts whether the feed is worth scheduling.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>python</category>
      <category>jobs</category>
      <category>api</category>
    </item>
    <item>
      <title>12 job boards, one table, no API key</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Sat, 05 Sep 2026 21:06:37 +0000</pubDate>
      <link>https://dev.to/7_akariae/12-job-boards-one-table-no-api-key-3i1n</link>
      <guid>https://dev.to/7_akariae/12-job-boards-one-table-no-api-key-3i1n</guid>
      <description>&lt;h2&gt;
  
  
  The short answer
&lt;/h2&gt;

&lt;p&gt;You can query 12 job boards in one run without an API key by using a single Apify Actor that searches LinkedIn, Indeed, Glassdoor and The Muse by default and merges eight keyless boards on request. It returns one row per role, deduplicated across boards, with 54 identical columns every run. A measured run on 8 Aug 2026 turned 90 raw listings into 89 billed rows in 39 seconds.&lt;/p&gt;

&lt;p&gt;That is the whole article in one paragraph. The rest is the paste-ready input, the numbers behind it, and the parts that do not work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "one table" is the hard part
&lt;/h2&gt;

&lt;p&gt;Scraping one job board is a solved problem — there are dozens of single-board scrapers. The pain starts at board number two:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The same job appears on three boards.&lt;/strong&gt; A "Senior Data Analyst" at one company is on LinkedIn, on Indeed and on Glassdoor. Naively concatenating three scrapers' output gives you three rows, three CSV lines, three cold emails to the same recruiter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every board names its fields differently.&lt;/strong&gt; &lt;code&gt;postedDate&lt;/code&gt; vs &lt;code&gt;date_posted&lt;/code&gt; vs &lt;code&gt;created_at&lt;/code&gt;; salary as a string on one board, as min/max integers on another, absent on a third.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Company names do not match.&lt;/strong&gt; &lt;em&gt;Wipro&lt;/em&gt; on one board is &lt;em&gt;Wipro Limited&lt;/em&gt; on the next, so a naive &lt;code&gt;group by company&lt;/code&gt; never collapses them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Deduplication has to happen across boards, on normalised company names, before you are charged for the rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  The input, copy-paste
&lt;/h2&gt;

&lt;p&gt;This is a complete run. Every other field has a working default:&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;"searchTerm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data analyst"&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;"New York, NY"&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;Defaults you are getting for free: boards &lt;code&gt;["linkedin","indeed","glassdoor","muse"]&lt;/code&gt;, 20 results &lt;strong&gt;per board&lt;/strong&gt;, full LinkedIn job details on, Apify's datacenter proxy.&lt;/p&gt;

&lt;p&gt;Same thing from the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/flash_scraper~multi-jobboard-scraper/run-sync-get-dataset-items"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$APIFY_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"searchTerm":"data analyst","location":"New York, NY","maxResults":30}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pass the token as a &lt;strong&gt;header&lt;/strong&gt;, not a query parameter — query strings end up in server logs, proxy logs, stack traces and your own shell history. The Apify API accepts &lt;code&gt;Authorization: Bearer&lt;/code&gt; on every endpoint.&lt;/p&gt;

&lt;p&gt;The HTTP response body is the rows. No second call to fetch a dataset.&lt;/p&gt;

&lt;p&gt;From Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;   &lt;span class="c1"&gt;# never hardcode the token
&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flash_scraper/multi-jobboard-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;searchTerm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data analyst&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;New York, NY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxResults&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jobs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;found_on_sites&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;maxResults&lt;/code&gt; is &lt;strong&gt;per board&lt;/strong&gt;, not per run — the single most common surprise. Four boards at 30 is up to 120 raw listings before deduplication.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the deduplication is worth, measured
&lt;/h2&gt;

&lt;p&gt;From the Actor's own README, with the dates it publishes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run&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;
&lt;code&gt;data analyst&lt;/code&gt; / New York, NY, 30 per board, 3 boards — 8 Aug 2026&lt;/td&gt;
&lt;td&gt;90 raw listings -&amp;gt; &lt;strong&gt;89 billed rows in 39 s&lt;/strong&gt;, 1 duplicate merged across boards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Untouched form, then-default 3 boards at 20 each — 8 Aug 2026&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;60 rows in 27 s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same run, salary coverage&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;salary_min_annual&lt;/code&gt; filled on &lt;strong&gt;74 of 89 rows (83%)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two identical runs a day apart, before only-new mode existed&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;47% of rows were the same job&lt;/strong&gt; — a daily schedule was re-buying half its data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two columns show the merge instead of hiding it:&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;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Senior Data Analyst"&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;"Acme Corp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"site"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linkedin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"found_on_sites"&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;"linkedin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"indeed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"glassdoor"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"duplicate_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;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"salary_min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;158100.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;"salary_max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;213800.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;"salary_interval"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yearly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"date_posted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-06"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"job_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://..."&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;One row, one charge, and you can still see which three boards carried it. Salary fields are filled on 59-70% of rows on a default run and 56-60% with LinkedIn detail fetching off (README's own fill table, measured 2026-08-07 and re-checked across all 5,936 delivered rows on 2026-08-23) — Glassdoor publishes pay on 95-100% of its rows, Indeed on 50-80%, LinkedIn on about 35% and only with detail fetching.&lt;/p&gt;

&lt;h2&gt;
  
  
  The board list, including the ones that do not work
&lt;/h2&gt;

&lt;p&gt;Default: &lt;strong&gt;LinkedIn, Indeed, Glassdoor, The Muse.&lt;/strong&gt;&lt;br&gt;
Optional keyless boards: &lt;strong&gt;Remotive, Jobicy, Himalayas, Hacker News "Who is hiring?", Remote OK, We Work Remotely, Working Nomads, DevITjobs US&lt;/strong&gt; — the remote-only ones join automatically when you tick remote. DevITjobs &lt;strong&gt;UK&lt;/strong&gt; is still selectable but was discontinued upstream on 2026-08-29 (re-probed 2026-09-05: its public endpoint redirects to a signup page), so 11 of the 12 selectable working boards return rows today.&lt;/p&gt;

&lt;p&gt;Blocked at the source today and reported as blocked rather than silently returning nothing: &lt;strong&gt;Google Jobs, ZipRecruiter, Bayt, BDJobs, Naukri.&lt;/strong&gt; Glassdoor also tops out at roughly 28-30 rows per query no matter what cap you set — a board-side limit, not a bug in the scraper.&lt;/p&gt;

&lt;p&gt;This matters more than it looks: a scraper that returns 0 rows for a board and calls the run a success is indistinguishable from "there are no jobs". Check that whatever tool you use writes a per-board outcome somewhere. This one writes a &lt;code&gt;RUN_SUMMARY&lt;/code&gt; record naming each board's result.&lt;/p&gt;
&lt;h2&gt;
  
  
  Remote-only searches: use the leaner Actor
&lt;/h2&gt;

&lt;p&gt;If your query has no city in it, the big three boards mostly get in the way. There is a separate Actor for that shape — &lt;strong&gt;Remote Jobs Aggregator&lt;/strong&gt; — which sweeps 10 keyless remote boards (RemoteOK, We Work Remotely, Working Nomads, DevITjobs US and UK, The Muse, Remotive, Jobicy, Himalayas, HN "Who is hiring?") with no key, no proxy and no login — DevITjobs UK has been dead upstream since 2026-08-29, so nine deliver rows today, and the run says so:&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;"searchTerms"&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;"python"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&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;Measured default run on &lt;strong&gt;15 Aug 2026&lt;/strong&gt;: 100 deduplicated jobs from 9 boards, 6 cross-board duplicates merged, &lt;strong&gt;35% of rows carrying a salary, 88% a description snippet, 100% a posting date&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One switch is worth knowing before you run it. &lt;code&gt;matchDescriptions&lt;/code&gt; also matches your keyword inside the first 500 characters of the posting, not just the title. Measured on 15 Aug 2026 with &lt;code&gt;["python"]&lt;/code&gt;: &lt;strong&gt;194 rows wide vs 28 title-only&lt;/strong&gt; — roughly 7x the recall, and a marketing role whose blurb mentions "our Python stack" now matches too. Wide by default in the form, title-only over the API.&lt;/p&gt;

&lt;p&gt;Every row carries &lt;code&gt;job_id&lt;/code&gt;, a 16-hex fingerprint of the canonical URL — that is your upsert key for Sheets, Airtable or a CRM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn it into a daily alert (the part people actually keep)
&lt;/h2&gt;

&lt;p&gt;Both Actors have an only-new mode that remembers what a given search has already delivered, in a private store in your own account, for 90 days:&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;"searchTerm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data analyst"&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;"New York, NY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"onlyNewJobs"&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;"webhookUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://hooks.slack.com/services/T000/B000/XXXX"&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;First run seeds the memory. Every run after that delivers — and bills — only postings it has not seen. A measured pair: 15 rows on the first run, &lt;strong&gt;0 on an identical rerun&lt;/strong&gt;. Schedule it from the run page (Actions -&amp;gt; Schedule), point &lt;code&gt;webhookUrl&lt;/code&gt; at Slack, Discord, or an n8n/Make/Zapier catch hook, and you have a job alert feed you own.&lt;/p&gt;

&lt;p&gt;Remember the 47% number above: without only-new mode, a daily schedule pays twice for half its rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;Pay-per-result, &lt;strong&gt;$0.005 per delivered row&lt;/strong&gt; for the multi-board Actor and &lt;strong&gt;$0.002&lt;/strong&gt; for the remote one (free-plan rates, read from the Store on 5 Sep 2026 — the Pricing tab on each Actor page is always authoritative). &lt;strong&gt;The remote Actor has a pricing record scheduled for 14 Sep 2026 that raises it to $0.003 per row&lt;/strong&gt;, so if you are reading this after that date, take the figure off the Pricing tab, not off this paragraph. Deduplicated and filtered rows are never billed, and a run that delivers nothing bills only a $0.00005 run start.&lt;/p&gt;

&lt;p&gt;Practical maths: a 4-board search at 20 per board is at most 80 rows = &lt;strong&gt;$0.40&lt;/strong&gt;. Apify's free plan needs no card and its monthly credit covers several runs of that size.&lt;/p&gt;

&lt;h2&gt;
  
  
  What neither Actor does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No login, anywhere.&lt;/strong&gt; Only public data. Nothing behind a login wall, no auto-apply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No historical archive.&lt;/strong&gt; Each run reads what the boards are showing today.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No guessed salary.&lt;/strong&gt; A salary column is empty when the board published no figure — it is never inferred.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Five boards are blocked&lt;/strong&gt; (listed above), and the run says so instead of pretending.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I scrape LinkedIn and Indeed jobs without an API key?
&lt;/h3&gt;

&lt;p&gt;Yes. Neither board offers a public jobs API to most developers, but both publish their search results as public pages, and the Actor above reads them without logging in — you only need an Apify API token to call the platform, not a key from LinkedIn or Indeed.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I remove duplicate jobs across job boards?
&lt;/h3&gt;

&lt;p&gt;Match on the canonical job URL first, then on (normalised company name, title, location). Normalising the company is the step most home-made pipelines skip, which is why &lt;em&gt;Wipro&lt;/em&gt; and &lt;em&gt;Wipro Limited&lt;/em&gt; stay two rows. The Actor above does both and exposes the result in &lt;code&gt;found_on_sites&lt;/code&gt; and &lt;code&gt;duplicate_count&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many rows can one run deliver?
&lt;/h3&gt;

&lt;p&gt;A measured stress run on 7 Aug 2026 returned 258 rows from 3 boards at 120 per board in 226 seconds (that run predates a 29 Aug 2026 LinkedIn paging fix, so its 118 LinkedIn rows were not the newest 118; it has not been re-measured since). Per-board inventory, not the cap, is usually the binding limit — Glassdoor stops near 30 per query.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a free way to try it?
&lt;/h3&gt;

&lt;p&gt;Apify's free plan needs no card and carries a monthly usage credit; a default 4-board run costs about $0.40 of it. Both Actors also publish example tasks you can open and run as-is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which is the right one for remote work?
&lt;/h3&gt;

&lt;p&gt;If your query has a city, use the multi-board Actor and tick remote — it applies each big board's own remote filter and enforces LinkedIn's client-side (LinkedIn's public search accepts a remote flag and ignores it, so the Actor filters those rows itself before billing). If your query has no city at all, the remote aggregator is cheaper and quieter.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I build and maintain both Actors (&lt;a href="https://apify.com/flash_scraper/multi-jobboard-scraper" rel="noopener noreferrer"&gt;Multi Job Board Scraper&lt;/a&gt;, &lt;a href="https://apify.com/flash_scraper/remote-job-aggregator" rel="noopener noreferrer"&gt;Remote Jobs Aggregator&lt;/a&gt;, publisher &lt;code&gt;flash_scraper&lt;/code&gt; on Apify). Every figure in this post is published in the Actors' own READMEs with the date it was measured; Store user and run counts were read from the public Apify Store API on 5 Sep 2026. If you reproduce a run and get different numbers, tell me in the comments and I will update the post.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>python</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Local business emails without scraping Google Maps</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Sat, 05 Sep 2026 21:00:43 +0000</pubDate>
      <link>https://dev.to/7_akariae/local-business-emails-without-scraping-google-maps-5fa</link>
      <guid>https://dev.to/7_akariae/local-business-emails-without-scraping-google-maps-5fa</guid>
      <description>&lt;h2&gt;
  
  
  The short answer
&lt;/h2&gt;

&lt;p&gt;You do not need Google Maps to build a local B2B list. OpenStreetMap gives you the businesses in any city for free, each business's own website gives you the email and phone, and a DNS MX lookup tells you whether the address can receive mail. Measured on 8 Aug 2026: 55 dentists in Austin, 96% with a phone, 55% with an MX-verified email.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not Google Maps
&lt;/h2&gt;

&lt;p&gt;Google Maps is the default answer, and for star ratings and review counts it is still the only answer. But it costs you three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A proxy bill.&lt;/strong&gt; Maps is aggressive about datacenter IPs, so most Maps scrapers need residential proxies, which is usually more expensive than the data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terms-of-service exposure.&lt;/strong&gt; Whatever your view of scraping public pages, using Google's own listing data is a policy question you have to answer to your client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A separate verification step.&lt;/strong&gt; A Maps listing carries a phone and a website. It does not carry an email, so you end up bolting a crawler and then a verification API onto the pipeline, each with its own bill.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The alternative pipeline is three keyless steps: &lt;strong&gt;OpenStreetMap -&amp;gt; the business's own site -&amp;gt; MX check.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: discovery on OpenStreetMap
&lt;/h2&gt;

&lt;p&gt;OpenStreetMap tags businesses by type (&lt;code&gt;amenity=dentist&lt;/code&gt;, &lt;code&gt;shop=hairdresser&lt;/code&gt;, &lt;code&gt;office=lawyer&lt;/code&gt;, …). Overpass, the query API, is public and keyless. This is the part that surprises people who have only used Maps: for premises-based businesses the coverage is genuinely good.&lt;/p&gt;

&lt;p&gt;It is also the part that fails honestly, and you should know the shape of the failure before you sell a list to anyone. Measured in the Austin bounding box on &lt;strong&gt;8 Aug 2026&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Records in OpenStreetMap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;dentist&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;171&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;plumber&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;electrician&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Premises get mapped; vans do not. If your niche is trades that drive to the customer, OpenStreetMap alone will not fill a list, and no amount of retrying changes that. Dentists, gyms, salons, law firms, restaurants, clinics, hotels, real-estate offices: dense. Plumbers, roofers, mobile locksmiths: thin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: crawl the business's own site
&lt;/h2&gt;

&lt;p&gt;The email is almost never in the map data. It is on the business's contact page. So the crawl is: fetch the homepage, follow the obvious contact/about links, pull &lt;code&gt;mailto:&lt;/code&gt; addresses, &lt;code&gt;tel:&lt;/code&gt; numbers, social profile links, and the &lt;code&gt;meta generator&lt;/code&gt; tag that tells you the site is WordPress or Wix or Squarespace.&lt;/p&gt;

&lt;p&gt;Two things worth building in from the start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Whose mailbox is it?&lt;/strong&gt; An address on the business's own domain is worth more than a &lt;code&gt;@gmail.com&lt;/code&gt;, and both are worth more than the address of the &lt;strong&gt;marketing agency that built the site&lt;/strong&gt; — that one is deliverable and still never reaches the business. On the reference run, 12% of all harvested addresses were third-party (agency) addresses, but only 10% of the ones promoted to primary, because candidates get ranked by mailbox ownership before one is picked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A blocked site is not a missing business.&lt;/strong&gt; Some sites refuse datacenter IPs: 8 of the 55 website-bearing rows in the reference run. Record that as &lt;code&gt;site_blocked&lt;/code&gt; rather than shipping an empty row that looks like "this business has no email".&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: MX verification, which is a DNS lookup
&lt;/h2&gt;

&lt;p&gt;You do not need a paid verification API to catch the majority of dead addresses. Resolve the domain's MX records (over DNS-over-HTTPS if you are running in a sandbox), and grade the address &lt;code&gt;deliverable&lt;/code&gt; / &lt;code&gt;risky&lt;/code&gt; / &lt;code&gt;undeliverable&lt;/code&gt;. It will not catch a valid domain with a dead mailbox — nothing short of SMTP probing will, and that has its own problems — but it removes typo domains, parked domains and expired domains before you pay for the row.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never promote a guessed address.&lt;/strong&gt; &lt;code&gt;info@&amp;lt;domain&amp;gt;&lt;/code&gt; is a guess. If you produce one, put it in its own column and never let it satisfy a "has email" filter. On the reference run, the full-enrichment preset produced 100 rows plus 23 guessed addresses — kept in &lt;code&gt;email_guess&lt;/code&gt;, never billed as verified.&lt;/p&gt;

&lt;h2&gt;
  
  
  The whole pipeline as one input
&lt;/h2&gt;

&lt;p&gt;I package the three steps as an Apify Actor, so this is the paste-and-run version:&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;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dentist"&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, Texas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"onlyWithWebsite"&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="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;25 delivered rows at the free-plan rate of $0.003 each = &lt;strong&gt;$0.075&lt;/strong&gt; (a pricing record scheduled for 14 Sep 2026 raises that to $0.005 a row, so $0.125; the Pricing tab on the Actor page is authoritative). No API key, no proxy, no login; discovery, crawl, MX verification and a 0-100 lead score all happen inside that one run.&lt;/p&gt;

&lt;p&gt;From the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/flash_scraper~local-business-leads/run-sync-get-dataset-items"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$APIFY_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"category":"dentist","location":"Austin, Texas","maxItems":25,"onlyWithWebsite":true}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pass the token as a &lt;strong&gt;header&lt;/strong&gt;, not a query parameter — query strings end up in server logs, proxy logs, stack traces and your own shell history. The Apify API accepts &lt;code&gt;Authorization: Bearer&lt;/code&gt; on every endpoint.&lt;/p&gt;

&lt;p&gt;From Python, keeping only the columns a CRM import wants:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;   &lt;span class="c1"&gt;# never hardcode the token
&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flash_scraper/local-business-leads&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dentist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Austin, Texas&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;onlyWithWebsite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;onlyVerifiedEmail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outputFields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;phone&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;website&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lead_grade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;leads;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deliverable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deliverable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Already have a list of company websites and only need the contacts? Skip discovery entirely by passing &lt;code&gt;websiteList&lt;/code&gt; — those rows come back marked &lt;code&gt;source: "user_supplied"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A row looks 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;"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;"Example Family Dental"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dentist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123 Example St, Austin, TX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+1 512 555 0100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"website"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example-dental.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hello@example-dental.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_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;"deliverable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_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;"own_domain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"website_platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WordPress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lead_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lead_grade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"osm_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.openstreetmap.org/node/..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"attribution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"© OpenStreetMap contributors (ODbL)"&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;h2&gt;
  
  
  The measured fill rates, including the ones I would rather not publish
&lt;/h2&gt;

&lt;p&gt;All from &lt;code&gt;dentist&lt;/code&gt; / &lt;code&gt;Austin, Texas&lt;/code&gt;, &lt;strong&gt;8 Aug 2026&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run&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;Website required, cap 100&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;55 businesses, 100% contactable&lt;/strong&gt; — 96% phone, 55% MX-verified email, 71% detected platform. Under the cap because OpenStreetMap holds 171 dentists in Austin and 55 of them are crawlable with a website&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bare &lt;code&gt;{}&lt;/code&gt;, no filters at all&lt;/td&gt;
&lt;td&gt;100 businesses, &lt;strong&gt;50% contactable&lt;/strong&gt; — 48% phone, &lt;strong&gt;26% email&lt;/strong&gt;, 34% platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold-email preset&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;31 rows, 100% with an MX-verified email&lt;/strong&gt;, 94% with a phone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Call-list preset, cap 100&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;56 rows, 100% with a phone&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web-design-prospect preset, cap 100&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;7 rows&lt;/strong&gt; — 68 Austin businesses met the low-score ceiling, but only 7 of them publish any contact channel at all&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The gap between line 1 and line 2 is the honest story of this kind of pipeline: filter for "has a website" and you get a contactable list; ask for everything mapped and roughly half the rows have nothing to contact. Both numbers are published, because a vendor who shows you only the first one is showing you a filter, not a capability.&lt;/p&gt;

&lt;p&gt;One more sparse column worth naming: &lt;code&gt;rating&lt;/code&gt; fills on about &lt;strong&gt;7% of rows&lt;/strong&gt; (4 of 55), and only where the business publishes a rating in its own site markup. It is never a Google rating. If you need Google's review data, scrape Google — this pipeline deliberately does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making it a weekly new-business alert
&lt;/h2&gt;

&lt;p&gt;Discovery is idempotent enough to schedule. Turn on only-new mode and the run remembers what this exact search already delivered (90-day memory, stored in your own account), so a weekly schedule delivers and bills only businesses that were not there last week:&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;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dentist"&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, Texas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"onlyNewBusinesses"&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;"webhookUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://hooks.slack.com/services/T000/B000/XXXX"&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;Set expectations honestly: new businesses appear at the speed of OpenStreetMap, which is the speed of volunteer mappers. Weekly or monthly is the right cadence; hourly will mostly report "nothing new" (and bill nothing for it).&lt;/p&gt;

&lt;h2&gt;
  
  
  Two legal points, not legal advice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenStreetMap data is ODbL.&lt;/strong&gt; Attribution has to travel with the data — that is why every discovered row carries an &lt;code&gt;attribution&lt;/code&gt; string, and why you should keep the column in your export rather than stripping it on import.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold email has rules that differ by country.&lt;/strong&gt; In the US, CAN-SPAM makes commercial email opt-out rather than opt-in, but each message still needs a real physical postal address and a working unsubscribe. In the EU and UK, check the ePrivacy/GDPR position for B2B before you send. Verifying that an address exists is not the same as being allowed to mail it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I get local business emails without scraping Google Maps?
&lt;/h3&gt;

&lt;p&gt;Yes. Use OpenStreetMap (public, keyless) for discovery, then crawl each business's own website for the address. You give up Google star ratings and review counts, and you gain emails, mailbox ownership, website platform and no proxy bill.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does 1,000 local business leads cost this way?
&lt;/h3&gt;

&lt;p&gt;$3 at the Actor's free-plan rate of $0.003 per delivered row (read from the Apify Store on 5 Sep 2026), MX verification included — &lt;strong&gt;$5 from 14 Sep 2026&lt;/strong&gt;, when a scheduled pricing record takes the rate to $0.005 per row. Read the Pricing tab rather than this sentence. Filtered rows are dropped before billing, so a run that finds nothing charges nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did my category return so few rows?
&lt;/h3&gt;

&lt;p&gt;Almost always OpenStreetMap density, not a scraping failure. Premises-based businesses are mapped; van-based trades are not. Compare 171 dentists with 9 plumbers in the same Austin bounding box (8 Aug 2026). A run that cannot reach your cap should tell you which of the two happened — a truncation or the whole city.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is an MX check the same as email verification?
&lt;/h3&gt;

&lt;p&gt;No. An MX check proves the domain can receive mail. It does not prove the specific mailbox exists. It removes typo, parked and expired domains cheaply, which is most of the dead addresses in a scraped list, and it is honest about the rest by grading them &lt;code&gt;risky&lt;/code&gt; rather than &lt;code&gt;deliverable&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I run this from an AI agent?
&lt;/h3&gt;

&lt;p&gt;Yes, through the Apify MCP server. A minimal input measured locally on 29 Aug 2026 returned 10 rows in 17 seconds for about $0.03: &lt;code&gt;{ "category": "dentist", "location": "Austin, Texas", "maxItems": 10, "crawlEmails": false }&lt;/code&gt; (that particular input skips the email crawl, so use it for a smoke test, not for a list).&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I build and maintain the Actor used in the examples (&lt;a href="https://apify.com/flash_scraper/local-business-leads" rel="noopener noreferrer"&gt;Local Business Leads Scraper&lt;/a&gt;, publisher &lt;code&gt;flash_scraper&lt;/code&gt; on Apify). Every fill rate quoted here is published in its README with the date it was measured; the price was read from the public Apify Store API on 5 Sep 2026. The three-step pipeline itself is not proprietary — Overpass, a contact crawler and a DNS MX lookup will get you there yourself, and this post is meant to be enough to build it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>python</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creator and Influencer Email Scrapers on Apify Compared (September 2026)</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Sat, 05 Sep 2026 18:35:29 +0000</pubDate>
      <link>https://dev.to/7_akariae/creator-and-influencer-email-scrapers-on-apify-compared-september-2026-1ekf</link>
      <guid>https://dev.to/7_akariae/creator-and-influencer-email-scrapers-on-apify-compared-september-2026-1ekf</guid>
      <description>&lt;p&gt;&lt;strong&gt;Almost every creator email scraper on Apify does one platform. dataovercoffee/Youtube-Channel-Business-Email-Scraper is the most used (3,644 users) and reads the login-gated email button, at $120 per 1,000. flash_scraper/creator-leads-scraper is the only Actor in this comparison covering TikTok, Instagram and YouTube in one 51-column schema, at $2 per 1,000.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every figure below was read from Apify's public Store API on &lt;strong&gt;2026-09-05&lt;/strong&gt;. Prices here vary by a factor of sixty, so read the Pricing tab before you run anything.&lt;/p&gt;

&lt;p&gt;Disclosure: I publish &lt;code&gt;flash_scraper/creator-leads-scraper&lt;/code&gt;, one of the actors compared here. Its two biggest limitations are stated below, and one of them is a hard no for influencer discovery on TikTok and Instagram.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the prices differ by 60x
&lt;/h2&gt;

&lt;p&gt;Two different products are sold under the same words. One reads what a creator published in public (About text, bio, linked website) and charges cents. The other uses logged-in accounts and CAPTCHA solving to reveal the address behind YouTube's "View email address" button, which is gated by a Google login and a daily reveal quota, and charges dollars. The second returns more emails and carries account and terms-of-service exposure the first does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;Users&lt;/th&gt;
&lt;th&gt;Rating (reviews)&lt;/th&gt;
&lt;th&gt;Price per 1,000&lt;/th&gt;
&lt;th&gt;Platforms and coverage&lt;/th&gt;
&lt;th&gt;What to watch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/dataovercoffee/Youtube-Channel-Business-Email-Scraper" rel="noopener noreferrer"&gt;dataovercoffee/Youtube-Channel-Business-Email-Scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;3,644&lt;/td&gt;
&lt;td&gt;4.40 (30)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$120.00&lt;/strong&gt; per 1,000 emails&lt;/td&gt;
&lt;td&gt;YouTube, using logged-in accounts and CAPTCHA solving to reach the gated address&lt;/td&gt;
&lt;td&gt;Plus a &lt;strong&gt;$280 per 1,000&lt;/strong&gt; force-fresh-scrape surcharge; highest price here, and the only one whose listing claims it reaches the login-gated address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/exporter24/youtube-email-bulk-scraper" rel="noopener noreferrer"&gt;exporter24/youtube-email-bulk-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;964&lt;/td&gt;
&lt;td&gt;5.0 (3)&lt;/td&gt;
&lt;td&gt;$30.00 per 1,000 results&lt;/td&gt;
&lt;td&gt;YouTube channel emails from public data&lt;/td&gt;
&lt;td&gt;Listing names no keyword discovery, so bring your own channel list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/lurkapi/youtube-channel-email-scraper" rel="noopener noreferrer"&gt;lurkapi/youtube-channel-email-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;644&lt;/td&gt;
&lt;td&gt;5.0 (3)&lt;/td&gt;
&lt;td&gt;$5.00 per 1,000 emails found&lt;/td&gt;
&lt;td&gt;YouTube About pages: business emails, contact info, social links; accepts @handles, URLs or IDs&lt;/td&gt;
&lt;td&gt;Keyword discovery is billed at &lt;strong&gt;$0.05 per search query&lt;/strong&gt; and validation at $1 per 1,000; a discovery-heavy run costs far more than the headline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/automation-lab/youtube-channel-email-scraper" rel="noopener noreferrer"&gt;automation-lab/youtube-channel-email-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;203&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$2.30 per 1,000 channels&lt;/td&gt;
&lt;td&gt;YouTube About pages: emails, subscriber counts, video counts, all linked socials, no proxy needed&lt;/td&gt;
&lt;td&gt;Emails found are billed again at &lt;strong&gt;$23 per 1,000&lt;/strong&gt;, plus a $0.005 run start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/haketa/youtube-contact-scraper" rel="noopener noreferrer"&gt;haketa/youtube-contact-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;92&lt;/td&gt;
&lt;td&gt;5.0 (1)&lt;/td&gt;
&lt;td&gt;$3.00 per 1,000 results&lt;/td&gt;
&lt;td&gt;YouTube keyword search or channel URLs: name, subscribers, views, country, business email, website, all socials&lt;/td&gt;
&lt;td&gt;Cheapest keyword-driven YouTube option here; one review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/afanasenko/instagram-influencer-search" rel="noopener noreferrer"&gt;afanasenko/instagram-influencer-search&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$10.00 per 1,000 profiles&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Instagram&lt;/strong&gt; hashtag and keyword discovery with follower range, minimum engagement rate, emails, phone, bio links, business category, Reels views&lt;/td&gt;
&lt;td&gt;The only real Instagram &lt;em&gt;discovery&lt;/em&gt; option in this comparison&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/funny_ground/tiktok-influencer-finder" rel="noopener noreferrer"&gt;funny_ground/tiktok-influencer-finder&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$5.00 per 1,000 results&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;TikTok&lt;/strong&gt; niche search with country, language and follower filters, exporting only profiles with a public contact&lt;/td&gt;
&lt;td&gt;Only TikTok keyword-search actor here; six users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/flash_scraper/creator-leads-scraper" rel="noopener noreferrer"&gt;flash_scraper/creator-leads-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;5.0 (2)&lt;/td&gt;
&lt;td&gt;$2.00 per 1,000 leads&lt;/td&gt;
&lt;td&gt;TikTok, Instagram and YouTube in &lt;strong&gt;one run, 51 identical columns&lt;/strong&gt;, MX-verified email, 0-100 lead score, only-new monitoring&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No TikTok or Instagram keyword search&lt;/strong&gt; (handles only). Optional AI cold opener is a second $2 per 1,000 event&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When to pick which
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pick dataovercoffee if reveal rate is the only thing that matters and the budget is real.&lt;/strong&gt; It is the most used and most reviewed of the creator email actors a Store search surfaced on 2026-09-05, 30,093 of 30,390 runs succeeded in the 30 days to 2026-09-05, and its listing is the only one here that claims the address keyless scrapers cannot reach. At $0.12 per email, 1,000 addresses is $120, and the force-fresh surcharge can take a run to $400 per 1,000.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick haketa/youtube-contact-scraper for cheap YouTube discovery.&lt;/strong&gt; Keyword search plus contact details at $3 per 1,000 is the best value in the YouTube-only column, and 3,908 of 3,934 runs succeeded in the 30 days to 2026-09-05.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick lurkapi if you already have the channel list.&lt;/strong&gt; Paying only for emails actually found ($0.005 each) is the fairest structure here for enrichment work. The $0.05 per search query makes it expensive for discovery, so use it as an enricher, not a finder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick afanasenko/instagram-influencer-search for Instagram discovery.&lt;/strong&gt; Nothing else in this comparison does it, and engagement rate plus follower range is exactly what influencer-marketing buyers filter on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick funny_ground/tiktok-influencer-finder to find TikTok creators by niche&lt;/strong&gt; rather than enrich handles you already have. Six users means unproven, so test small.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick flash_scraper/creator-leads-scraper when you already have handles across more than one platform and want one spreadsheet rather than three.&lt;/strong&gt; Every row has the same 51 columns whichever platform it came from, every email is MX-verified with a status, and filters run before billing. &lt;code&gt;onlyNewCreators&lt;/code&gt; on a schedule delivers only creators that appeared since the last run. At $0.002 per lead it is the cheapest per row here — 1.15x under the next cheapest headline rate ($2.30 per 1,000, automation-lab, which then bills emails found again at $23 per 1,000 on top) and 60x under the most used ($120).&lt;/p&gt;

&lt;h2&gt;
  
  
  What ours does not do, stated plainly
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;There is no TikTok or Instagram keyword or hashtag search.&lt;/strong&gt; For those two platforms you supply usernames and the actor enriches them. YouTube is the only discovery platform: a keyword search returns roughly 30 channels, and their published links then give you TikTok and Instagram handles to feed back in. If your job is "find me TikTok beauty creators in Spain with 50k followers", this actor cannot start that job, and funny_ground or afanasenko can.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It does not read the email behind YouTube's "View email address" button.&lt;/strong&gt; That button needs a Google login, a reCAPTCHA and a daily reveal quota. This actor stays keyless and logged out, so YouTube emails come from About text, published channel links and the linked website instead. That is the whole reason it costs $2 per 1,000 and dataovercoffee costs $120.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email fill is a fraction, measured on small samples.&lt;/strong&gt; In the 2026-08-09 verification runs, all after website enrichment: 6 of 9 YouTube channels on one keyword and 4 of 8 on a second, 3 of 9 TikTok creators, 1 of 5 Instagram creators. Read those as an order of magnitude, not a guarantee. Most addresses come from the creator's linked website, not the bio: a standalone measurement found an email in the TikTok bio itself on 1 of 28 profiles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instagram delivers partially at volume.&lt;/strong&gt; Measured off-platform on 2026-09-03, Instagram's JSON endpoint refused every residential exit for 12 of 12 handles while the public profile page served 16 of 16 on the same exits, so the actor falls back to the page. A handle refused on both paths is reported by name and never billed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No phone numbers, and no engagement rate outside Instagram.&lt;/strong&gt; And 16 users with 2 reviews is a small footprint next to 3,644.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real run costs
&lt;/h2&gt;

&lt;p&gt;At $0.002 per creator lead, 1,000 leads is $2.00 and a 30-lead test is $0.06. &lt;code&gt;maxCreators&lt;/code&gt; counts creators delivered, not scraped: filters run before the count, and with an email filter set the run keeps discovering in up to three extra waves. Filtered-out, blocked and nonexistent handles are never billed. The AI cold opener is opt-in at a second $0.002 per row.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short answers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I find a TikTok or Instagram creator's email by username?&lt;/strong&gt; Yes, on flash_scraper/creator-leads-scraper, lurkapi (YouTube), automation-lab (YouTube) and the enrichment mode of the TikTok actors. It works only when the creator published an address somewhere public, usually on their linked website rather than in the bio. In the 2026-08-09 measurements that was 3 of 9 TikTok creators and 1 of 5 Instagram creators.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What percentage of creators actually have a public email?&lt;/strong&gt; Between roughly a fifth and two thirds, depending on platform and keyword, on the measurements above. Any actor promising a full sheet of verified influencer emails from a keyless, logged-out scrape is describing something the public data does not contain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which actor covers all three platforms in one run?&lt;/strong&gt; As read on 2026-09-05, flash_scraper/creator-leads-scraper is the only one in this comparison whose listing names TikTok, Instagram and YouTube with one output schema. The trade for that breadth is the missing TikTok and Instagram keyword search.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Data source: Apify public Store API, read 2026-09-05. Author: Flash Scrape (&lt;code&gt;flash_scraper&lt;/code&gt; on Apify), publisher of one of the actors listed. Corrections welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>api</category>
      <category>python</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Remote Job Aggregators on Apify Compared (September 2026)</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Sat, 05 Sep 2026 18:29:58 +0000</pubDate>
      <link>https://dev.to/7_akariae/remote-job-aggregators-on-apify-compared-september-2026-3cjd</link>
      <guid>https://dev.to/7_akariae/remote-job-aggregators-on-apify-compared-september-2026-3cjd</guid>
      <description>&lt;p&gt;&lt;strong&gt;Eight Actors compared here aggregate remote job boards into one feed. flash_scraper/remote-job-aggregator sweeps the most boards (10 keyless boards plus one opt-in) at $2 per 1,000 deduplicated jobs. nivlekk/remote-jobs-aggregator is the cheapest per row at $0.50 per 1,000, and memo23 is the cheapest that merges six boards at $1.99 and adds employer emails. benthepythondev has the largest user base at 738.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every figure below was read from Apify's public Store API on &lt;strong&gt;2026-09-05&lt;/strong&gt;. This category churns fast, so the Pricing tab on each actor page is authoritative, not this article.&lt;/p&gt;

&lt;p&gt;Disclosure: I publish &lt;code&gt;flash_scraper/remote-job-aggregator&lt;/code&gt;, one of the actors compared here. It has zero reviews, and that is stated in the table rather than hidden.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why board count is the metric that matters here
&lt;/h2&gt;

&lt;p&gt;All of these actors read the same public, keyless feeds: RemoteOK, Remotive, We Work Remotely, Himalayas, Jobicy, Working Nomads, Arbeitnow, the Hacker News "Who is hiring?" thread, and a few smaller boards. Board health is a shared risk rather than an actor-specific one: Jobspresso itself answered HTTP 403 to our own direct board probe on 2026-08-27, and DevITjobs UK went dead upstream on 2026-08-29 (re-probed 2026-09-05: &lt;code&gt;devitjobs.uk/api/jobsLight&lt;/code&gt; 302s to a signup page) — either would affect any actor reading them, ours included. None of them can reach LinkedIn, Indeed or Glassdoor remote listings, because those are a different scraping problem entirely. So the honest differentiators are: how many of those feeds an actor merges, whether it deduplicates a role that appears on three of them, whether it can run as a scheduled alert that only delivers new postings, and price per unique row.&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;Users&lt;/th&gt;
&lt;th&gt;Rating (reviews)&lt;/th&gt;
&lt;th&gt;Price per 1,000&lt;/th&gt;
&lt;th&gt;Boards covered&lt;/th&gt;
&lt;th&gt;What to watch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/benthepythondev/remote-jobs-aggregator" rel="noopener noreferrer"&gt;benthepythondev/remote-jobs-aggregator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;738&lt;/td&gt;
&lt;td&gt;5.0 (1)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$15.00&lt;/strong&gt; per 1,000 results&lt;/td&gt;
&lt;td&gt;Arbeitnow, Jobicy, Himalayas, RemoteOK, Remotive, Working Nomads (6)&lt;/td&gt;
&lt;td&gt;Salary extraction is a &lt;strong&gt;separate $10 per 1,000 event&lt;/strong&gt;; most-used but by far the most expensive per row&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/inlifeprojects/himalayas-jobs-scraper" rel="noopener noreferrer"&gt;inlifeprojects/himalayas-jobs-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;608&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$1.00 per 1,000 results&lt;/td&gt;
&lt;td&gt;Himalayas only (1)&lt;/td&gt;
&lt;td&gt;Single board, nothing to deduplicate; filters by seniority and country&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/sync-network/multi-site-remote-job-finder" rel="noopener noreferrer"&gt;sync-network/multi-site-remote-job-finder&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;282&lt;/td&gt;
&lt;td&gt;3.0 (1)&lt;/td&gt;
&lt;td&gt;$3.00 per 1,000 results&lt;/td&gt;
&lt;td&gt;RemoteOK, Remotive, We Work Remotely, Jobspresso (4)&lt;/td&gt;
&lt;td&gt;Four boards; the listing does not name cross-board deduplication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/memo23/remote-jobs-aggregator" rel="noopener noreferrer"&gt;memo23/remote-jobs-aggregator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;87&lt;/td&gt;
&lt;td&gt;5.0 (2)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$1.99&lt;/strong&gt; per 1,000 results&lt;/td&gt;
&lt;td&gt;RemoteOK (full depth), We Work Remotely, Remotive, Himalayas, Jobicy, Arbeitnow (6)&lt;/td&gt;
&lt;td&gt;Adds opt-in employer contact emails and geo eligibility; claims 2,000 to 3,000 unique jobs per run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/get_anything/remote-jobs-aggregator" rel="noopener noreferrer"&gt;get_anything/remote-jobs-aggregator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;5.0 (2)&lt;/td&gt;
&lt;td&gt;$2.00 per 1,000 job records&lt;/td&gt;
&lt;td&gt;Remotive, RemoteOK, Arbeitnow, Himalayas, Jobicy, We Work Remotely (6)&lt;/td&gt;
&lt;td&gt;Deduplicated and normalised from official public feeds; no run-start fee&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/nivlekk/remote-jobs-aggregator" rel="noopener noreferrer"&gt;nivlekk/remote-jobs-aggregator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$0.50&lt;/strong&gt; per 1,000 results&lt;/td&gt;
&lt;td&gt;RemoteOK, We Work Remotely, Remotive named in the title; 7 selectable in its input schema (&lt;code&gt;remoteok&lt;/code&gt;, &lt;code&gt;weworkremotely&lt;/code&gt;, &lt;code&gt;remotive&lt;/code&gt;, &lt;code&gt;arbeitnow&lt;/code&gt;, &lt;code&gt;jobicy&lt;/code&gt;, &lt;code&gt;himalayas&lt;/code&gt;, &lt;code&gt;workingnomads&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Cheapest per row anywhere in this category, plus a $0.001 run start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/delightful_unicorn/remote-jobs-aggregator" rel="noopener noreferrer"&gt;delightful_unicorn/remote-jobs-aggregator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$1.00 per 1,000 results&lt;/td&gt;
&lt;td&gt;RemoteOK, We Work Remotely, Working Nomads (3)&lt;/td&gt;
&lt;td&gt;Positioned as a unified API, no proxy; deduplication is not named in the listing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/flash_scraper/remote-job-aggregator" rel="noopener noreferrer"&gt;flash_scraper/remote-job-aggregator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;none yet (0)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$2.00 per 1,000 deduplicated jobs&lt;/td&gt;
&lt;td&gt;RemoteOK, We Work Remotely, Working Nomads, DevITjobs US, DevITjobs UK, The Muse, Remotive, Jobicy, Himalayas, HN "Who is hiring?" (10) plus opt-in Arbeitnow&lt;/td&gt;
&lt;td&gt;devitjobs.uk is down upstream and is reported per run, never billed. A change to $3 per 1,000 is scheduled for 2026-09-14&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When to pick which
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pick nivlekk/remote-jobs-aggregator if you want the absolute floor on price.&lt;/strong&gt; Fifty cents per 1,000 rows is half the price of the next cheapest ($1.00 per 1,000, inlifeprojects and delightful_unicorn) and a quarter of the $2 tier. Its title names three boards but its input schema offers seven, and there are no reviews yet; for a hobby feed or a first prototype the price is hard to argue with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick memo23/remote-jobs-aggregator if you want depth plus employer contacts.&lt;/strong&gt; RemoteOK's public feed returns the 100 newest listings by default, and an actor that pages past that returns jobs the others never see. Opt-in employer emails turn a job feed into a lead list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick benthepythondev/remote-jobs-aggregator if user count is your proxy for reliability.&lt;/strong&gt; At 738 users it is the most-used aggregator here, ahead of inlifeprojects (608) and 2.6x the next multi-board actor (sync-network, 282), and 747 of 748 runs succeeded in the 30 days to 2026-09-05. Do the arithmetic first: at $15 per 1,000 results plus $10 per 1,000 salary extractions, 1,000 jobs with salaries costs $25, against $2 to $2.50 from most of this table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick inlifeprojects/himalayas-jobs-scraper if Himalayas alone is enough.&lt;/strong&gt; Buying an aggregator to read one board is overhead you do not need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick flash_scraper/remote-job-aggregator if you want the widest keyless board sweep in one run, or if you want the same search to run daily and deliver only what is new.&lt;/strong&gt; Ten boards by default is the largest count in the table, and the two DevITjobs boards, The Muse and the Hacker News "Who is hiring?" thread are sources no other actor here names. Rows are merged across boards by canonical job URL and by (title, company), so a role on two boards ships and bills once. With &lt;code&gt;onlyNewJobs&lt;/code&gt; on a schedule, a run where nothing is new delivers zero rows and bills only the $0.00005 start. Hourly, weekly and monthly pay is converted to annual (times 2080, 52, 12) with a magnitude guard, so &lt;code&gt;salary_min&lt;/code&gt; sorts across every board on one axis.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ours does not do, stated plainly
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It has no reviews.&lt;/strong&gt; Zero, from 18 users, at the time of writing. Four of the eight actors in this table are in the same position, but it should be the first thing you weigh, not something you discover later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It covers no LinkedIn, Indeed or Glassdoor remote listings.&lt;/strong&gt; Ten keyless boards is ten public feeds. If you need the big three, that is a different actor and a different price bracket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Salary is on a minority of rows.&lt;/strong&gt; On the 2026-08-15 default run, 100 deduplicated jobs from 9 boards with 6 cross-board duplicates merged, 35 percent of rows carried a salary, 88 percent a description snippet and 100 percent a posting date. DevITjobs fills salary on nearly every row; The Muse and Working Nomads publish none at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One board is currently down.&lt;/strong&gt; devitjobs.uk has been unreachable upstream. Its absence is named in the run status and it is never billed, but it is nine working default boards today, not ten.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Republication is restricted.&lt;/strong&gt; Remotive's terms forbid re-posting their rows to other job boards. Jobicy allows it with credit and the original apply links kept. Himalayas asks for a link back to himalayas.app. These terms bind every actor in this table equally.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real run costs
&lt;/h2&gt;

&lt;p&gt;At $0.002 per deduplicated job, 500 jobs is $1.00, and 2,499 jobs at $0.002 plus the $0.00005 run start comes to $4.998 — so a $5 free-plan credit covers 2,499 jobs with change. Apify's free plan carries a monthly usage credit (currently $5, apify.com/pricing read 2026-09-05), which covers roughly 2,499 deduplicated jobs from this actor if spent on it alone. Duplicates merge before billing, filtered rows are never charged, and a nothing-new monitoring run bills only the $0.00005 start. A pricing record scheduled for 2026-09-14 raises the rate to $0.003 per job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short answers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is there a remote jobs API that needs no API key?&lt;/strong&gt; Every actor in this table is keyless, because they all read public feeds that require no registration. Running them through Apify does require an Apify token, and the free plan needs no card. If you want the feeds without Apify at all, RemoteOK, Remotive, Himalayas, Jobicy and Arbeitnow all publish open JSON endpoints you can call yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I get an alert for only new remote jobs?&lt;/strong&gt; Set an only-new flag and put the actor on an Apify schedule. flash_scraper/remote-job-aggregator (&lt;code&gt;onlyNewJobs&lt;/code&gt;) and benthepythondev's actor both name a new-only monitor in their listings. The billing consequence matters more than the feature: on a per-result actor, a monitor that re-delivers the same 400 jobs every morning bills you for 400 jobs every morning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many remote jobs can one run return?&lt;/strong&gt; It depends on the boards, not the actor. RemoteOK's public feed is the 100 newest listings unless an actor pages deeper, We Work Remotely's category RSS feeds run 25 to 100 rows each, and Working Nomads is a curated list of roughly 50. memo23 claims 2,000 to 3,000 unique jobs per run from six boards at full depth, which is the highest figure any listing in this table states.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Data source: Apify public Store API, read 2026-09-05. Author: Flash Scrape (&lt;code&gt;flash_scraper&lt;/code&gt; on Apify), publisher of one of the actors listed. Corrections welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>api</category>
      <category>python</category>
      <category>career</category>
    </item>
    <item>
      <title>Local Business Lead Scrapers on Apify Compared (September 2026)</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Sat, 05 Sep 2026 18:24:14 +0000</pubDate>
      <link>https://dev.to/7_akariae/local-business-lead-scrapers-on-apify-compared-september-2026-41g</link>
      <guid>https://dev.to/7_akariae/local-business-lead-scrapers-on-apify-compared-september-2026-41g</guid>
      <description>&lt;p&gt;&lt;strong&gt;Most local business lead scrapers on Apify are Google Maps scrapers with a website-crawling step bolted on. lukaskrivka/google-maps-with-contact-details is the most used (87,957 users, 4.63 stars). flash_scraper/local-business-leads is the outlier: it discovers businesses on OpenStreetMap instead of Google Maps, and includes MX email verification in its $3 per 1,000.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every figure below was read from Apify's public &lt;strong&gt;Store&lt;/strong&gt; API (&lt;code&gt;GET /v2/store&lt;/code&gt;) on &lt;strong&gt;2026-09-05&lt;/strong&gt; — including every user count, so they are all on the same footing. The per-actor endpoint (&lt;code&gt;GET /v2/acts/&amp;lt;id&amp;gt;&lt;/code&gt;) can read one higher: it gives flash_scraper/local-business-leads 33 rather than 32, and code-node-tools 33 as well. Prices, users and ratings change; the Pricing tab on each actor page is authoritative.&lt;/p&gt;

&lt;p&gt;Disclosure: I publish &lt;code&gt;flash_scraper/local-business-leads&lt;/code&gt;, one of the actors compared here. Its limits are listed in the same detail as everyone else's, including the one that will disqualify it for many buyers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How prices are normalised
&lt;/h2&gt;

&lt;p&gt;These actors bill per event, and the events differ in kind, which makes headline prices misleading. Some charge per place found. Some charge separately for the website crawl that actually produces the email. Some charge again to verify that the email is deliverable. The table lists the primary per-result event multiplied by 1,000 at the &lt;strong&gt;free-plan rate&lt;/strong&gt;, then names the add-on events, because a $5 per 1,000 place price with a $100 per 1,000 email-verification add-on is not a $5 tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paid Apify plans get tiered discounts on several of these actors, ours included&lt;/strong&gt; — and on the add-on events the discount can be enormous. lukaskrivka's three $100-per-1,000 add-ons fall to $4.00 (email verification), $7.50 (lead enrichment) and $10.00 (social-profile enrichment) per 1,000 on Bronze, and lower again above it (Store pricing record read 2026-09-05). Our own free-plan-to-Diamond spread is about 30 percent. So if you are on a paid plan, re-read every figure below off the Pricing tab: the free-plan column overstates the gap by a factor of 25 on those particular add-ons.&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison table
&lt;/h2&gt;

&lt;p&gt;Every row shows the same 30-day run-success figure, taken from the Store API on 2026-09-05, so the comparison is symmetrical rather than pointed at one actor.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;Users&lt;/th&gt;
&lt;th&gt;Rating (reviews)&lt;/th&gt;
&lt;th&gt;Price per 1,000&lt;/th&gt;
&lt;th&gt;30-day run success&lt;/th&gt;
&lt;th&gt;What it covers&lt;/th&gt;
&lt;th&gt;What to watch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/lukaskrivka/google-maps-with-contact-details" rel="noopener noreferrer"&gt;lukaskrivka/google-maps-with-contact-details&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;87,957&lt;/td&gt;
&lt;td&gt;4.63 (221)&lt;/td&gt;
&lt;td&gt;$5.00 per 1,000 places&lt;/td&gt;
&lt;td&gt;70,296 / 76,404 (92%)&lt;/td&gt;
&lt;td&gt;Google Maps places plus website crawl for emails, phones, socials, address, zipcode&lt;/td&gt;
&lt;td&gt;Add-ons are billed separately: contact enrichment $2.50/1k, place details $3.00/1k, filters $1.50/1k, and email verification, lead enrichment and social-profile enrichment at &lt;strong&gt;$100 per 1,000 each on Apify's free plan, falling to $4.00, $7.50 and $10.00 per 1,000 on Bronze&lt;/strong&gt; and lower above it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/s-r/google-maps-contact-details" rel="noopener noreferrer"&gt;s-r/google-maps-contact-details&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;166&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$4.00 per 1,000 places&lt;/td&gt;
&lt;td&gt;1,165 / 1,177 (99%)&lt;/td&gt;
&lt;td&gt;Google Maps places enriched from the business website: email, phone, Facebook, Instagram, LinkedIn, X, YouTube, TikTok&lt;/td&gt;
&lt;td&gt;$2.00/1k contact-enrichment event on top, plus a $0.002 run start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/santhej/nowebsite-lead-finder" rel="noopener noreferrer"&gt;santhej/nowebsite-lead-finder&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;220&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$8.00 per 1,000 leads&lt;/td&gt;
&lt;td&gt;412 / 438 (94%)&lt;/td&gt;
&lt;td&gt;Google Maps businesses &lt;strong&gt;without&lt;/strong&gt; a website, opportunity-scored, for web-design and marketing agencies&lt;/td&gt;
&lt;td&gt;Deliberately excludes businesses with sites, so no email crawl is possible; $0.001 run start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/faisalrjbd/google-maps-phone-email-extractor" rel="noopener noreferrer"&gt;faisalrjbd/google-maps-phone-email-extractor&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;170&lt;/td&gt;
&lt;td&gt;4.14 (4)&lt;/td&gt;
&lt;td&gt;$5.00 per 1,000 results&lt;/td&gt;
&lt;td&gt;66 / 66 (100%)&lt;/td&gt;
&lt;td&gt;Google Maps phones, emails, websites, socials, addresses, ratings, reviews&lt;/td&gt;
&lt;td&gt;Email verification is not named in the listing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/jurassic_jove/google-maps-lead-generator" rel="noopener noreferrer"&gt;jurassic_jove/google-maps-lead-generator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$20.00 per 1,000 leads&lt;/td&gt;
&lt;td&gt;59 / 64 (92%)&lt;/td&gt;
&lt;td&gt;Google Maps leads with a full Playwright visit to each business site for higher extraction accuracy&lt;/td&gt;
&lt;td&gt;Highest per-lead price in this table — 2.5x the next highest ($8) and 18x the cheapest ($1.10)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/leadharbor/google-maps-verified-email-scraper" rel="noopener noreferrer"&gt;leadharbor/google-maps-verified-email-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$3.00 per 1,000 leads&lt;/td&gt;
&lt;td&gt;127 / 143 (89%)&lt;/td&gt;
&lt;td&gt;Google Maps leads with MX-checked emails tagged valid / risky / invalid, CSV out&lt;/td&gt;
&lt;td&gt;Verification method is not detailed in the listing; no reviews yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/code-node-tools/google-maps-lead-scraper" rel="noopener noreferrer"&gt;code-node-tools/google-maps-lead-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$1.10 per 1,000 results&lt;/td&gt;
&lt;td&gt;155 / 160 (97%)&lt;/td&gt;
&lt;td&gt;Google Maps search plus website, phone, email and socials, streamed to the dataset&lt;/td&gt;
&lt;td&gt;Cheapest here; uses Apify residential proxy; verification not named&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/flash_scraper/local-business-leads" rel="noopener noreferrer"&gt;flash_scraper/local-business-leads&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;5.0 (3)&lt;/td&gt;
&lt;td&gt;$3.00 per 1,000 delivered leads, MX verification included&lt;/td&gt;
&lt;td&gt;166 / 173 (96%)&lt;/td&gt;
&lt;td&gt;OpenStreetMap discovery, own-website crawl for MX-verified email, phone, socials, site platform, 0-100 lead score, 73 stable columns, Google Maps link on every row&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Does not scrape Google Maps&lt;/strong&gt;, so no Google star ratings or review counts. A change to $5 per 1,000 is scheduled in its pricing record for 2026-09-14&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When to pick which
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pick lukaskrivka/google-maps-with-contact-details if you want the most-reviewed option and you are buying places, not verified emails.&lt;/strong&gt; 221 reviews at 4.63 is the strongest social proof in local lead generation on Apify. Budget carefully: at $5 per 1,000 places plus $2.50 per 1,000 contact enrichments you are near $7.50 per 1,000 before verification, and the verification add-on is priced at $100 per 1,000 on the free plan (it drops to $4 per 1,000 on Bronze, so on a paid plan this is a much smaller consideration than the free-plan sticker suggests).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick santhej/nowebsite-lead-finder if you sell websites.&lt;/strong&gt; Filtering Google Maps down to businesses with no site is a different job from lead scraping, and $8 per lead is reasonable when every row is a qualified pitch. It is the wrong tool for email outreach: a business with no website usually has no email to find.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick code-node-tools/google-maps-lead-scraper if price per row is the whole decision.&lt;/strong&gt; At $1.10 per 1,000 it is a third of the next cheapest. No reviews yet, so run a small batch and check the email column first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick leadharbor or flash_scraper if bounce rate is what you actually care about.&lt;/strong&gt; Both include MX checking in the per-lead price rather than charging for it separately. leadharbor grades each address valid / risky / invalid from Google Maps discovery. flash_scraper grades them deliverable / risky / undeliverable, adds a mailbox-ownership classification (own domain, free inbox, or the business's marketing agency), and never promotes a pattern-guessed address into the &lt;code&gt;email&lt;/code&gt; column: guesses stay in &lt;code&gt;email_guess&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick flash_scraper/local-business-leads specifically when you want one flat price with the crawl, the verification, the scoring and the socials all inside it, and you do not need Google's star ratings.&lt;/strong&gt; On the reference run (&lt;code&gt;dentist&lt;/code&gt;, Austin Texas, &lt;code&gt;onlyWithWebsite: true&lt;/code&gt;, n=55, measured 2026-08-08), 96 percent of rows carried a phone, 55 percent an MX-verified email, 73 percent a Facebook profile and 71 percent an identified website platform. Filters run before billing, so a run that finds nothing charges nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ours does not do, stated plainly
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It does not scrape Google Maps.&lt;/strong&gt; Discovery runs on OpenStreetMap. That is the reason it needs no API key, no proxy and no login, and it is also the reason there are no Google star ratings and no Google review counts on the rows. The &lt;code&gt;rating&lt;/code&gt; and &lt;code&gt;review_count&lt;/code&gt; columns exist only when a business publishes a rating in its own website markup, measured at about 7 percent of rows (4 of 55 on the 2026-08-08 reference run). Every row carries a &lt;code&gt;google_maps_url&lt;/code&gt; that opens a Maps search for that business, but nothing is read from Google.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenStreetMap coverage is uneven by category.&lt;/strong&gt; The Austin bounding box held 171 dentists but 9 plumbers and 5 electricians. Storefront categories (dentists, gyms, salons, restaurants, law firms, real estate offices) are dense. Van-based trades are thin. If plumbers in one city is your list, a Google Maps actor will find more of them, and that is a straight factual advantage for the other seven rows in the table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email fill is a fraction, not a sheet.&lt;/strong&gt; 55 percent on the reference run with &lt;code&gt;onlyWithWebsite: true&lt;/code&gt; (n=55), and 26 percent with every filter off (n=100), both measured 2026-08-08. Any actor promising near-total email coverage on local businesses is describing pattern guesses, not found addresses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It has 32 users and 3 reviews.&lt;/strong&gt; That is the smallest footprint in this table — code-node-tools is next at 33 users, and on the authoritative &lt;code&gt;/v2/acts&lt;/code&gt; endpoint both read 33 today, so call it a tie for last. Test it on 10 rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real run costs
&lt;/h2&gt;

&lt;p&gt;At $0.003 per delivered lead, 1,000 leads is $3.00 and MX verification is inside that number. A 100-lead test is $0.30. Apify's free plan carries a monthly usage credit (currently $5), which is roughly 1,600 leads if spent on this actor alone. Every filter (&lt;code&gt;onlyWithEmail&lt;/code&gt;, &lt;code&gt;onlyVerifiedEmail&lt;/code&gt;, &lt;code&gt;onlyWithWebsite&lt;/code&gt;, &lt;code&gt;requirePhone&lt;/code&gt;) runs before billing. A pricing record scheduled for 2026-09-14 raises the rate to $0.005 per lead, so check the Pricing tab rather than trusting this paragraph after that date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short answers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is there a local business scraper that needs no API key and no proxy?&lt;/strong&gt; Yes. &lt;code&gt;flash_scraper/local-business-leads&lt;/code&gt; runs discovery on OpenStreetMap and crawls each business's own public website from datacenter IPs, so there is nothing to configure. The Google Maps actors in this table generally require Apify's proxy, and one of them (code-node-tools) states it uses the residential pool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the cheapest way to get verified business emails?&lt;/strong&gt; On the numbers above, the two flat-rate MX-checking actors: leadharbor at $3 per 1,000 and flash_scraper at $3 per 1,000, both with verification included. The pattern to avoid is a low place price with a three-figure-per-thousand verification add-on on the plan you are actually on — lukaskrivka's is $100 per 1,000 on the free plan and $4 per 1,000 on Bronze, which is exactly why headline comparisons between these actors are unreliable unless you name your plan tier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a 0-100 lead score a customer rating?&lt;/strong&gt; No. On flash_scraper/local-business-leads it measures completeness and reachability of the contact data, not the quality of the business. A dentist with a bad reputation and a full contact block scores higher than a beloved one with no website.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Data source: Apify public Store API, read 2026-09-05. Author: Flash Scrape (&lt;code&gt;flash_scraper&lt;/code&gt; on Apify), publisher of one of the actors listed. Corrections welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>api</category>
      <category>python</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Multi Job Board Scrapers on Apify Compared (September 2026)</title>
      <dc:creator>Zakaria Blefkih</dc:creator>
      <pubDate>Sat, 05 Sep 2026 18:23:54 +0000</pubDate>
      <link>https://dev.to/7_akariae/multi-job-board-scrapers-on-apify-compared-september-2026-16o2</link>
      <guid>https://dev.to/7_akariae/multi-job-board-scrapers-on-apify-compared-september-2026-16o2</guid>
      <description>&lt;p&gt;&lt;strong&gt;The best multi job board scraper on Apify depends on which boards you need. openclawai/job-board-scraper is the most used (2,582 users) and reaches Google Jobs and ZipRecruiter. flash_scraper/multi-jobboard-scraper covers 12 selectable working boards — 11 of which deliver rows today, after DevITjobs UK went dead upstream — and deduplicates a role posted on three boards into one billed row. Both cost $5 per 1,000 results.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every figure below was read from Apify's public Store API (&lt;code&gt;https://api.apify.com/v2/store&lt;/code&gt;) on &lt;strong&gt;2026-09-05&lt;/strong&gt;. User counts, ratings, review counts and prices on Apify change without notice, so treat this as a dated snapshot and check the Pricing tab on each actor page before you budget a run.&lt;/p&gt;

&lt;p&gt;Disclosure: I publish &lt;code&gt;flash_scraper/multi-jobboard-scraper&lt;/code&gt;, one of the actors in the table. I have not put it first, and its limits are stated below in the same detail as everyone else's.&lt;/p&gt;

&lt;h2&gt;
  
  
  How prices are normalised
&lt;/h2&gt;

&lt;p&gt;Apify actors bill per event, and most job scrapers charge one primary event per delivered job. The "Price per 1,000" column is that primary event multiplied by 1,000, at the &lt;strong&gt;free-plan rate&lt;/strong&gt;. Paid Apify plans get tiered discounts on several of these actors. Where an actor also charges a meaningful run-start fee or a second event, it is named in the same cell, because a $0.10 run start changes the economics of a 20-row test run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;Users&lt;/th&gt;
&lt;th&gt;Rating (reviews)&lt;/th&gt;
&lt;th&gt;Price per 1,000&lt;/th&gt;
&lt;th&gt;What it covers&lt;/th&gt;
&lt;th&gt;What its Store listing does not name&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/openclawai/job-board-scraper" rel="noopener noreferrer"&gt;openclawai/job-board-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;2,582&lt;/td&gt;
&lt;td&gt;5.0 (3)&lt;/td&gt;
&lt;td&gt;$5.00 (+ $0.01/1k dataset items, $0.00005 start)&lt;/td&gt;
&lt;td&gt;LinkedIn, Indeed, Glassdoor, Google Jobs and ZipRecruiter in one run&lt;/td&gt;
&lt;td&gt;Cross-board deduplication, only-new monitoring, keyless remote boards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/doggo/uk-jobs-board-scraper" rel="noopener noreferrer"&gt;doggo/uk-jobs-board-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;368&lt;/td&gt;
&lt;td&gt;5.0 (2)&lt;/td&gt;
&lt;td&gt;$5.00 (+ &lt;strong&gt;$0.10 per run start&lt;/strong&gt;)&lt;/td&gt;
&lt;td&gt;Indeed, Reed, Totaljobs, CV-Library, Adzuna, RemoteOK, Arbeitnow across UK, US and Europe&lt;/td&gt;
&lt;td&gt;LinkedIn, Glassdoor, deduplication, alert mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/khadinakbar/jobs-scraper" rel="noopener noreferrer"&gt;khadinakbar/jobs-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;353&lt;/td&gt;
&lt;td&gt;none yet (0)&lt;/td&gt;
&lt;td&gt;$3.00 (+ $0.00005 start)&lt;/td&gt;
&lt;td&gt;Indeed, LinkedIn, Glassdoor; MCP and API ready&lt;/td&gt;
&lt;td&gt;Deduplication, remote boards, ATS boards, monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/vero-api/multi-job-board-scraper-linkedin-indeed-glassdoor-more" rel="noopener noreferrer"&gt;vero-api/multi-job-board-scraper-linkedin-indeed-glassdoor-more&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;208&lt;/td&gt;
&lt;td&gt;5.0 (1)&lt;/td&gt;
&lt;td&gt;$5.00 (+ $0.00005 start)&lt;/td&gt;
&lt;td&gt;LinkedIn, Indeed, Glassdoor plus Bayt, Naukri and BDJobs for Gulf and South Asia&lt;/td&gt;
&lt;td&gt;Deduplication, remote boards, alert mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/curious_coder/linkedin-jobs-scraper" rel="noopener noreferrer"&gt;curious_coder/linkedin-jobs-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;148,567&lt;/td&gt;
&lt;td&gt;4.59 (140)&lt;/td&gt;
&lt;td&gt;$2.00 (+ $0.00005 start)&lt;/td&gt;
&lt;td&gt;LinkedIn only, with full job details, job poster and company data&lt;/td&gt;
&lt;td&gt;Any second board&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/misceres/indeed-scraper" rel="noopener noreferrer"&gt;misceres/indeed-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;30,224&lt;/td&gt;
&lt;td&gt;2.86 (66)&lt;/td&gt;
&lt;td&gt;$6.00&lt;/td&gt;
&lt;td&gt;Indeed only, organic and sponsored listings&lt;/td&gt;
&lt;td&gt;Any second board&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/memo23/apify-indeed-cheerio-ppr" rel="noopener noreferrer"&gt;memo23/apify-indeed-cheerio-ppr&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;704&lt;/td&gt;
&lt;td&gt;4.51 (8)&lt;/td&gt;
&lt;td&gt;$1.49 (+ $0.007 start)&lt;/td&gt;
&lt;td&gt;Indeed only, plus employer firmographics (CEO, revenue, industry) and optional contact emails&lt;/td&gt;
&lt;td&gt;Any second board&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/flash_scraper/multi-jobboard-scraper" rel="noopener noreferrer"&gt;flash_scraper/multi-jobboard-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td&gt;5.0 (3)&lt;/td&gt;
&lt;td&gt;$5.00 (+ $0.00005 start)&lt;/td&gt;
&lt;td&gt;LinkedIn, Indeed, Glassdoor plus 9 keyless public boards including The Muse — 12 selectable working boards, of which DevITjobs UK has been discontinued upstream since 2026-08-29 (re-probed 2026-09-05), so 11 deliver rows today — cross-board dedup, only-new alerts, Greenhouse/Lever/Ashby ATS&lt;/td&gt;
&lt;td&gt;Google Jobs, ZipRecruiter, Bayt, BDJobs, Naukri (blocked at source)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last column is deliberately narrow in scope: it lists what an actor's own Apify Store title and description did &lt;strong&gt;not&lt;/strong&gt; claim on 2026-09-05. It is not a test result. An actor may well do something its listing never mentions, and the only way to know is to run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to pick which
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pick openclawai/job-board-scraper if Google Jobs or ZipRecruiter is non-negotiable.&lt;/strong&gt; It is the only actor in this group whose listing names both, and with 2,582 users it is the most battle-tested multi-board option here. Google Jobs in particular has no keyless route that I have been able to reproduce, so an actor that claims it is worth trying on a small run first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick curious_coder/linkedin-jobs-scraper if you only ever need LinkedIn.&lt;/strong&gt; At 148,567 users and 4.59 stars from 140 reviews, it is the most reviewed of the job scrapers a Store search surfaced on 2026-09-05, and $2 per 1,000 is less than half what any multi-board actor charges. Buying a multi-board tool to scrape one board is paying for plumbing you will not use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick memo23/apify-indeed-cheerio-ppr if you want Indeed rows that double as sales leads.&lt;/strong&gt; At $1.49 per 1,000 it is the cheapest per-row option in the table, and employer firmographics plus optional contact-email enrichment is a combination the other Indeed actors do not advertise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick vero-api or doggo for regional depth.&lt;/strong&gt; Bayt, Naukri and BDJobs (vero-api) cover the Gulf and South Asia; Reed, Totaljobs, CV-Library and Adzuna (doggo) cover the UK. If your search is regional, board coverage beats every other consideration. Watch doggo's $0.10 run start if you plan many small scheduled runs: 30 daily runs is $3 per month before a single row is delivered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick flash_scraper/multi-jobboard-scraper if duplicates are your actual problem, or if you want the same search to run daily and deliver only what is new.&lt;/strong&gt; A role posted on LinkedIn, Indeed and Glassdoor arrives as one row carrying &lt;code&gt;found_on_sites&lt;/code&gt; and &lt;code&gt;duplicate_count&lt;/code&gt;, and it bills once rather than three times. With &lt;code&gt;onlyNewJobs&lt;/code&gt; on a schedule, a run where nothing is new delivers zero rows and bills only the $0.00005 start. On a measured run of 90 raw rows on 2026-08-08, 89 were billed after the merge. It also reaches Greenhouse, Lever and Ashby, so company career pages come through the same schema as the big boards.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ours does not do, stated plainly
&lt;/h2&gt;

&lt;p&gt;Five selectable boards are &lt;strong&gt;blocked at the source&lt;/strong&gt;: Google Jobs serves a bot-check page, ZipRecruiter returns HTTP 403, Naukri demands a CAPTCHA, and Bayt and BDJobs also refuse. That was checked on 2026-08-07 and re-measured on 2026-08-11. If Google Jobs is your requirement, this actor is the wrong tool and openclawai's is the one to try.&lt;/p&gt;

&lt;p&gt;It never logs in and never auto-applies, so nothing behind a login wall is reachable. It is not a historical archive; each run reads what the boards are showing now. LinkedIn pay comes from the public search card and the posting text, not from the fuller base-pay block LinkedIn shows on some job pages (present on 2 of 6 postings measured 2026-08-29). Glassdoor tops out around 28 to 30 rows per query, which is a board-side cap, and it returns HTTP 403 on some runs entirely, in which case the run status names the board and the missing board bills nothing.&lt;/p&gt;

&lt;p&gt;One of the twelve selectable boards is also dead at source rather than blocked: &lt;strong&gt;DevITjobs UK was discontinued upstream on 2026-08-29&lt;/strong&gt; — a direct probe of &lt;code&gt;devitjobs.uk/api/jobsLight&lt;/code&gt; on 2026-09-05 returns a 302 to a signup page — so eleven boards deliver rows today. Its absence is reported in the run status and it is never billed.&lt;/p&gt;

&lt;p&gt;And the honest commercial caveat: at 42 users it is the smallest multi-board actor in this table — a fifth of vero-api's 208 and under 2% of openclawai's 2,582. Three reviews averaging 5.0 is three reviews, not a track record. Run it on 20 rows before you trust it with 2,000.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real run costs
&lt;/h2&gt;

&lt;p&gt;At the free-plan rate of $0.005 per deduplicated job, an untouched form (four default boards, up to 20 rows each) delivers at most 80 rows for at most $0.40. A 500-job sweep is $2.50. Filtered-out rows are never billed, and a failed or empty run bills only the $0.00005 start. Apify's free plan carries a monthly usage credit (currently $5), which covers roughly 1,000 deduplicated jobs from this actor if spent on it alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short answers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which job board scrapers on Apify need no API key?&lt;/strong&gt; All eight in this table are keyless. &lt;strong&gt;None of their Store listings asks for a LinkedIn, Indeed or Glassdoor login&lt;/strong&gt; — they describe reading public search pages. (That is a reading of eight listings, not a test of eight actors: we have not run the seven we do not publish.) Keyless does not mean unblockable: Glassdoor intermittently 403s across every actor here, and Google Jobs refuses everyone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does salary data actually come through?&lt;/strong&gt; More often than most people expect. On flash_scraper/multi-jobboard-scraper's measured runs, &lt;code&gt;salary_min&lt;/code&gt; and friends were filled on &lt;strong&gt;59 to 70 percent of rows with LinkedIn detail fetching on (the default)&lt;/strong&gt; and 56 to 60 percent with it off — Glassdoor 95 to 100 percent, Indeed 50 to 80 percent depending on query, LinkedIn roughly 35 percent and only with detail fetching. Measured 2026-08-07 and re-checked across all 5,936 delivered rows on 2026-08-23. Any actor claiming near-total salary coverage across LinkedIn is worth checking on a small run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I republish the rows on my own job board?&lt;/strong&gt; Not universally. Remotive's terms forbid re-posting to other job boards. Jobicy allows it with credit and the original apply links kept. Himalayas asks for a link back to himalayas.app. LinkedIn, Indeed and Glassdoor terms do not contemplate republication at all. Read each board's terms before building a job site on scraped rows.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Data source: Apify public Store API, read 2026-09-05. Author: Flash Scrape (&lt;code&gt;flash_scraper&lt;/code&gt; on Apify), publisher of one of the actors listed. Corrections welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>api</category>
      <category>python</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
