<?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: VNCNT LABS</title>
    <description>The latest articles on DEV Community by VNCNT LABS (@vncntlabs).</description>
    <link>https://dev.to/vncntlabs</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%2F4191115%2F59d59191-ba58-4c46-9e74-77c098f08213.png</url>
      <title>DEV Community: VNCNT LABS</title>
      <link>https://dev.to/vncntlabs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vncntlabs"/>
    <language>en</language>
    <item>
      <title>A website SEO audit from an API: broken links, 404s and on-page issues for $3 per 1,000 pages (Python, curl, MCP)</title>
      <dc:creator>VNCNT LABS</dc:creator>
      <pubDate>Fri, 30 Oct 2026 14:18:39 +0000</pubDate>
      <link>https://dev.to/vncntlabs/a-website-seo-audit-from-an-api-broken-links-404s-and-on-page-issues-for-3-per-1000-pages-4m0j</link>
      <guid>https://dev.to/vncntlabs/a-website-seo-audit-from-an-api-broken-links-404s-and-on-page-issues-for-3-per-1000-pages-4m0j</guid>
      <description>&lt;p&gt;This morning I ran an audit on vncntlabs.com and it came back with 9 broken links on a 10-page crawl. That got my attention for about thirty seconds. Every one of them pointed at &lt;code&gt;/cdn-cgi/l/email-protection&lt;/code&gt;, the URL Cloudflare swaps in for email addresses. Crawlers get a 404 there. Real visitors never do, because a script rewrites the link in the browser.&lt;/p&gt;

