<?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: Matthew Curtis</title>
    <description>The latest articles on DEV Community by Matthew Curtis (@mdcurt).</description>
    <link>https://dev.to/mdcurt</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%2F4233959%2F896424d1-f1d0-4082-976c-9fbf5c2d28b8.png</url>
      <title>DEV Community: Matthew Curtis</title>
      <link>https://dev.to/mdcurt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mdcurt"/>
    <language>en</language>
    <item>
      <title>OpenAI has 34 open "Forward Deployed" jobs. Palantir has 70.</title>
      <dc:creator>Matthew Curtis</dc:creator>
      <pubDate>Tue, 10 Nov 2026 03:35:54 +0000</pubDate>
      <link>https://dev.to/mdcurt/openai-has-34-open-forward-deployed-jobs-palantir-has-70-32ld</link>
      <guid>https://dev.to/mdcurt/openai-has-34-open-forward-deployed-jobs-palantir-has-70-32ld</guid>
      <description>&lt;p&gt;OpenAI has 34 open jobs with "Forward Deployed" in the title. Twenty-five of them were posted since August 1, and seven went up on November 5 and 6. They're spread over 14 cities, and most of them sit in a department called Forward Deployed Engineering, which has 37 openings.&lt;/p&gt;

&lt;p&gt;Palantir has 70, and its oldest open posting is a Forward Deployed Software Engineer listing dated December 2009. Cursor has 8, Anthropic has 8 and Adobe has 6. Of the ten companies I checked on November 8, only Ubisoft had none.&lt;/p&gt;

&lt;p&gt;I didn't get this from a jobs site. Most company career pages run on an applicant-tracking system, and five of the common ones (Greenhouse, Lever, Ashby, Workday, SmartRecruiters) serve the whole board as public JSON. It's the same endpoint the careers page calls. The data is sitting there, but nobody opens ten of those every Monday and compares them with last week.&lt;/p&gt;

&lt;p&gt;So I pulled all ten in one run with &lt;a href="https://apify.com/mdcurt/ats-job-board-scraper" rel="noopener noreferrer"&gt;ATS Job Board Scraper&lt;/a&gt;, an Apify Actor I wrote. The run made 19 requests, took 65 seconds and cost $1.63. It returned 1,356 open roles matching "engineer", and no request failed. Every number below is from that run.&lt;/p&gt;

&lt;p&gt;If you sell to engineering teams and read a new role as a sign of budget, or you're job hunting and want to hear about a role the day it opens, or you use open roles as a headcount proxy, put your own companies in the input and you'll get the same tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  The input
&lt;/h2&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="nl"&gt;"boards"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"https://boards.greenhouse.io/anthropic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://boards.greenhouse.io/stripe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://boards.greenhouse.io/figma"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://boards.greenhouse.io/coinbase"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://jobs.lever.co/palantir"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://jobs.ashbyhq.com/openai"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://jobs.ashbyhq.com/ramp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://jobs.ashbyhq.com/cursor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://adobe.wd5.myworkdayjobs.com/external_experienced"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://jobs.smartrecruiters.com/Ubisoft2"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"engineer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each URL is the "View all jobs" link from that company's careers page. The Actor works out which system it's looking at from the host name, so there's nothing else to configure. These ten cover all five systems.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;query&lt;/code&gt; keeps a role when every word in it appears in the title, department, team, location or employment type. That's looser than it sounds: 67 of the 1,356 have no "engineer" in the title and matched on a department or team name. Leave &lt;code&gt;query&lt;/code&gt; empty to track every open role.&lt;/p&gt;

&lt;p&gt;The 19 requests break down like this. A Greenhouse, Lever or Ashby board arrives whole in one request, and there are eight of those. Ubisoft's SmartRecruiters board took one page. Workday pages by 20 and is searched on the server first, so Adobe took ten.&lt;/p&gt;

&lt;p&gt;Pricing is $0.005 to start a run plus $0.0012 per record, so 1,356 records is $1.63. One board of 50 roles is about $0.065. There's no login or API key involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is hiring
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Employer&lt;/th&gt;
&lt;th&gt;Roles matching "engineer"&lt;/th&gt;
&lt;th&gt;New since Nov 1&lt;/th&gt;
&lt;th&gt;"Forward Deployed" in title&lt;/th&gt;
&lt;th&gt;Pay band published&lt;/th&gt;
&lt;th&gt;Median band midpoint (USD)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;396&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;21&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;34&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;td&gt;$347,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;260&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;95%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$402,500&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stripe&lt;/td&gt;
&lt;td&gt;190&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;16&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Palantir&lt;/td&gt;
&lt;td&gt;185&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coinbase&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;99%&lt;/td&gt;
&lt;td&gt;$208,125&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adobe&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;46&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Figma&lt;/td&gt;
&lt;td&gt;41&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;93%&lt;/td&gt;
&lt;td&gt;$264,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ramp&lt;/td&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;$255,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ubisoft&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;OpenAI and Anthropic have 656 of these roles between them. The other eight companies have 700.&lt;/p&gt;

&lt;p&gt;The "new" column is the one I'd watch. Seventy-one roles were posted between November 2 and November 8: 11, 10, 12, 18 and 18 on the weekdays, then one on Saturday and one on Sunday. Stripe posted 16, which is 8% of its open engineering roles in a single week, and three of those are the same Staff Security Engineer, Abuse Control listing. Cursor posted none. OpenAI posted 21, and a third of them were in Forward Deployed Engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to "Forward Deployed"
&lt;/h2&gt;

&lt;p&gt;The phrase is in 134 of the 1,356 titles. Palantir accounts for 70, which is 38% of its engineering roles. Thirty-five of those have "Government" in the title and 31 are new-grad or internship postings.&lt;/p&gt;

&lt;p&gt;The other 64 are spread over eight companies. Sixty-two of them carry a posted date, and 47 of those dates fall after August 1.&lt;/p&gt;

&lt;p&gt;OpenAI's 34 split two ways. Some are by city, with listings for Tokyo, Seoul, Singapore, Sydney, Abu Dhabi, London, Madrid, Munich, Zurich and Paris. The US ones are split by industry: healthcare, legal, financial services, cyber and life sciences. Fourteen share one pay band, $185K to $300K, which sits well under the $347,500 midpoint of OpenAI's engineering bands overall.&lt;/p&gt;

&lt;p&gt;Cursor's eight were all posted since June 22, and three of them are Regional Director roles. Four of Anthropic's eight are manager roles. Coinbase has a Forward Deployed Engineer for its own finance department and a Forward Deployed Engineer Intern in HR Technology. I'm not sure where those two get deployed to.&lt;/p&gt;

&lt;p&gt;My reading, which one snapshot can't prove, is that the title is moving from Palantir into companies that sell AI to large customers. A weekly count of title words would settle it, and that's cheap to set up.&lt;/p&gt;

&lt;p&gt;One caution about dates. The posted date means different things on different systems, and a re-posted evergreen listing looks new. I trust a week-over-week diff more than a date, and the monitor further down is built on one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the pay bands say
&lt;/h2&gt;

&lt;p&gt;Whether a company publishes pay depends on how its board is configured. Five of these ten publish a band on 82% to 100% of their roles, and all five are on Greenhouse or Ashby. Stripe (Greenhouse) and Cursor (Ashby) have the field switched off. Palantir on Lever, Adobe on Workday and Ubisoft on SmartRecruiters show none.&lt;/p&gt;

&lt;p&gt;Among the ones that publish, Anthropic's bands sit highest. The median midpoint is $402,500 against $347,500 at OpenAI. At Anthropic, 123 of 221 bands have a midpoint of $400K or more. At OpenAI it's 43 of 319. The most common band is $405K to $485K at Anthropic (45 roles) and $266K to $445K at OpenAI (43 roles). Both top out at $850K, on 28 Anthropic roles and 3 OpenAI roles.&lt;/p&gt;

&lt;p&gt;I wouldn't lean on those midpoints. These are posted base-pay bands, some of them are very wide (one Anthropic band runs from $280K to $850K), and OpenAI's listings add "Offers Equity" without a number. A midpoint tells you how a company frames a role in public. It doesn't tell you what anyone was offered.&lt;/p&gt;