&lt;p&gt;So the audit was right (a crawler really does see a 404) and it's also not something I need to fix. That's the kind of thing I wanted an audit tool to say in plain words, so the tool I built, &lt;a href="https://apify.com/vncntlabs/website-seo-audit?fpr=vccewy" rel="noopener noreferrer"&gt;Website SEO Audit&lt;/a&gt;, puts a note on those rows: "crawlers see a 404 here, real visitors don't. Usually safe to ignore."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(The Store links here carry my Apify affiliate ID, so Apify pays me a small commission if you sign up through one.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What a run gives you
&lt;/h2&gt;

&lt;p&gt;You pass a domain and a page limit. It crawls the site and writes three kinds of rows, each with a &lt;code&gt;type&lt;/code&gt; field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;page&lt;/code&gt;: status code, title and its length, meta description, H1, word count, load time and the list of issues on that page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;site&lt;/code&gt;: an overall score, pages crawled, broken pages, broken links, duplicate titles and content, sitemap, robots.txt, SSL and HTTPS redirect checks, and every issue grouped with how many pages it hits and a short fix&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;broken-link&lt;/code&gt;: the page the link sits on, the anchor text, the target and the status code it returned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also skip the crawl and pass single page URLs. That's handy for a page you just published.&lt;/p&gt;

&lt;p&gt;Here's my own site from today's run. Score 85.14 out of 100, 10 pages crawled (9 HTML pages plus the Cloudflare URL itself), 213 internal links and 37 external ones. Besides the 9 email links it flagged:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the home page title at 68 characters, over the 65 it wants&lt;/li&gt;
&lt;li&gt;the /apps/ page title at 25 characters ("Android Apps · VNCNT Labs"), under 30&lt;/li&gt;
&lt;li&gt;one image without alt text on the home page&lt;/li&gt;
&lt;li&gt;render-blocking CSS or scripts on all 9 pages&lt;/li&gt;
&lt;li&gt;3 URLs it calls not SEO friendly (/apps/ferntimer/, /apps/housetimer/ and /apps/whentimer/, I guess because the words run together)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sitemap, robots.txt, SSL, HTTP/2 and the HTTP to HTTPS redirect all passed. Honestly the alt text is the only thing on that list I'm going to fix today. The URLs are app names and they're staying.&lt;/p&gt;

&lt;p&gt;For a second test I used books.toscrape.com, a public practice site for scrapers. 10 pages scored 92.2 with no broken links, but it has no XML sitemap, no robots.txt, HTTP doesn't redirect to HTTPS, and all 10 pages are missing a meta description. All 10 were also flagged as near-duplicate content, which makes sense since they're all product grids. It caught that &lt;code&gt;/&lt;/code&gt; and &lt;code&gt;/index.html&lt;/code&gt; share the title "All products | Books to Scrape - Sandbox", which is the kind of duplicate you only notice when something lists it for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Python with &lt;code&gt;apify-client&lt;/code&gt; 3.x. In 3.x &lt;code&gt;call()&lt;/code&gt; returns a &lt;code&gt;Run&lt;/code&gt; object, so the dataset ID is &lt;code&gt;run.default_dataset_id&lt;/code&gt;, not &lt;code&gt;run["defaultDatasetId"]&lt;/code&gt;:&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="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;websites&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;books.toscrape.com&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;maxPagesPerSite&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="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;vncntlabs/website-seo-audit&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="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&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="n"&gt;default_dataset_id&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;site&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;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;site&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;| score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;onpageScore&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;| pages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pagesCrawled&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;| broken pages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brokenPages&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;| broken links&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brokenLinks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;issue&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;issues&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&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="nf"&gt;print&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;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pagesAffected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;site-wide&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;issue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;issue&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;-&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;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;howToFix&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;broken-link&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  broken link&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;linkFrom&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;-&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;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;linkTo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;targetStatusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;issues&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&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="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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;issues&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That took 52 seconds end to end today and printed the 10 pages, then this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;books.toscrape.com ok | score 92.2 | pages 10 | broken pages 0 | broken links 0
   site-wide | No XML sitemap found -&amp;gt; Publish /sitemap.xml and list it in robots.txt.
   site-wide | HTTP doesn't redirect to HTTPS -&amp;gt; Add a site-wide 301 from http:// to https://.
   10 | Missing meta description -&amp;gt; Write a 120 to 160 character description that matches the page.
   10 | Low text-to-HTML ratio -&amp;gt; Add useful text or trim heavy markup.
   10 | Very little text on the page -&amp;gt; Add more helpful content, or noindex the page if it shouldn't rank.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checking two single pages with curl, no crawl:&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;-sS&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/vncntlabs~website-seo-audit/run-sync-get-dataset-items?timeout=290"&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="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&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;'{"pageUrls":["https://books.toscrape.com/","https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one came back in about 4 seconds with two &lt;code&gt;page&lt;/code&gt; rows (scores 97.07 and 97.44). The home page got dinged for the missing meta description and a missing charset meta tag.&lt;/p&gt;

&lt;p&gt;If you use Claude, Cursor or another MCP client, add this as a remote MCP server. It loads only this one Actor, and you sign in to Apify in the browser, so no token goes in the file:&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;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apify"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"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://mcp.apify.com/?tools=vncntlabs/website-seo-audit"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Node version is in the repo linked at the bottom.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed and cost
&lt;/h2&gt;

&lt;p&gt;It's not instant. The crawl runs on DataForSEO's OnPage crawler, and both 10-page runs today took about 46 seconds on the platform. Queue time is the wild card. On Oct 28 a 20-page test took close to 5 minutes, almost all of it waiting. That's why the curl example checks single pages: the sync endpoint gives up after 300 seconds, so for a real crawl start the run and read the dataset when it's done (which is what the Python does).&lt;/p&gt;

&lt;p&gt;Price is $0.005 per run plus $0.003 per page audited. Both 10-page runs were $0.035 each, the 2-page curl check was $0.011, and 1,000 pages comes to about $3. Sites that can't be crawled and single URLs that fail to load aren't charged. A 404 found during a crawl does count as an audited page, since finding it is the point. On the free Apify plan a run audits one site of up to 25 pages plus 10 single URLs.&lt;/p&gt;

&lt;p&gt;It doesn't render JavaScript, and it won't log in. Sites that build their content in the browser, or sit behind a login or a bot wall, will come back thin.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it compares
&lt;/h2&gt;

&lt;p&gt;I checked these today (October 30, 2026) on the Apify Store API and Screaming Frog's site.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/vncntlabs/website-seo-audit?fpr=vccewy" rel="noopener noreferrer"&gt;vncntlabs/website-seo-audit&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Crawls a site or checks single URLs; page, site and broken-link rows&lt;/td&gt;
&lt;td&gt;$0.005 per run + $0.003 per page ($3.01 per 1,000)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;smart-digital/complete-seo-audit-tool&lt;/td&gt;
&lt;td&gt;Crawls a site; 0 to 100 score per page, meta tags, headings, schema, images, accessibility, Core Web Vitals per its description&lt;/td&gt;
&lt;td&gt;$0.04 per page free plan, $0.035 Silver, $0.03 Gold and up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;logiover/bulk-url-status-checker&lt;/td&gt;
&lt;td&gt;Status codes and redirect chains for a list of URLs you give it, no crawl&lt;/td&gt;
&lt;td&gt;$0.0025 per URL free plan, down to $0.001 Gold and up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Screaming Frog SEO Spider&lt;/td&gt;
&lt;td&gt;Desktop crawler, 300+ issue types&lt;/td&gt;
&lt;td&gt;Free up to 500 URLs per crawl, £199 a year for more&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Where they're better, plainly. smart-digital's audit checks more things than mine (schema, accessibility and performance are all toggles in its input) and has 787 users with a 5.0 rating. Mine has 1 user. If you want depth per page and don't mind paying about 13 times more, that's a reasonable pick. If you already have a list of URLs and only want status codes and redirect chains, logiover's checker is cheaper per URL than mine and traces redirects. And for a one-off audit of your own site from a laptop, Screaming Frog's free version is hard to beat. It renders JavaScript too, which mine doesn't.&lt;/p&gt;

&lt;p&gt;Where mine fits is when the audit has to run somewhere else: on a schedule, inside a script or an n8n flow, across a list of client sites, or as a tool an AI agent can call, at a per-page price that doesn't hurt when you run it every week. I haven't run the other two Actors on the same sites, so I'm not going to claim mine finds more.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/PravinrajV/vncntlabs-apify-examples/tree/main/10-website-seo-audit" rel="noopener noreferrer"&gt;https://github.com/PravinrajV/vncntlabs-apify-examples/tree/main/10-website-seo-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What do you check first when you audit a site? I always go straight to the broken links, then the missing meta descriptions, and I'd like to know if anyone actually acts on the render-blocking warnings.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;em&gt;Disclosure: I build the Apify Actor used here (VNCNT Labs). Every number in this post comes from a real run on Oct 30, 2026 (plus the 20-page queue timing noted above from Oct 28), and the prices are Apify Store list prices checked that day.&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>python</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>YouTube transcript API: full text and timestamps from links, keyword searches or channels for $0.005 a video (Python, curl, MCP)</title>
      <dc:creator>VNCNT LABS</dc:creator>
      <pubDate>Tue, 27 Oct 2026 14:31:12 +0000</pubDate>
      <link>https://dev.to/vncntlabs/youtube-transcript-api-full-text-and-timestamps-from-links-keyword-searches-or-channels-for-31kd</link>
      <guid>https://dev.to/vncntlabs/youtube-transcript-api-full-text-and-timestamps-from-links-keyword-searches-or-channels-for-31kd</guid>
      <description>&lt;p&gt;A friend asked me which ChatGPT tutorial to send her mom to. I typed "chatgpt tutorial for beginners" into YouTube and got five long videos back, 2 hours 40 minutes of them in total. I wasn't going to watch all of that to answer one text message. I wanted the words, with timestamps, so I could skim them, search them and hand them to a model.&lt;/p&gt;

&lt;p&gt;So I ran my own Apify Actor, &lt;a href="https://apify.com/vncntlabs/youtube-transcript-scraper?fpr=vccewy" rel="noopener noreferrer"&gt;YouTube Transcript Scraper&lt;/a&gt;, on that search. Here's what came back, what it cost, the code, and where other transcript Actors on the Apify Store are simply better.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(The Store links here carry my Apify affiliate ID, so Apify pays me a small commission if you sign up through one.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The run
&lt;/h2&gt;

&lt;p&gt;This is the Actor's public &lt;a href="https://apify.com/vncntlabs/youtube-transcript-scraper/examples/youtube-keyword-transcripts?fpr=vccewy" rel="noopener noreferrer"&gt;keyword preset&lt;/a&gt;, unchanged:&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;"keywords"&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;"chatgpt tutorial for beginners"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxVideosPerKeyword"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"excludeShorts"&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;The search found 32 videos, none of the top ones were Shorts, and it queued the first 5. The run took 47 seconds and returned 6 rows: one summary row for the keyword and one transcript row per video. All 5 came back with captions, so all 5 were charged at $0.005. That's $0.025 for 31,701 words.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Video&lt;/th&gt;
&lt;th&gt;Channel&lt;/th&gt;
&lt;th&gt;Length&lt;/th&gt;
&lt;th&gt;Words&lt;/th&gt;
&lt;th&gt;Views&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;ChatGPT for Beginners - 2026 Edition&lt;/td&gt;
&lt;td&gt;AI Mastermind&lt;/td&gt;
&lt;td&gt;16 min&lt;/td&gt;
&lt;td&gt;2,543&lt;/td&gt;
&lt;td&gt;595,711&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;ChatGPT Tutorial: How to Use Chat GPT For Beginners&lt;/td&gt;
&lt;td&gt;Charlie Chang&lt;/td&gt;
&lt;td&gt;27 min&lt;/td&gt;
&lt;td&gt;6,253&lt;/td&gt;
&lt;td&gt;4,984,364&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;ChatGPT Work Tutorial for Beginners&lt;/td&gt;
&lt;td&gt;Kevin Stratvert&lt;/td&gt;
&lt;td&gt;9 min&lt;/td&gt;
&lt;td&gt;1,766&lt;/td&gt;
&lt;td&gt;65,944&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;FULL ChatGPT Tutorial For Beginners in 2026! (Become a PRO)&lt;/td&gt;
&lt;td&gt;AI Foundations&lt;/td&gt;
&lt;td&gt;91 min&lt;/td&gt;
&lt;td&gt;18,428&lt;/td&gt;
&lt;td&gt;26,887&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;ChatGPT Tutorial for Beginners: How to Actually Get Work Done with AI&lt;/td&gt;
&lt;td&gt;Kevin Stratvert&lt;/td&gt;
&lt;td&gt;14 min&lt;/td&gt;
&lt;td&gt;2,711&lt;/td&gt;
&lt;td&gt;110,648&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each transcript row has the full text, a &lt;code&gt;segments&lt;/code&gt; list (&lt;code&gt;start&lt;/code&gt;, &lt;code&gt;duration&lt;/code&gt;, &lt;code&gt;end&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt; in seconds), the caption language, title, channel, views, length and the search rank. For the record, my answer to the text message was video 1. It opens with "now I know how intimidating a new technology can be for somebody who's trying to learn especially if you're a little bit older", which is exactly the audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the transcripts actually look like
&lt;/h2&gt;

&lt;p&gt;Two things surprised me once I read the raw rows.&lt;/p&gt;

&lt;p&gt;First, you can tell automatic captions from creator captions without being told. Kevin Stratvert's two videos come back as proper sentences: 161 and 164 segments, punctuation, no overlapping times. The AI Mastermind and Charlie Chang videos are lowercase with almost no punctuation, and nearly every segment overlaps the next one (349 of 363 and 833 of 837). That's YouTube's rolling auto captions. The text itself isn't duplicated, only the timing overlaps, so joining the segments gives you exactly the &lt;code&gt;transcript&lt;/code&gt; field. But it also means auto captions spell things the way they hear them. Video 1 says "chat gbt" 22 times, and the 91-minute one has "ChatGBT" 52 times. If you search transcripts for a product name, search for the misspellings too.&lt;/p&gt;

&lt;p&gt;Second, search order moves. I ran the same input again two minutes later for the code below and videos 4 and 5 had swapped places. If you're tracking rankings over time, store the &lt;code&gt;searchRank&lt;/code&gt; with a date and don't treat one run as gospel.&lt;/p&gt;

&lt;h2&gt;
  
  
  A single video, with [mm:ss] lines
&lt;/h2&gt;

&lt;p&gt;For one link I like the timestamped text field. It's one string with a timestamp in front of every line, which is the easiest thing to paste into notes or a prompt. This is the &lt;a href="https://apify.com/vncntlabs/youtube-transcript-scraper/examples/youtube-video-transcript?fpr=vccewy" rel="noopener noreferrer"&gt;single-video preset&lt;/a&gt; on Steve Jobs' 2005 Stanford speech:&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;-sS&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/vncntlabs~youtube-transcript-scraper/run-sync-get-dataset-items?maxTotalChargeUsd=0.01"&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="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&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;'{"videos":["https://www.youtube.com/watch?v=UF8uR6Z6KLc"],"includeSegments":false,"includeTimestampedText":true}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.[0].timestampedTranscript'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; jobs.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That took 24 seconds and wrote 244 lines (2,298 words). &lt;code&gt;grep -n "Stay Hungry" jobs.txt&lt;/code&gt; finds &lt;code&gt;[14:08] Beneath it were the words: "Stay Hungry. Stay Foolish."&lt;/code&gt; straight away, which is the kind of lookup I actually use this for.&lt;/p&gt;

&lt;p&gt;One gap I should mention: for videos you pass as links, &lt;code&gt;views&lt;/code&gt; and &lt;code&gt;videoDurationSeconds&lt;/code&gt; come back empty. Those come from search results, so only keyword and channel rows have them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning it into chunks for RAG
&lt;/h2&gt;

&lt;p&gt;This is the Python I ran for the search above, with &lt;code&gt;apify-client&lt;/code&gt; 3.x. In 3.x &lt;code&gt;call()&lt;/code&gt; returns a &lt;code&gt;Run&lt;/code&gt; object, so the dataset ID is &lt;code&gt;run.default_dataset_id&lt;/code&gt;, not &lt;code&gt;run["defaultDatasetId"]&lt;/code&gt;. It cuts every transcript into about 60 seconds of speech and keeps a link that opens the video at that second, so whatever answers your model gives can point back to the exact moment:&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;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&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="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;keywords&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;chatgpt tutorial for beginners&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;maxVideosPerKeyword&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;excludeShorts&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# max_total_charge_usd caps what this run can cost you (pay-per-event)
&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;vncntlabs/youtube-transcript-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="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_total_charge_usd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.05&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;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&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="n"&gt;default_dataset_id&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;transcript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;  &lt;span class="c1"&gt;# skips the keyword summary row and videos without captions
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;searchRank&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&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="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;channelName&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;): &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
          &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wordCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; words, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;videoDurationSeconds&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="mi"&gt;60&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; min&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# about 60 seconds of speech per chunk, with a link that opens the video there
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;seg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;segments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end&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="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;t=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&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;text&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;t=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&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;text&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&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;chunks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chunks ready to embed&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;chunks&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;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;chunks&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;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It printed the five videos and &lt;code&gt;164 chunks ready to embed&lt;/code&gt;. From there it's whatever embedding model and vector store you already use. A Node version of the same call is in the repo linked below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Videos without captions
&lt;/h2&gt;

&lt;p&gt;Some videos simply have no captions, and those get a row with &lt;code&gt;status: "no_captions"&lt;/code&gt; and &lt;code&gt;charged: false&lt;/code&gt;. In a bigger test last week I ran 6 searches with 15 videos each: 86 of 90 had transcripts (96%), and the 4 without were TV documentaries and full episodes. That batch took 93 seconds. The longest video in it was 13 hours and still came back whole, at about 163,000 words.&lt;/p&gt;

&lt;p&gt;The other public presets are a channel one (&lt;a href="https://apify.com/vncntlabs/youtube-transcript-scraper/examples/youtube-channel-transcripts?fpr=vccewy" rel="noopener noreferrer"&gt;the 5 newest long videos from @veritasium&lt;/a&gt;) and a &lt;a href="https://apify.com/vncntlabs/youtube-transcript-scraper/examples/youtube-spanish-subtitles?fpr=vccewy" rel="noopener noreferrer"&gt;Spanish caption track&lt;/a&gt; of the same Stanford speech. The keyword preset is the one I'd start with.&lt;/p&gt;

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

&lt;p&gt;$0.005 per transcript delivered, no start fee. Fast mode (a priority queue for big batches on a tight timeout) is $0.008. The keyword run was $0.025 and the Stanford speech was $0.005. On Apify's free plan a run stops at 10 transcripts. On paid plans it goes up to 1,000 per run, and the max charge you set always wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it compares with other Apify Actors
&lt;/h2&gt;

&lt;p&gt;I checked these on the Apify API today (October 27, 2026). Prices are per 1,000 transcripts on the free Apify plan unless noted.&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;Inputs&lt;/th&gt;
&lt;th&gt;Extras&lt;/th&gt;
&lt;th&gt;Price per 1,000&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/vncntlabs/youtube-transcript-scraper?fpr=vccewy" rel="noopener noreferrer"&gt;vncntlabs/youtube-transcript-scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Links, IDs, keyword search (Shorts filter), channels&lt;/td&gt;
&lt;td&gt;Segments, [mm:ss] text, status row per video, up to 1,000 per run&lt;/td&gt;
&lt;td&gt;$5 ($8 fast mode); no captions, not charged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;supreme_coder/youtube-transcript-scraper&lt;/td&gt;
&lt;td&gt;Links, channels, playlists, keyword search&lt;/td&gt;
&lt;td&gt;JSON, plain text, SRT, VTT; language fallback, translation&lt;/td&gt;
&lt;td&gt;$1 free plan, $0.70 Bronze and up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;johnvc/YoutubeTranscripts&lt;/td&gt;
&lt;td&gt;Links (up to 100 per run), channels&lt;/td&gt;
&lt;td&gt;SRT, VTT, translation, auto vs manual flag, free language check&lt;/td&gt;
&lt;td&gt;$2.75 free plan, $2 Gold and up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;starvibe/youtube-video-transcript&lt;/td&gt;
&lt;td&gt;One video, or one channel with a date range&lt;/td&gt;
&lt;td&gt;Likes, comments, subscriber count, auto-generated flag; free users 50 a day&lt;/td&gt;
&lt;td&gt;$5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pintostudio/youtube-transcript-scraper&lt;/td&gt;
&lt;td&gt;One video per run&lt;/td&gt;
&lt;td&gt;Timestamped segments in your language&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Where they're better, plainly. If price per video is all you care about, supreme_coder is 5 to 7 times cheaper than mine and also does playlists and SRT files. johnvc's is about half my price, tells you whether captions are auto-generated (mine doesn't), translates, and has thousands of users and a 4.78 rating. Mine has 2 users. starvibe's gives you likes and comment counts that mine doesn't.&lt;/p&gt;

&lt;p&gt;Where mine fits: keyword search with a Shorts filter and the search rank on every row, a ready-to-paste [mm:ss] text field, and a clear status row for every video, so you can see what was skipped and why. It reads transcripts through DataForSEO's YouTube API rather than scraping YouTube pages. I haven't tested the others on the same 90-video batch, so I'm not going to claim mine is more reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it from an assistant
&lt;/h2&gt;

&lt;p&gt;Add this to Claude, ChatGPT or Cursor as a remote MCP server. It loads only this Actor, and you sign in to Apify in the browser, so no token goes in the file:&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;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apify"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"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://mcp.apify.com/?tools=vncntlabs/youtube-transcript-scraper"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool shows up as &lt;code&gt;vncntlabs--youtube-transcript-scraper&lt;/code&gt;. Something like "get transcripts of the top 3 videos for 'sourdough starter', skip Shorts, and tell me where they disagree" works fine.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/PravinrajV/vncntlabs-apify-examples/tree/main/05-youtube-transcripts" rel="noopener noreferrer"&gt;https://github.com/PravinrajV/vncntlabs-apify-examples/tree/main/05-youtube-transcripts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're feeding transcripts into a RAG setup, I'm curious what chunk size you landed on. 60 seconds worked for tutorials, but I suspect it's too short for interviews where one answer runs three minutes.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;em&gt;Disclosure: I build the Apify Actor used here (VNCNT Labs). Every number in this post comes from a real run on Oct 27, 2026 (plus the 90-video batch noted above from Oct 23), and the prices are Apify Store list prices checked that day.&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>youtube</category>
      <category>python</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>Website traffic checker API: plausible.io's Google traffic, competitor keywords and backlinks for 10 cents</title>
      <dc:creator>VNCNT LABS</dc:creator>
      <pubDate>Fri, 23 Oct 2026 14:22:26 +0000</pubDate>
      <link>https://dev.to/vncntlabs/website-traffic-checker-api-plausibleios-google-traffic-competitor-keywords-and-backlinks-for-412j</link>
      <guid>https://dev.to/vncntlabs/website-traffic-checker-api-plausibleios-google-traffic-competitor-keywords-and-backlinks-for-412j</guid>
      <description>&lt;p&gt;This morning I wanted a quick answer to a simple question: how do the privacy-first analytics tools split Google search traffic between them? Plausible, Fathom, Simple Analytics. I didn't want to open a suite, export three CSVs and clean them up. I wanted one API call per question and rows I could drop into a script.&lt;/p&gt;

&lt;p&gt;So I ran my own Apify Actor, &lt;a href="https://apify.com/vncntlabs/domain-seo-data?fpr=vccewy" rel="noopener noreferrer"&gt;Domain SEO Data&lt;/a&gt;, on plausible.io. Below is what came back, what it cost, the code I used, and where other tools on the Apify Store are simply better.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(The Store links here carry my Apify affiliate ID, so Apify pays me a small commission if you sign up through one.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The run
&lt;/h2&gt;

&lt;p&gt;I started from the Actor's public "Website Traffic Checker" preset (overview plus backlink profile) and asked for 10 ranked keywords and 3 competitors on top:&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;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"report"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"domains"&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;"plausible.io"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"countries"&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;"US"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxKeywords"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxCompetitors"&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;"includeBacklinks"&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;It finished in about 6 seconds and returned 14 rows: one overview row, 10 keyword rows and 3 competitor rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What plausible.io looks like in US Google
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Estimated monthly organic visits (US)&lt;/td&gt;
&lt;td&gt;6,893&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ranking keywords (top 100)&lt;/td&gt;
&lt;td&gt;1,535&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Top 3 / top 10&lt;/td&gt;
&lt;td&gt;139 / 466&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Estimated traffic value per month&lt;/td&gt;
&lt;td&gt;$103,331&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keywords new / up / down / lost since the last update&lt;/td&gt;
&lt;td&gt;1,035 / 206 / 214 / 756&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paid search traffic&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain rank (0 to 100)&lt;/td&gt;
&lt;td&gt;73&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backlinks / referring domains&lt;/td&gt;
&lt;td&gt;637,979 / 16,940&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backlink spam score&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first thing that jumped out was how brand-heavy it is. The keyword "plausible" alone (60,500 searches a month, position 1) accounts for about 5,338 of those 6,893 estimated visits. That's 77%. For a company that writes a lot of content, I expected more of the traffic to come from the blog.&lt;/p&gt;

&lt;p&gt;The second thing was the backlink profile. About 206,000 of the 638,000 backlinks come from &lt;code&gt;.se&lt;/code&gt; domains. That smells like a handful of sitewide links (footer or "analytics by" badges) rather than 200,000 editorial mentions. Referring domains (16,940) is the number I'd trust here, not the raw backlink count.&lt;/p&gt;

&lt;p&gt;The traffic number is DataForSEO's click model for Google organic results. It is not total visits, and it won't match Plausible's own dashboard or Similarweb. I only compare domains inside one source.&lt;/p&gt;

&lt;h2&gt;
  
  
  The keywords it ranks for
&lt;/h2&gt;

&lt;p&gt;These came back sorted by estimated traffic, which is the default:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Keyword&lt;/th&gt;
&lt;th&gt;Position&lt;/th&gt;
&lt;th&gt;Monthly searches&lt;/th&gt;
&lt;th&gt;Ranking URL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;plausible&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;60,500&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;plausible analytics&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1,900&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;google analytics&lt;/td&gt;
&lt;td&gt;66&lt;/td&gt;
&lt;td&gt;450,000&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;plausible.io&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;170&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;plausible logo&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;210&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;what is plausible&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;720&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;free web analytics service&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;12,100&lt;/td&gt;
&lt;td&gt;/open-source-website-analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shopify analytics&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;1,600&lt;/td&gt;
&lt;td&gt;/blog/shopify-analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;plausible io&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;170&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;google analytics alternatives&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;720&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One row I don't fully believe: "google analytics" at position 66 gets credited with about 284 visits a month. That's the click model doing math on a 450,000-search keyword. Nobody clicks through to page 7 that often. If you're building a report for a client, I'd filter out anything below position 20 before summing traffic (the Actor has a &lt;code&gt;maxPosition&lt;/code&gt; input for exactly this).&lt;/p&gt;

&lt;p&gt;The useful find was "shopify analytics" at position 5 with a blog post. That's the kind of content keyword a competitor could go after, and it's the reason people search "competitor keywords" in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SEO competitors
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Competitor&lt;/th&gt;
&lt;th&gt;Shared keywords&lt;/th&gt;
&lt;th&gt;Share of plausible.io's keywords&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;semrush.com&lt;/td&gt;
&lt;td&gt;600&lt;/td&gt;
&lt;td&gt;39.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;backlinko.com&lt;/td&gt;
&lt;td&gt;489&lt;/td&gt;
&lt;td&gt;31.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hubspot.com&lt;/td&gt;
&lt;td&gt;485&lt;/td&gt;
&lt;td&gt;31.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Not Fathom. Not Matomo. Plausible's search competitors are SEO and marketing publishers, because so much of its non-brand content is about analytics and marketing topics. If you want product competitors, you have to name them yourself. That's what bulk mode is for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bulk mode: three analytics tools side by side
&lt;/h2&gt;

&lt;p&gt;Bulk mode returns one row per domain (traffic, keyword count, domain rank) and is meant for long lists. I ran it with three:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Domain&lt;/th&gt;
&lt;th&gt;Est. US organic visits&lt;/th&gt;
&lt;th&gt;Ranking keywords&lt;/th&gt;
&lt;th&gt;Domain rank&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;plausible.io&lt;/td&gt;
&lt;td&gt;6,893&lt;/td&gt;
&lt;td&gt;1,535&lt;/td&gt;
&lt;td&gt;73&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;usefathom.com&lt;/td&gt;
&lt;td&gt;1,883&lt;/td&gt;
&lt;td&gt;781&lt;/td&gt;
&lt;td&gt;73&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;simpleanalytics.com&lt;/td&gt;
&lt;td&gt;1,125&lt;/td&gt;
&lt;td&gt;4,261&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Simple Analytics ranks for almost three times as many keywords as Plausible but gets about a sixth of the estimated traffic. Lots of long-tail positions, not many clicks. That one table answered my original question better than an hour of clicking around would have.&lt;/p&gt;

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

&lt;p&gt;Prices come from the Actor's current pay-per-event pricing on the Store:&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;Count&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Run start&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;$0.005&lt;/td&gt;
&lt;td&gt;$0.005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain overview&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ranked keyword&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;td&gt;$0.010&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Competitor&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;$0.004&lt;/td&gt;
&lt;td&gt;$0.012&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backlink profile&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;$0.05&lt;/td&gt;
&lt;td&gt;$0.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.097&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The bulk run was $0.005 to start, $0.003 per domain and $0.05 per batch of up to 1,000 domains, so $0.064 for three. That batch fee makes bulk silly for three domains and cheap for 1,000 (about $3.06). Domains with no search data aren't charged in report mode.&lt;/p&gt;

&lt;p&gt;The public presets worth starting from are &lt;a href="https://apify.com/vncntlabs/domain-seo-data/examples/website-traffic-checker?fpr=vccewy" rel="noopener noreferrer"&gt;Website Traffic Checker&lt;/a&gt; (overview plus backlinks, about $0.075), &lt;a href="https://apify.com/vncntlabs/domain-seo-data/examples/find-seo-competitors?fpr=vccewy" rel="noopener noreferrer"&gt;Find a Website's SEO Competitors&lt;/a&gt; (25 competitors, up to $0.125) and the &lt;a href="https://apify.com/vncntlabs/domain-seo-data/examples/semrush-alternative-domain-overview?fpr=vccewy" rel="noopener noreferrer"&gt;Domain Overview Report&lt;/a&gt; (100 keywords, 10 competitors and backlinks, up to $0.215).&lt;/p&gt;

&lt;h2&gt;
  
  
  How it compares with other Apify Actors
&lt;/h2&gt;

&lt;p&gt;I checked these on the Apify API today (October 23, 2026). Prices are per 1,000 results on the free Apify plan unless noted.&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;Data source&lt;/th&gt;
&lt;th&gt;What it returns&lt;/th&gt;
&lt;th&gt;Price per 1,000&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apify.com/vncntlabs/domain-seo-data?fpr=vccewy" rel="noopener noreferrer"&gt;vncntlabs/domain-seo-data&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;DataForSEO API&lt;/td&gt;
&lt;td&gt;Google organic and paid estimates, ranked keywords, competitors, backlinks&lt;/td&gt;
&lt;td&gt;$20 overviews, $1 keywords, $4 competitors, $50 backlink profiles; bulk $3 per domain plus $0.05 per batch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tri_angle/fast-similarweb-scraper&lt;/td&gt;
&lt;td&gt;Similarweb&lt;/td&gt;
&lt;td&gt;Monthly visits, global and country rank, top countries, top keywords&lt;/td&gt;
&lt;td&gt;$2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tri_angle/similarweb-scraper&lt;/td&gt;
&lt;td&gt;Similarweb&lt;/td&gt;
&lt;td&gt;Total visits, traffic sources, competitors, top countries, company info&lt;/td&gt;
&lt;td&gt;$13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pro100chok/semrush-scraper&lt;/td&gt;
&lt;td&gt;Semrush and Moz&lt;/td&gt;
&lt;td&gt;Authority, traffic, backlinks, competitors&lt;/td&gt;
&lt;td&gt;$15 free plan, $5 Bronze, $4 Gold and up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;radeance/semrush-scraper&lt;/td&gt;
&lt;td&gt;Semrush&lt;/td&gt;
&lt;td&gt;Authority score, traffic, backlinks, competitors&lt;/td&gt;
&lt;td&gt;$25 free plan, $20 Silver, $17.50 Gold and up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;amassuo/semrush-competitor-keywords&lt;/td&gt;
&lt;td&gt;Not stated (the slug says Semrush)&lt;/td&gt;
&lt;td&gt;Ranked keywords and organic competitors&lt;/td&gt;
&lt;td&gt;$2 keywords, $2 competitors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Where they're better, plainly. If you want total visits from all channels (direct, social, referral), the Similarweb Actors give you that and mine doesn't. Mine only estimates Google search traffic. The fast Similarweb one is also cheaper per domain than my bulk mode, and it has far more users (2,159 versus my 1). The Semrush scrapers give you the Semrush numbers that clients and agencies already recognize. And amassuo's competitor rows cost half of mine.&lt;/p&gt;

&lt;p&gt;Where mine fits: keyword rows at $1 per 1,000 are the cheapest I found, the backlink profile comes in the same run, and it calls a licensed data API instead of reading another site's pages. One more honest limit: the numbers update on DataForSEO's schedule, not live. The backlinko.com competitor row today showed the exact same traffic (19,941) and keyword count (30,602) as a run I did on October 17, and the SERP dates on these keywords run from late July to mid September.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Python with &lt;code&gt;apify-client&lt;/code&gt; 3.x. In 3.x &lt;code&gt;call()&lt;/code&gt; returns a &lt;code&gt;Run&lt;/code&gt; object, so the dataset ID is &lt;code&gt;run.default_dataset_id&lt;/code&gt;, not &lt;code&gt;run["defaultDatasetId"]&lt;/code&gt;:&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;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&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="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;mode&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;report&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;domains&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;plausible.io&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;countries&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;US&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;maxKeywords&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;maxCompetitors&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;includeBacklinks&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# max_total_charge_usd caps what this run can cost you (pay-per-event)
&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;vncntlabs/domain-seo-data&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="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_total_charge_usd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.25&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="n"&gt;default_dataset_id&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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="k"&gt;if&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;type&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;domain&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;domain&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: ~&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;organicTraffic&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; organic visits/month, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
          &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;organicKeywords&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; keywords, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;top10&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; in the top 10&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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="k"&gt;if&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;type&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;keyword&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;position&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;keyword&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; vol &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;searchVolume&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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="k"&gt;if&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;type&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;competitor&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;competitor&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sharedKeywords&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; shared keywords (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sharedKeywordsPct&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running that printed &lt;code&gt;plausible.io: ~6,893 organic visits/month, 1,535 keywords, 466 in the top 10&lt;/code&gt; and the rows above.&lt;/p&gt;

&lt;p&gt;Bulk mode with curl, as one synchronous call that returns the dataset rows:&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;-sS&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/vncntlabs~domain-seo-data/run-sync-get-dataset-items?maxTotalChargeUsd=0.10"&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="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&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;'{"mode":"bulk","domains":["plausible.io","usefathom.com","simpleanalytics.com"],"countries":["US"],"includeAuthority":true}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you'd rather ask an assistant, add this to Claude, ChatGPT or Cursor as a remote MCP server. It loads only this Actor, and you sign in to Apify in the browser, so no token goes in the file:&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;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apify"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"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://mcp.apify.com/?tools=vncntlabs/domain-seo-data"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool shows up as &lt;code&gt;vncntlabs--domain-seo-data&lt;/code&gt;. Something like "check US organic traffic for these 40 agency domains in bulk mode and sort by traffic" works fine.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/PravinrajV/vncntlabs-apify-examples/tree/main/04-website-traffic-checker" rel="noopener noreferrer"&gt;https://github.com/PravinrajV/vncntlabs-apify-examples/tree/main/04-website-traffic-checker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've compared these traffic estimates against a site's real analytics, I'd like to hear how far off they were. My guess is brand-heavy sites come out closest, but I haven't tested that properly yet.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;em&gt;Disclosure: I build the Apify Actor used here (VNCNT Labs). Every number in this post comes from a real run on Oct 23, 2026, and the prices are Apify Store list prices checked that day.&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>api</category>
      <category>python</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Bulk Google + Amazon keyword search volume for about $3 per 1,000 keywords (API, n8n, Claude)</title>
      <dc:creator>VNCNT LABS</dc:creator>
      <pubDate>Sat, 17 Oct 2026 20:08:34 +0000</pubDate>
      <link>https://dev.to/vncntlabs/bulk-google-amazon-keyword-search-volume-for-about-3-per-1000-keywords-api-n8n-claude-f87</link>
      <guid>https://dev.to/vncntlabs/bulk-google-amazon-keyword-search-volume-for-about-3-per-1000-keywords-api-n8n-claude-f87</guid>
      <description>&lt;p&gt;If you've ever pasted 300 keywords into an SEO suite and hit a daily cap, or you just want search volume inside a script or an AI agent without paying for a seat, this is the setup I use: one API call in, one row per keyword out.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Google monthly search volume, with up to 4 years of monthly history&lt;/li&gt;
&lt;li&gt;CPC, competition, keyword difficulty and search intent&lt;/li&gt;
&lt;li&gt;Month-over-month, quarter-over-quarter and year-over-year trend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon&lt;/strong&gt; monthly search volume (a modeled estimate, because Amazon doesn't publish volumes)&lt;/li&gt;
&lt;li&gt;An optional USPTO trademark-risk flag, useful if you sell on Etsy, Merch by Amazon or KDP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The data comes from DataForSEO. Google figures come from its Google Ads-based keyword database (refreshed about monthly), so no Google Ads account is needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real run: 12 keywords, United States
&lt;/h2&gt;

&lt;p&gt;I mixed SEO-tool keywords with product keywords to show the range:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Keyword&lt;/th&gt;
&lt;th&gt;Google / month&lt;/th&gt;
&lt;th&gt;Amazon / month&lt;/th&gt;
&lt;th&gt;CPC&lt;/th&gt;
&lt;th&gt;KD&lt;/th&gt;
&lt;th&gt;YoY&lt;/th&gt;
&lt;th&gt;Trademark flag&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;google keyword planner&lt;/td&gt;
&lt;td&gt;49,500&lt;/td&gt;
&lt;td&gt;5,759&lt;/td&gt;
&lt;td&gt;$18.10&lt;/td&gt;
&lt;td&gt;47&lt;/td&gt;
&lt;td&gt;-18%&lt;/td&gt;
&lt;td&gt;high ("google")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;keyword research tool&lt;/td&gt;
&lt;td&gt;4,400&lt;/td&gt;
&lt;td&gt;299&lt;/td&gt;
&lt;td&gt;$15.75&lt;/td&gt;
&lt;td&gt;81&lt;/td&gt;
&lt;td&gt;-81%&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;etsy seo&lt;/td&gt;
&lt;td&gt;2,900&lt;/td&gt;
&lt;td&gt;224&lt;/td&gt;
&lt;td&gt;$7.69&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;-47%&lt;/td&gt;
&lt;td&gt;high ("etsy")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;long tail keywords&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;149&lt;/td&gt;
&lt;td&gt;$46.37&lt;/td&gt;
&lt;td&gt;61&lt;/td&gt;
&lt;td&gt;-70%&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;keyword search volume&lt;/td&gt;
&lt;td&gt;880&lt;/td&gt;
&lt;td&gt;74&lt;/td&gt;
&lt;td&gt;$12.61&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;td&gt;-55%&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;amazon keyword tool&lt;/td&gt;
&lt;td&gt;260&lt;/td&gt;
&lt;td&gt;74&lt;/td&gt;
&lt;td&gt;$12.83&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;-77%&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;coloring book for adults&lt;/td&gt;
&lt;td&gt;60,500&lt;/td&gt;
&lt;td&gt;1,907&lt;/td&gt;
&lt;td&gt;$0.61&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;-18%&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;teacher gift&lt;/td&gt;
&lt;td&gt;18,100&lt;/td&gt;
&lt;td&gt;1,645&lt;/td&gt;
&lt;td&gt;$0.88&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pickleball paddle&lt;/td&gt;
&lt;td&gt;301,000&lt;/td&gt;
&lt;td&gt;11,594&lt;/td&gt;
&lt;td&gt;$1.50&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;-45%&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three things stood out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Generic "keyword tool" searches are falling fast.&lt;/strong&gt; "keyword research tool" is down 81% year over year and "free keyword tool" is down 80%. My guess is that people now ask an AI assistant instead. That's also the best argument for piping keyword data &lt;em&gt;into&lt;/em&gt; those assistants (see below).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CPC and difficulty don't move together.&lt;/strong&gt; "long tail keywords" has a $46 CPC but KD 61. "amazon keyword tool" has a $12.83 CPC at KD 17, a much easier target.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The trademark flag isn't noise for sellers.&lt;/strong&gt; "etsy seo" and "google keyword planner" come back high-risk because of live marks. That's irrelevant for a blog post, but it matters if the phrase goes on a T-shirt. "pickleball paddle" is medium because live marks contain "pickleball". That doesn't mean you can't use it. It means you should check the record before printing it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Option 1: Python
&lt;/h2&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;YOUR_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;vncntlabs/keyword-search-volume&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;keywords&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;teacher gift&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;coloring book for adults&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;pickleball paddle&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;sources&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;google&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;amazon&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;United States&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;trademarkCheck&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="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&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="n"&gt;default_dataset_id&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="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keyword&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;googleSearchVolume&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazonSearchVolume&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpcUsd&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;h2&gt;
  
  
  Option 2: plain HTTP (n8n, Make, Zapier, curl)
&lt;/h2&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/vncntlabs~keyword-search-volume/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="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&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;'{"keywords":["teacher gift","pickleball paddle"],"sources":["google"],"location":"United States"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In n8n, that's one HTTP Request node, or the Apify node with "Run actor and get dataset".&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 3: from Claude, ChatGPT or Cursor (MCP)
&lt;/h2&gt;

&lt;p&gt;Apify runs a hosted MCP server. Add it to your client:&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;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"apify"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"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://mcp.apify.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then ask something like &lt;em&gt;"Get US Google and Amazon search volume for these 40 keywords and sort by volume per KD point."&lt;/em&gt; The assistant finds the Actor, runs it, and reads the dataset. You pay only for the rows returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&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;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Keyword with Google volume&lt;/td&gt;
&lt;td&gt;$0.003&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keyword with Amazon volume&lt;/td&gt;
&lt;td&gt;$0.004&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Batch fee (per up to 700 Google / 1,000 Amazon keywords that returned data)&lt;/td&gt;
&lt;td&gt;$0.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trademark check&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So &lt;strong&gt;1,000 Google-only keywords cost $3.10&lt;/strong&gt;, and keywords with no data aren't charged. The 12-keyword run above with Google, Amazon and trademark checks came to about $0.20 at list price. You can set a maximum charge per run, and the Actor stops before exceeding it. A new Apify account's free monthly credit covers a few hundred keywords.&lt;/p&gt;

&lt;p&gt;To be fair to the competition: if you only need Google numbers for very large lists, some Store Actors charge less per row (I keep a dated comparison on our site). Where this one is different is Amazon volume and the trademark flag in the same row.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Volumes are rounded monthly averages, so use them to compare keywords, not as exact traffic.&lt;/li&gt;
&lt;li&gt;Amazon volume is modeled, so treat it as relative.&lt;/li&gt;
&lt;li&gt;Trademark flags are automated screening against live U.S. federal marks only. They're not legal advice, and no flag doesn't mean safe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/PravinrajV/vncntlabs-apify-examples/tree/main/01-keyword-search-volume" rel="noopener noreferrer"&gt;https://github.com/PravinrajV/vncntlabs-apify-examples/tree/main/01-keyword-search-volume&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://apify.com/vncntlabs/keyword-search-volume" rel="noopener noreferrer"&gt;https://apify.com/vncntlabs/keyword-search-volume&lt;/a&gt;. Questions or missing features? Leave a comment. I read them all.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;&lt;em&gt;Disclosure: I build and sell the Apify Actor used in this post (VNCNT Labs). Every number in this post comes from a real run on October 17, 2026, and prices are the Apify Store list prices on that date.&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>api</category>
      <category>python</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