&lt;p&gt;The medians cover annual bands in US dollars only. I left out bands in pounds, euros, rupees and other currencies. I also left out intern postings, which put a monthly rate or what looks like an hourly one in the same fields (Ramp's say $12.5K per month). And I dropped two bands that are typos on the company's own board: one Anthropic posting lists $1 to $2, and one Coinbase posting tops out at $179,300,152.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning it into a Monday digest
&lt;/h2&gt;

&lt;p&gt;I don't want to rerun this and compare tables by hand, so I schedule it through &lt;a href="https://apify.com/mdcurt/dataset-diff-monitor" rel="noopener noreferrer"&gt;Dataset Diff Monitor&lt;/a&gt;, another Actor of mine. It runs the scraper, compares the new dataset with last week's by &lt;code&gt;id&lt;/code&gt;, and posts one message listing what was added and what was removed.&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="nl"&gt;"sourceActorId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"mdcurt/ats-job-board-scraper"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"sourceInput"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"boards"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"…the ten URLs above…"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"engineer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"keyFields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"ignoreFields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"scrapedAt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"updatedAt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"postedAt"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"notifyOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"added"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"removed"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"firstRunBehavior"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"snapshot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Engineering hiring at 10 target employers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"labelField"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"urlField"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"slackWebhookUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"https://hooks.slack.com/services/XXX/YYY/ZZZ"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Schedule it for Monday at 07:00 (cron &lt;code&gt;0 7 * * 1&lt;/code&gt;). The first run stores a baseline and stays quiet. From the second run on you get the roles each company opened and closed that week, with titles and links.&lt;/p&gt;

&lt;p&gt;Two choices in there need explaining. &lt;code&gt;id&lt;/code&gt; is the key because it's built from the system, the board and the job number, so it stays the same from run to run. The four ignored fields change on every run or whenever someone edits a posting, and I only care about roles appearing and disappearing.&lt;/p&gt;

&lt;p&gt;On cost: the scraper is $1.63. The monitor adds $0.02 to start, $0.001 per row it compares and $0.01 per notification, which is $1.39 for 1,356 rows. Together that's about $3.02 a week for ten employers. Discord, Telegram and plain webhooks work in place of Slack.&lt;/p&gt;

&lt;p&gt;To pay less, narrow &lt;code&gt;query&lt;/code&gt;, or run the scraper on its own every day with the previous run's ids in &lt;code&gt;knownIds&lt;/code&gt;. It skips those, so a daily run only pays for new postings.&lt;/p&gt;

&lt;p&gt;A few other ways to point it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For sales signals, set &lt;code&gt;notifyOn&lt;/code&gt; to &lt;code&gt;["added"]&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt; to the function you sell to, such as &lt;code&gt;"data"&lt;/code&gt;, &lt;code&gt;"security"&lt;/code&gt; or &lt;code&gt;"platform"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For a job search, set &lt;code&gt;location&lt;/code&gt; to a city such as &lt;code&gt;"London"&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt; to &lt;code&gt;"senior engineer"&lt;/code&gt;, and run it daily.&lt;/li&gt;
&lt;li&gt;For a headcount proxy, leave &lt;code&gt;query&lt;/code&gt; empty, raise &lt;code&gt;maxItems&lt;/code&gt; to 10000 and track added minus removed per employer each week.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Calling it from an agent
&lt;/h2&gt;

&lt;p&gt;Pass one job URL as the only board and you get one request and one record back for $0.0062. The Actor works through Apify's MCP server at &lt;code&gt;https://mcp.apify.com/?tools=mdcurt/ats-job-board-scraper&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fine print
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It reads career pages hosted on Greenhouse, Lever, Ashby, Workday or SmartRecruiters. Paste the hosted URL, since a custom domain like careers.example.com won't be recognised. Taleo, iCIMS, SuccessFactors and Workable aren't covered.&lt;/li&gt;
&lt;li&gt;The five endpoints are the public job-board APIs that the career pages call themselves. There's no login and no CAPTCHA. The Actor returns a description snippet of up to 300 characters and a link to the posting. It doesn't copy full postings or collect contact details.&lt;/li&gt;
&lt;li&gt;Greenhouse, Lever and Ashby return the whole board in one request. Workday and SmartRecruiters are paged through to the last page. Version 1.0.1 fixed a bug that stopped Workday boards at 40 jobs, which I found while writing this post.&lt;/li&gt;
&lt;li&gt;Lever's &lt;code&gt;postedAt&lt;/code&gt; is the date the listing was created, so evergreen listings look ancient. Palantir's oldest says 2009.&lt;/li&gt;
&lt;li&gt;Adobe's Workday list gave a posted date for 38 of its 78 roles, so its "new" count is a floor.&lt;/li&gt;
&lt;li&gt;Greenhouse departments are whatever the company typed in. Stripe's are cost-centre codes such as "5112 General University".&lt;/li&gt;
&lt;li&gt;The "Forward Deployed" counts are titles that contain the phrase, counted once per role.&lt;/li&gt;
&lt;li&gt;"Pay band published" counts a band in any currency. The medians use 319 bands for OpenAI, 221 for Anthropic, 71 for Coinbase, 33 for Figma and 35 for Ramp.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;salaryMin&lt;/code&gt; and &lt;code&gt;salaryMax&lt;/code&gt; are only filled when the band is in the posting.&lt;/li&gt;
&lt;li&gt;The 1,356 records and the exact input are in the Actor's source under &lt;code&gt;examples/hiring-monitor-target-employers/&lt;/code&gt;. The same input is saved as the example task "Monitor engineering hiring at 10 target employers" on the Actor's Example tasks tab.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run this on your own list and see a title spreading the way this one has, leave a comment. I'd like to know which one.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>career</category>
      <category>sales</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Babbel has a 4.5 on Google Play. Its last 20 German reviews average 1.9.</title>
      <dc:creator>Matthew Curtis</dc:creator>
      <pubDate>Tue, 10 Nov 2026 03:04:13 +0000</pubDate>
      <link>https://dev.to/mdcurt/babbel-has-a-45-on-google-play-its-last-20-german-reviews-average-19-4m6a</link>
      <guid>https://dev.to/mdcurt/babbel-has-a-45-on-google-play-its-last-20-german-reviews-average-19-4m6a</guid>
      <description>&lt;p&gt;Babbel's rating in the German Play Store is 4.48. On November 9 I pulled its 20 most recent German reviews and they averaged 1.9 stars. Fifteen of the twenty were one or two stars. Babbel's support team had replied to eighteen of them.&lt;/p&gt;

&lt;p&gt;None of that is hidden. It sits on public Play Store pages, next to where the app ranks in the grossing chart, when it last shipped and what it's rated in every other country. The catch is that nobody is going to click through twelve store pages every morning to read it.&lt;/p&gt;

&lt;p&gt;So this post does it in one run. I'm using &lt;a href="https://apify.com/mdcurt/google-play-app-scraper" rel="noopener noreferrer"&gt;Google Play Store Scraper&lt;/a&gt;, an Apify Actor I wrote, to watch four language-learning apps (Duolingo, Babbel, Busuu, Memrise) in the US, German and Brazilian stores. The run made 75 requests, took 32 seconds and cost $0.08. It came back with 72 app records, 1,440 reviews and 362 chart positions, and nothing failed. Every number below is from that run.&lt;/p&gt;

&lt;p&gt;If you do product or ASO work and have a competitive set to watch, or you're picking which country to launch in next, or you use chart rank as a stand-in for revenue, swap your own apps into the input and you'll get the same tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  The input
&lt;/h2&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="nl"&gt;"queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"com.duolingo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"com.babbel.mobile.android.en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"com.busuu.android.enc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"com.memrise.android.memrisecompanion"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"chart:GROSSING:EDUCATION"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"locales"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"en-US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"de-DE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"pt-BR"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"reviewsPerApp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Package ids are the &lt;code&gt;id=&lt;/code&gt; part of a Play Store URL. Each query runs once per store front, so the four apps come to 12 records. I capped the run at 72, which leaves 60 for the chart: the top 20 of Top Grossing › Education in each country, with full details.&lt;/p&gt;

&lt;p&gt;The chart query takes any collection and category (&lt;code&gt;chart:TOP_FREE:FINANCE&lt;/code&gt;, &lt;code&gt;chart:GROSSING:GAME_PUZZLE&lt;/code&gt;, and so on). A plain keyword like &lt;code&gt;"language learning"&lt;/code&gt; works too and ranks apps by search position instead of chart position. Google shows about 25–30 results per term when you aren't signed in.&lt;/p&gt;

&lt;p&gt;Pricing is $0.005 to start a run plus $0.001 per record, so 72 records is $0.077. Reviews come inside the app record and aren't charged. There's no Google account or API key involved anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where everyone ranks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;App&lt;/th&gt;
&lt;th&gt;US grossing rank (Education)&lt;/th&gt;
&lt;th&gt;Germany&lt;/th&gt;
&lt;th&gt;Brazil&lt;/th&gt;
&lt;th&gt;US rating&lt;/th&gt;
&lt;th&gt;DE rating&lt;/th&gt;
&lt;th&gt;BR rating&lt;/th&gt;
&lt;th&gt;Last update&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Duolingo&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.75&lt;/td&gt;
&lt;td&gt;4.65&lt;/td&gt;
&lt;td&gt;4.86&lt;/td&gt;
&lt;td&gt;2026-11-09&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Babbel&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;4.57&lt;/td&gt;
&lt;td&gt;4.48&lt;/td&gt;
&lt;td&gt;4.80&lt;/td&gt;
&lt;td&gt;2026-11-05 (v22.22.0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Busuu&lt;/td&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;4.65&lt;/td&gt;
&lt;td&gt;4.58&lt;/td&gt;
&lt;td&gt;4.82&lt;/td&gt;
&lt;td&gt;2026-11-03 (v32.51.1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memrise&lt;/td&gt;
&lt;td&gt;109&lt;/td&gt;
&lt;td&gt;not in the 73&lt;/td&gt;
&lt;td&gt;not in the 89&lt;/td&gt;
&lt;td&gt;4.40&lt;/td&gt;
&lt;td&gt;4.19&lt;/td&gt;
&lt;td&gt;4.74&lt;/td&gt;
&lt;td&gt;2026-10-19&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Duolingo is first in all three countries, which nobody needed a scraper to guess. The other rows say more. Babbel is #2 at home in Germany and #17 in Brazil. Busuu is #39 in the US but #8 in Germany and #15 in Brazil, so most of its money is coming from outside the US. Memrise is #109 in the US and isn't on the German or Brazilian chart at all.&lt;/p&gt;

&lt;p&gt;About that #109. The dataset only holds full records for the top 20 per country, but the run also saves a &lt;code&gt;RANKINGS&lt;/code&gt; record to the key-value store with every position Google publishes. On the day of this run that was 200 in the US, 73 in Germany and 89 in Brazil. That's how an app sitting at #39 or #109 still gets a rank without you paying for 200 detail records.&lt;/p&gt;

&lt;p&gt;One more thing in that table: all four apps have their highest rating in Brazil and their lowest in Germany. Ratings are per country (the rating count is global), so if you only ever check your home store you're looking at one score out of several.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the newest reviews say
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;App&lt;/th&gt;
&lt;th&gt;Store&lt;/th&gt;
&lt;th&gt;Avg stars, newest 20&lt;/th&gt;
&lt;th&gt;1–2★ of 20&lt;/th&gt;
&lt;th&gt;Developer replies of 20&lt;/th&gt;
&lt;th&gt;Period covered&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Duolingo&lt;/td&gt;
&lt;td&gt;US&lt;/td&gt;
&lt;td&gt;4.40&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duolingo&lt;/td&gt;
&lt;td&gt;DE&lt;/td&gt;
&lt;td&gt;3.90&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duolingo&lt;/td&gt;
&lt;td&gt;BR&lt;/td&gt;
&lt;td&gt;4.85&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Babbel&lt;/td&gt;
&lt;td&gt;US&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.45&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;18&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Babbel&lt;/td&gt;
&lt;td&gt;DE&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.90&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;18&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Babbel&lt;/td&gt;
&lt;td&gt;BR&lt;/td&gt;
&lt;td&gt;2.85&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;12 weeks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Busuu&lt;/td&gt;
&lt;td&gt;US&lt;/td&gt;
&lt;td&gt;4.30&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Busuu&lt;/td&gt;
&lt;td&gt;DE&lt;/td&gt;
&lt;td&gt;3.55&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;17 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Busuu&lt;/td&gt;
&lt;td&gt;BR&lt;/td&gt;
&lt;td&gt;3.90&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memrise&lt;/td&gt;
&lt;td&gt;US&lt;/td&gt;
&lt;td&gt;3.20&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3 weeks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memrise&lt;/td&gt;
&lt;td&gt;DE&lt;/td&gt;
&lt;td&gt;3.50&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memrise&lt;/td&gt;
&lt;td&gt;BR&lt;/td&gt;
&lt;td&gt;3.60&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2 months&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Back to Babbel. Its newest reviews average between 1.9 and 2.9 stars depending on the country, against lifetime ratings of 4.5 to 4.8. And somebody at Babbel answers nearly all of them: 18 of 20 in the US and in Germany, 15 of 20 in Brazil. Duolingo and Busuu answered none of their 60. If you compete with Babbel, those replies are a free look at how their support team handles complaints.&lt;/p&gt;

&lt;p&gt;Before anyone reads too much into this: twenty reviews is a small sample, and people who bother to write a review skew unhappy. I treat it as a tripwire. When an app trips it, raise &lt;code&gt;reviewsPerApp&lt;/code&gt; for that app (it goes up to 200 and still costs nothing extra) and read properly.&lt;/p&gt;

&lt;p&gt;The last column is worth a look too. It's how long each app took to collect those 20 reviews, which makes it a rough gauge of review volume. Duolingo fills the list in a day in every country. Memrise needs four months in Germany.&lt;/p&gt;

&lt;p&gt;Each review comes with &lt;code&gt;score&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt; (cut at 300 characters), &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;appVersion&lt;/code&gt;, &lt;code&gt;thumbsUp&lt;/code&gt;, &lt;code&gt;replyText&lt;/code&gt; and &lt;code&gt;replyDate&lt;/code&gt;. Since the app version is on every review, "what have people complained about since 22.22.0" is a one-line filter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is actually on the chart
&lt;/h2&gt;

&lt;p&gt;Six apps make the Education grossing top 20 in all three countries: Duolingo, Learna AI, PictureThis, Babbel, Simply Piano and Simply Draw.&lt;/p&gt;

&lt;p&gt;Everything else is local. The US list has ClassDojo, Reading.com, Epic and Lingvano (sign language). Germany has phase6, sofatutor and NeuroNation. Brazil has four exam-prep apps (Qconcursos, Tec Concursos, Gran Cursos Questões, Passei Direto) plus 12min. None of those show up anywhere on the other two countries' charts.&lt;/p&gt;

&lt;p&gt;Then there are the AI English tutors. Praktika and Loora hold #5–#6 in Germany and #3–#4 in Brazil, and neither is in the US top 20. That's no surprise for apps that teach English, but it does mean a language app in Berlin or São Paulo is up against two competitors that never appear if you only watch the US chart.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chart-top20-by-country.csv&lt;/code&gt; in the sample data has the three lists side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning it into an alert
&lt;/h2&gt;

&lt;p&gt;I don't want to rerun this by hand and compare tables, so I schedule it through &lt;a href="https://apify.com/mdcurt/dataset-diff-monitor" rel="noopener noreferrer"&gt;Dataset Diff &amp;amp; Alert Monitor&lt;/a&gt;, another Actor of mine. It runs the scraper, compares the result with the previous run and posts only what changed to Slack, Discord, Telegram or a webhook.&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="nl"&gt;"sourceActorId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"mdcurt/google-play-app-scraper"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"sourceInput"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;"queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"com.duolingo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"com.babbel.mobile.android.en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"com.busuu.android.enc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"com.memrise.android.memrisecompanion"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;"locales"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"en-US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"de-DE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"pt-BR"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"keyFields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"watchFields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"scoreText"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"inAppPurchaseRange"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"notifyOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"changed"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"labelField"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"urlField"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"slackWebhookUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"https://hooks.slack.com/services/…"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This config is a release-and-pricing watch. You get one message when an app ships a new version, when its displayed rating moves a step (4.6 to 4.5), when the in-app price range changes or when the listing gets renamed.&lt;/p&gt;

&lt;p&gt;Two choices in there aren't obvious. &lt;code&gt;url&lt;/code&gt; is the key because it's unique per app and store front. And the watch is on &lt;code&gt;scoreText&lt;/code&gt;, not &lt;code&gt;score&lt;/code&gt;, because the raw average shifts in the fifth decimal place on every run and you'd be pinged every time.&lt;/p&gt;

&lt;p&gt;On cost: twelve records are $0.017 on the scraper. The monitor adds $0.02 to start, $0.001 per row it compares and $0.01 per notification it sends. A check where nothing changed comes to about $0.05.&lt;/p&gt;

&lt;p&gt;Rank changes take one more step. Schedule the full input from the top of this post weekly and compare the &lt;code&gt;RANKINGS&lt;/code&gt; record from two runs. &lt;code&gt;lists[].items[]&lt;/code&gt; is &lt;code&gt;{rank, id, title}&lt;/code&gt;, so spotting a newcomer in the top 20, or your own app slipping, is about ten lines of script. Or one prompt, if you'd rather hand it to an agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calling it from an agent
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;{"queries": ["com.duolingo"], "maxItems": 1}&lt;/code&gt; returns one record in about a second for $0.006. Add &lt;code&gt;"reviewsPerApp": 20&lt;/code&gt; and the newest reviews come back in the same record at no extra charge. For a ranked list with no detail requests, use &lt;code&gt;"queries": ["chart:GROSSING:EDUCATION"], "fetchDetails": false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Actor needs no login and runs with limited permissions, so it works through Apify's MCP server at &lt;code&gt;https://mcp.apify.com/?tools=mdcurt/google-play-app-scraper&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fine print
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Chart positions are Google's public Top Grossing list for that store front at the moment of the run. They move daily.&lt;/li&gt;
&lt;li&gt;A chart goes as deep as Google publishes, which tops out at 200 positions and is often less (73 in Germany and 89 in Brazil here).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ratingsCount&lt;/code&gt; is the global count. &lt;code&gt;score&lt;/code&gt; and the reviews belong to the store front.&lt;/li&gt;
&lt;li&gt;You can list as many store fronts in &lt;code&gt;locales&lt;/code&gt; as you like. Each app-and-country pair is one $0.001 record.&lt;/li&gt;
&lt;li&gt;Review text is cut at 300 characters, and &lt;code&gt;textTruncated&lt;/code&gt; tells you when that happened. Reviewer display names are in the Actor's output, but I removed them from the sample file.&lt;/li&gt;
&lt;li&gt;This covers Google Play only. It doesn't touch the App Store.&lt;/li&gt;
&lt;li&gt;The sample was collected from Google's public pages without a login: 75 requests, none failed, none blocked.&lt;/li&gt;
&lt;li&gt;The 72 records, the full rank map and the two CSVs behind the tables are in the Actor's source under &lt;code&gt;examples/competitor-app-watch/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run this on your own category and something odd turns up, leave a comment. I'd like to see it.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>mobile</category>
      <category>marketing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Track Competitors on Google Trends Automatically (No Browser, $0.035 a Run)</title>
      <dc:creator>Matthew Curtis</dc:creator>
      <pubDate>Sun, 08 Nov 2026 19:01:29 +0000</pubDate>
      <link>https://dev.to/mdcurt/how-to-track-competitors-on-google-trends-automatically-no-browser-0035-a-run-3jjb</link>
      <guid>https://dev.to/mdcurt/how-to-track-competitors-on-google-trends-automatically-no-browser-0035-a-run-3jjb</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — Google Trends has no official API, and browser-based scrapers fail half the time. This tutorial shows how to get competitor search-interest data (12-month trend, US state ranking, rising and &lt;em&gt;Breakout&lt;/em&gt; queries) for five brands in one 21-second run costing $0.035, and how to turn it into a weekly Slack alert for about $0.07 a week. Every number below comes from a real run on 2026-11-08.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who this is for:&lt;/strong&gt; SEO and content teams, brand and category managers, market researchers, and anyone building an AI agent that needs a quick "is this brand trending?" answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why automate Google Trends competitor analysis?
&lt;/h2&gt;

&lt;p&gt;Google Trends is the cheapest competitive-intelligence source there is. It tells you when demand for a competitor peaks, where in the country they are strongest, and which new product names people have started searching for — weeks before that shows up in sales data.&lt;/p&gt;

&lt;p&gt;The problem is getting the data out. There is no official Google Trends API, the unofficial Python libraries break every few months, and browser-based scrapers are slow and get rate-limited. The approach here calls the same JSON endpoints the Trends website uses, so a brand's full series arrives in about two seconds and the run pays per record.&lt;/p&gt;

&lt;p&gt;We'll use five US running-shoe brands as the example — &lt;strong&gt;Hoka, Brooks, ASICS, New Balance and On&lt;/strong&gt; — but the input works for any category: SaaS tools, car models, skincare lines, podcast names.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Set up the Google Trends scraper input
&lt;/h2&gt;

&lt;p&gt;Open &lt;a href="https://apify.com/mdcurt/google-trends-scraper" rel="noopener noreferrer"&gt;Google Trends Scraper on Apify&lt;/a&gt; (free account, no credit card for the first runs), switch the input to the JSON tab and paste:&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="nl"&gt;"keywords"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"hoka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"brooks running"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"asics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"new balance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"on running"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"geo"&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="nl"&gt;"timeRange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"today 12-m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"datasets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"interestOverTime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"interestByRegion"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"relatedQueries"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three tips before you press Start:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Type brand names the way searchers do&lt;/strong&gt; — &lt;code&gt;brooks running&lt;/code&gt;, not &lt;code&gt;Brooks Running Company&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch common-word brands.&lt;/strong&gt; &lt;code&gt;on running&lt;/code&gt; is also plain English; the related-queries list will show you how much noise that adds (see Step 3).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick the right time range.&lt;/strong&gt; &lt;code&gt;today 12-m&lt;/code&gt; gives weekly points for a year; &lt;code&gt;today 3-m&lt;/code&gt; gives daily points and is the better choice for monitoring (Step 4).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Prefer code? The same input works via the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl -X POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/mdcurt~google-trends-scraper/runs?token=$APIFY_TOKEN"&lt;/span&gt; \
  -H &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; -d @input.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Run it (21 seconds, $0.035)
&lt;/h2&gt;

&lt;p&gt;The run returns 15 records: for each of the 5 brands one &lt;code&gt;interestOverTime&lt;/code&gt; record, one &lt;code&gt;interestByRegion&lt;/code&gt; record and one &lt;code&gt;relatedQueries&lt;/code&gt; record. In the sample run: 20/20 requests OK, 0 rate limits, 0 blocked pages, first record after 7 s, 19 compute-seconds on a 256 MB run. Price: 15 records × $0.002 + $0.005 start = &lt;strong&gt;$0.035&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can download the result as JSON, CSV or Excel from the run's Dataset tab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Read the competitor data (real numbers, 2026-11-08)
&lt;/h2&gt;

&lt;p&gt;One rule first: &lt;strong&gt;Google Trends values are relative.&lt;/strong&gt; Each keyword is indexed on its own, so 100 means &lt;em&gt;that brand's own busiest week in the period&lt;/em&gt;. Compare shapes and ratios within a brand, not bar heights across brands.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Brand&lt;/th&gt;
&lt;th&gt;12-month average&lt;/th&gt;
&lt;th&gt;Peak week&lt;/th&gt;
&lt;th&gt;Latest (week of 2026-11-08)&lt;/th&gt;
&lt;th&gt;Latest ÷ average&lt;/th&gt;
&lt;th&gt;Top-3 states after Wyoming*&lt;/th&gt;
&lt;th&gt;Rising queries flagged &lt;strong&gt;Breakout&lt;/strong&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;on running&lt;/td&gt;
&lt;td&gt;69.6&lt;/td&gt;
&lt;td&gt;2026-04-12&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;0.86&lt;/td&gt;
&lt;td&gt;Kansas 41, Oklahoma 37, Alabama 35&lt;/td&gt;
&lt;td&gt;1 of 22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;asics&lt;/td&gt;
&lt;td&gt;48.9&lt;/td&gt;
&lt;td&gt;2026-04-12&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;0.82&lt;/td&gt;
&lt;td&gt;Delaware 28, DC 27, New York 26&lt;/td&gt;
&lt;td&gt;2 of 25 (&lt;code&gt;asics men's gel-nimbus 28&lt;/code&gt;, &lt;code&gt;asics hypersync&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hoka&lt;/td&gt;
&lt;td&gt;47.7&lt;/td&gt;
&lt;td&gt;2026-04-12&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;0.69&lt;/td&gt;
&lt;td&gt;Hawaii 35, California 31, Alabama 28&lt;/td&gt;
&lt;td&gt;0 of 25 (top riser &lt;code&gt;hoka cielo x1 3.0&lt;/code&gt;, +3,900 %)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;new balance&lt;/td&gt;
&lt;td&gt;46.2&lt;/td&gt;
&lt;td&gt;2026-04-12&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;0.74&lt;/td&gt;
&lt;td&gt;Massachusetts 23, DC 22, California 21&lt;/td&gt;
&lt;td&gt;3 of 24 (&lt;code&gt;new balance men's 1080v15&lt;/code&gt;, &lt;code&gt;women's 1080v15&lt;/code&gt;, &lt;code&gt;fresh foam x more v6&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;brooks running&lt;/td&gt;
&lt;td&gt;25.2&lt;/td&gt;
&lt;td&gt;2026-04-12&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0.48&lt;/td&gt;
&lt;td&gt;Washington 18, DC 17, Nebraska 17&lt;/td&gt;
&lt;td&gt;2 of 4 (&lt;code&gt;brooks adrenaline gts 25&lt;/code&gt;, &lt;code&gt;brooks women's adrenaline gts 25 running shoes&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What this table tells a category manager in one minute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Seasonality is shared.&lt;/strong&gt; All five brands peaked in the same week (2026-04-12, spring-marathon season) and all five are below their yearly average in November. &lt;strong&gt;Latest ÷ average&lt;/strong&gt; is the fair momentum metric when every series has its own 100.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who is holding up.&lt;/strong&gt; On keeps 86 % of its average going into winter; Brooks is at 48 %. Part of Brooks' drop is the query itself — people search &lt;code&gt;brooks shoes&lt;/code&gt; more than &lt;code&gt;brooks running&lt;/code&gt; (the &lt;code&gt;top[]&lt;/code&gt; list shows this), so add both spellings next week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product launches appear as Breakouts first.&lt;/strong&gt; &lt;code&gt;new balance 1080v15&lt;/code&gt;, &lt;code&gt;asics gel-nimbus 28&lt;/code&gt; and &lt;code&gt;brooks adrenaline gts 25&lt;/code&gt; are all current-season models. A &lt;em&gt;Breakout&lt;/em&gt; means the query grew more than 5,000 % — it is the field worth an alert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check for noise.&lt;/strong&gt; On's rising list includes &lt;code&gt;ps5 games running on xbox hardware&lt;/code&gt;. For common-word brands pass a Google topic id instead of free text (the &lt;code&gt;keywords&lt;/code&gt; field accepts &lt;code&gt;/m/…&lt;/code&gt; ids) or set &lt;code&gt;category: 20&lt;/code&gt; (Sports).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;* &lt;strong&gt;Why does Wyoming score 100 for every brand?&lt;/strong&gt; It is a Google Trends sampling artefact in very low-population states — a handful of searches moves the index. It happens for many consumer terms. Drop Wyoming when ranking states, and read Alaska, Vermont and DC with the same caution.&lt;/p&gt;

&lt;h3&gt;
  
  
  What a record looks like
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;interestOverTime&lt;/code&gt;, one per brand:&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="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"interestOverTime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"keyword"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"hoka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"geo"&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="nl"&gt;"timeRange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"today 12-m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"resolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"WEEK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"pointCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"average"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;47.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"peak"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"2026-04-12T00:00:00.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"latest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"2026-11-08T00:00:00.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"isPartial"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"points"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"2025-11-02T00:00:00.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"isPartial"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"… 53 more"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"https://trends.google.com/trends/explore?q=hoka&amp;amp;geo=US&amp;amp;date=today+12-m"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;relatedQueries&lt;/code&gt; carries &lt;code&gt;top[]&lt;/code&gt; and &lt;code&gt;rising[]&lt;/code&gt;, each &lt;code&gt;{ query, value, formattedValue, isBreakout, url }&lt;/code&gt;. &lt;code&gt;interestByRegion&lt;/code&gt; carries &lt;code&gt;regions[]&lt;/code&gt; of &lt;code&gt;{ geoCode, name, value }&lt;/code&gt; sorted by value, plus &lt;code&gt;topRegion&lt;/code&gt; and &lt;code&gt;regionCount&lt;/code&gt; (51 for the US).&lt;/p&gt;

&lt;p&gt;Record &lt;code&gt;id&lt;/code&gt;s are stable per keyword × location × time range × category, so the same brand has the same id every week. That is what makes the next step work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Get a weekly Google Trends alert in Slack
&lt;/h2&gt;

&lt;p&gt;Schedule &lt;strong&gt;the monitor, not the scraper.&lt;/strong&gt; &lt;a href="https://apify.com/mdcurt/dataset-diff-monitor" rel="noopener noreferrer"&gt;Dataset Diff Monitor&lt;/a&gt; runs the Trends scraper for you, compares the new dataset with last week's snapshot by &lt;code&gt;id&lt;/code&gt;, and sends one digest to Slack, Discord, Telegram or a webhook (n8n, Make, Zapier).&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="nl"&gt;"sourceActorId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"mdcurt/google-trends-scraper"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"sourceInput"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;"keywords"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"hoka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"brooks running"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"asics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"new balance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"on running"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;"geo"&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="nl"&gt;"timeRange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"today 3-m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;"datasets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"interestOverTime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"relatedQueries"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"keyFields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"watchFields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"rising"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"ignoreFields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"scrapedAt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"points"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"top"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"notifyOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"changed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"added"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"firstRunBehavior"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"snapshot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Running-shoe brands – Google Trends weekly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"labelField"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"keyword"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"urlField"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"slackWebhookUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"https://hooks.slack.com/services/…"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How it behaves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;today 3-m&lt;/code&gt; gives &lt;strong&gt;daily&lt;/strong&gt; points, so &lt;code&gt;latest&lt;/code&gt; changes every week (the 12-month series only has a partial last week).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;watchFields: ["latest", "rising"]&lt;/code&gt; means a brand is reported only when its latest value or its rising-queries list changed. New Breakout model names land in Slack the week they appear; &lt;code&gt;points&lt;/code&gt; and &lt;code&gt;top&lt;/code&gt; churn slightly every run and are ignored.&lt;/li&gt;
&lt;li&gt;The first run stores the baseline silently. From the second run on you get a digest listing each changed brand with a link to its Trends page, and every change is also written to a dataset you can chart.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost per weekly run ≈ $0.07&lt;/strong&gt; (10 source records $0.025 + monitor start $0.02 + 10 rows compared $0.01 + one message $0.01). Under $4 a year.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create the schedule in Apify Console → Schedules, cron &lt;code&gt;0 7 * * 1&lt;/code&gt; (Monday 07:00), pointing at Dataset Diff Monitor with the input above.&lt;/p&gt;

&lt;h2&gt;
  
  
  More ways to use the same setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Several countries:&lt;/strong&gt; one monitor per &lt;code&gt;geo&lt;/code&gt; (&lt;code&gt;US&lt;/code&gt;, &lt;code&gt;GB&lt;/code&gt;, &lt;code&gt;DE&lt;/code&gt;, &lt;code&gt;JP&lt;/code&gt;) — Trends indexes each country separately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trending-now watch:&lt;/strong&gt; &lt;code&gt;datasets: ["trendingNow"]&lt;/code&gt;, hourly schedule, &lt;code&gt;notifyOn: ["added"]&lt;/code&gt; → an alert when a new search enters a country's Trending-now feed (≈ $0.08 per hourly run including the monitor).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-campaign analysis:&lt;/strong&gt; a custom range such as &lt;code&gt;"2026-03-01 2026-04-30"&lt;/code&gt; with &lt;code&gt;relatedQueries&lt;/code&gt; shows which queries a campaign lifted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI agents:&lt;/strong&gt; pass &lt;code&gt;{"keywords": ["&amp;lt;brand&amp;gt;"], "geo": "US"}&lt;/code&gt; and read &lt;code&gt;latest.value&lt;/code&gt;, &lt;code&gt;average&lt;/code&gt;, &lt;code&gt;peak.date&lt;/code&gt; and &lt;code&gt;rising[]&lt;/code&gt; from the three records that return in 2–3 seconds; one brand costs about $0.011. MCP endpoint: &lt;code&gt;https://mcp.apify.com/?tools=mdcurt/google-trends-scraper&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Is there an official Google Trends API?&lt;/strong&gt;&lt;br&gt;
No. Google offers Trends only as a website and a daily RSS feed. Tools either drive a browser or call the site's internal JSON endpoints; this scraper does the latter, which is why it needs no browser and finishes in seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I compare brands on one scale?&lt;/strong&gt;&lt;br&gt;
Not in this version — each keyword is fetched on its own, so each has its own 100. Use &lt;em&gt;Latest ÷ average&lt;/em&gt; for cross-brand momentum, or run the five-term comparison once a quarter in the Trends UI for the level set. Multi-keyword comparison on one scale is on the roadmap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does one state show 100 for every keyword?&lt;/strong&gt;&lt;br&gt;
Sampling: in states with few searches a handful of queries moves the index to 100. Wyoming is the usual culprit for US data. Exclude it when ranking regions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does "Breakout" mean in Google Trends?&lt;/strong&gt;&lt;br&gt;
A related query whose search volume grew more than 5,000 % versus the previous period — usually a new product name, a news event or a viral term. The scraper flags it as &lt;code&gt;isBreakout: true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will Google block this?&lt;/strong&gt;&lt;br&gt;
Google rate-limits rather than blocks: the scraper paces requests, pauses and retries on HTTP 429 (never counted as a failure), and drops any challenge page instead of working around it. A 70-keyword run passed 280/280 requests with datacenter proxies; residential proxies are not needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does it cost at scale?&lt;/strong&gt;&lt;br&gt;
$0.005 per run plus $0.002 per record (a record is a whole series or table, not a data point). 100 keywords × 3 datasets ≈ $0.61. Store discounts apply on paid Apify plans.&lt;/p&gt;




&lt;p&gt;The full 15-record sample dataset, the input and the run's SUMMARY ship in the Actor source under &lt;code&gt;examples/competitor-search-interest-monitor/&lt;/code&gt;, and the input is one click away as the example task &lt;strong&gt;"Monitor competitor brands' Google search interest by US state"&lt;/strong&gt; on the &lt;a href="https://apify.com/mdcurt/google-trends-scraper" rel="noopener noreferrer"&gt;Actor page&lt;/a&gt;. Feature requests — comparison on one scale, YouTube/News/Shopping properties — are welcome in the Actor's Issues tab.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>seo</category>
      <category>tutorial</category>
      <category>datascience</category>
    </item>
  </channel>
</rss>
