<?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: ByteWright</title>
    <description>The latest articles on DEV Community by ByteWright (@byte_wright_59e59ada74a).</description>
    <link>https://dev.to/byte_wright_59e59ada74a</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%2F4203374%2F3ad72d86-5a18-44dd-8c70-62332ced8bbf.jpeg</url>
      <title>DEV Community: ByteWright</title>
      <link>https://dev.to/byte_wright_59e59ada74a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/byte_wright_59e59ada74a"/>
    <language>en</language>
    <item>
      <title>How to see your competitors' Google ads (and what 5 DTC brands are running right now)</title>
      <dc:creator>ByteWright</dc:creator>
      <pubDate>Sat, 24 Oct 2026 03:33:51 +0000</pubDate>
      <link>https://dev.to/byte_wright_59e59ada74a/how-to-see-your-competitors-google-ads-and-what-5-dtc-brands-are-running-right-now-19mc</link>
      <guid>https://dev.to/byte_wright_59e59ada74a/how-to-see-your-competitors-google-ads-and-what-5-dtc-brands-are-running-right-now-19mc</guid>
      <description>&lt;p&gt;Warby Parker's typical Google ad in the US has been running for about 594 days. Gymshark's has been running for 49. Of the last 60 US ads each brand showed, 28 of Gymshark's went live in the past month, against 6 of Warby Parker's.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg92b8oes7hufaka4z4eo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg92b8oes7hufaka4z4eo.png" alt="Format of the latest 60 US Google ads for Warby Parker, Allbirds, HelloFresh, Glossier and Gymshark, with median days live" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of that comes from a free Google page, the Ads Transparency Center. Below: how to read it for any competitor, two mistakes that make it misleading, and the numbers behind the chart.&lt;/p&gt;

&lt;h2&gt;
  
  
  The free way
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://adstransparency.google.com" rel="noopener noreferrer"&gt;adstransparency.google.com&lt;/a&gt;. No login.&lt;/li&gt;
&lt;li&gt;Type the competitor's &lt;strong&gt;website domain&lt;/strong&gt; (&lt;code&gt;warbyparker.com&lt;/code&gt;), not their brand name. More on why in a minute.&lt;/li&gt;
&lt;li&gt;Check the country next to the search box. It defaults to wherever you are, so switch it to the market you compete in.&lt;/li&gt;
&lt;li&gt;Filter by format if you only care about video or image ads.&lt;/li&gt;
&lt;li&gt;Click into an ad to see its preview, its variations and when it was last shown.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. You'll see Search, YouTube, Display and Shopping ads in one grid.&lt;/p&gt;

&lt;p&gt;What you won't see: spend, impressions, clicks or targeting. Google doesn't publish those for commercial ads, so spend figures can't come from this page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistake 1: searching the brand name
&lt;/h2&gt;

&lt;p&gt;I searched "HelloFresh" with the US selected. Every advertiser Google suggested was called HelloFresh SE and registered in Germany. The top three had 17 US ads between them, and only 8 of those had run in the past week.&lt;/p&gt;

&lt;p&gt;Then I searched &lt;code&gt;hellofresh.com&lt;/code&gt;. 57 of the first 60 ads came from an advertiser called &lt;strong&gt;Grocery Delivery E-Services USA Inc.&lt;/strong&gt;, all shown in the past 7 days. That's HelloFresh's US company, and the name search never surfaced it.&lt;/p&gt;

&lt;p&gt;Samsung is worse. The top three suggestions for "Samsung" are accounts registered in Malaysia, Italy and Saudi Arabia: 13 US ads, none shown in the past week. &lt;code&gt;samsung.com&lt;/code&gt; returns Google's estimate of about 10,000 US ads, and 35 of the first 40 came from "Samsung Electronics America". Most of the rest were agencies (Cheil Colombia, Channel Factory).&lt;/p&gt;

&lt;p&gt;Big companies advertise under legal entity names and per-country accounts. A domain search finds the advertisers promoting the website, whatever their accounts are called.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistake 2: treating every ad as current
&lt;/h2&gt;

&lt;p&gt;The grid mixes ads that ran for one day with ads that have run for years. Google records two dates for every ad (depending on your region, the ad page shows one or both; the export further down always has both):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First shown&lt;/strong&gt; tells you when they launched it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Last shown&lt;/strong&gt; tells you if it's still live.&lt;/li&gt;
&lt;li&gt;The gap between them tells you how long they've kept paying for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An ad that's still running after a year is one nobody has bothered to switch off. That doesn't prove it converts, but it's a much better shortlist than "the ads that showed up first in the grid".&lt;/p&gt;

&lt;h2&gt;
  
  
  What the 5 brands are doing
&lt;/h2&gt;

&lt;p&gt;I pulled the first 60 US ads Google lists for each domain on 2026-10-24. All 300 had been shown in the past 7 days, so this is what's live, not their history.&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;Google's estimate of US ads&lt;/th&gt;
&lt;th&gt;Median days live&lt;/th&gt;
&lt;th&gt;Live 1 year+&lt;/th&gt;
&lt;th&gt;New in last 30 days&lt;/th&gt;
&lt;th&gt;Formats (text / image / video)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Warby Parker&lt;/td&gt;
&lt;td&gt;~4,000&lt;/td&gt;
&lt;td&gt;594&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;55 / 3 / 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allbirds&lt;/td&gt;
&lt;td&gt;~900&lt;/td&gt;
&lt;td&gt;226&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;25 / 30 / 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HelloFresh&lt;/td&gt;
&lt;td&gt;~800&lt;/td&gt;
&lt;td&gt;177&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;52 / 8 / 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Glossier&lt;/td&gt;
&lt;td&gt;~700&lt;/td&gt;
&lt;td&gt;142&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;36 / 5 / 19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gymshark&lt;/td&gt;
&lt;td&gt;~2,000&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;27 / 10 / 23&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Out of 60 ads each. What I'd take from it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Warby Parker is running a search machine.&lt;/strong&gt; 55 of 60 are text ads, and over half have run for more than a year. 6 of them have a first-shown date of 2021-10-25, the same date as Gymshark's oldest ad. That looks like the earliest date the Transparency Center reports, so some of these ads are probably older.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gymshark tests constantly.&lt;/strong&gt; Almost half of its live ads launched in the past month, 6 of them in the past week, and video is 23 of 60. If you sell into the same audience, this is the account to check weekly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Glossier sits in between:&lt;/strong&gt; a core of long-running ads (26 over a year old) plus a steady flow of new video.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Allbirds leans on image ads&lt;/strong&gt; (30 of 60), the only brand of the five where images outnumber text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HelloFresh ran no video&lt;/strong&gt; in this sample.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more thing showed up in the Gymshark results: 2 of the 60 ads came from advertisers that aren't Gymshark's own accounts. A domain search includes every advertiser promoting the site, resellers and agencies too. If it's your own brand, that's a quick way to see who else is advertising it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting it into a spreadsheet
&lt;/h2&gt;

&lt;p&gt;The Transparency Center has no export. For one competitor and a quick look, scrolling is fine. For a weekly check on five competitors, or a pitch deck for a client, copying dates off ad pages gets old fast.&lt;/p&gt;

&lt;p&gt;Disclosure: I built a tool for this. &lt;a href="https://apify.com/datasmithhq/google-ads-transparency-scraper" rel="noopener noreferrer"&gt;Google Ads Transparency Scraper&lt;/a&gt; on Apify takes a list of domains, advertiser names or advertiser IDs and exports every ad with its format, first and last shown dates, preview image and a link back to Google's page, as CSV, Excel or JSON. It costs $0.002 per ad, so the latest 100 ads of one competitor are $0.20, and searches that find nothing aren't charged. In my test run it pulled 312 ads from 4 searches in about 30 seconds.&lt;/p&gt;

&lt;p&gt;The table above took one run with five domains, country set to US and 60 ads per domain.&lt;/p&gt;

&lt;p&gt;I'll re-run the same five brands in December to see how many of Gymshark's 28 new ads are still alive.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;An AI assistant helped me draft this article. I checked every number against the raw data myself; it was fetched from Google's Ads Transparency Center on 2026-10-24.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>ecommerce</category>
      <category>seo</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to compare more than 5 keywords in Google Trends (and why "swift" beat "python")</title>
      <dc:creator>ByteWright</dc:creator>
      <pubDate>Fri, 23 Oct 2026 20:34:29 +0000</pubDate>
      <link>https://dev.to/byte_wright_59e59ada74a/how-to-compare-more-than-5-keywords-in-google-trends-and-why-swift-beat-python-57ld</link>
      <guid>https://dev.to/byte_wright_59e59ada74a/how-to-compare-more-than-5-keywords-in-google-trends-and-why-swift-beat-python-57ld</guid>
      <description>&lt;p&gt;The cover chart shows 12 search terms on one Google Trends scale, US, past 12 months. You can't get that chart from Google directly. The compare box stops at 5 terms, and each comparison is rescaled so its own top value is 100.&lt;/p&gt;

&lt;p&gt;Before the method, the surprise in the data: "swift" almost ties "python". That's not the programming language pulling ahead. The plain word "swift" also counts searches for Taylor Swift and the Suzuki Swift car. I'll come back to that, because it's the mistake that ruins most keyword comparisons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why you can't just run more comparisons
&lt;/h2&gt;

&lt;p&gt;I asked Google Trends about "rust" twice, same day, same country, same 12 months. Next to "python" it averaged 30.1. Next to "dart" it averaged 41.6.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F436ylrebmr1xjkuqs0tm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F436ylrebmr1xjkuqs0tm.png" alt="Average interest in " width="800" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same searches, different numbers, because each request sets its own top value to 100. So you can't put the results of two separate comparisons in one spreadsheet column and sort them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: an anchor keyword
&lt;/h2&gt;

&lt;p&gt;Put the same keyword, the anchor, in every batch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;batch 1: anchor + 4 keywords&lt;/li&gt;
&lt;li&gt;batch 2: anchor + the next 4&lt;/li&gt;
&lt;li&gt;and so on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The anchor's real search volume is the same in every batch; only its scale changes. That gives you one conversion factor per batch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;factor = sum of anchor values in batch 1 / sum of anchor values in this batch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiply every keyword in a batch by its factor, and everything is on batch 1's scale. Then divide by the overall maximum and multiply by 100, so the top value is 100 again.&lt;/p&gt;

&lt;p&gt;For the chart above I used "java" as the anchor: 11 other terms, 3 batches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking the anchor
&lt;/h2&gt;

&lt;p&gt;Google returns whole numbers. If the anchor is tiny next to the biggest keyword in its batch, its values round to 0, 1 or 2 and the factor gets noisy. Pick an anchor that's clearly visible in every batch. "java" averaged 14.9 on the final scale here, well above the rounding floor. Use the same country, time range and category in every batch, or the numbers aren't comparable.&lt;/p&gt;

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

&lt;p&gt;This uses &lt;a href="https://github.com/GeneralMills/pytrends" rel="noopener noreferrer"&gt;pytrends&lt;/a&gt;, an unofficial Google Trends client:&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;random&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pytrends.request&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TrendReq&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeframe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;today 12-m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;geo&lt;/span&gt;&lt;span class="o"&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="n"&gt;pytrends&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TrendReq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;en-US&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tz&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pytrends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build_payload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeframe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;timeframe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;geo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pytrends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;interest_over_time&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;isPartial&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ignore&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Put every batch on batch 1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s scale using the anchor, then rescale to a peak of 100.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;ref_total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;batches&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="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;batches&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="nf"&gt;copy&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;batch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;batches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
        &lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref_total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&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;column&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;java&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;others&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;python&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;javascript&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;typescript&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;golang&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;rust&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;kotlin&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;swift&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;ruby&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;php&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;scala&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;dart&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;batches&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;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;others&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;batches&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="nf"&gt;fetch_batch&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;others&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]]))&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Google rate-limits fast; see below
&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stitch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;anchor&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ascending&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check it, compare any 4 or 5 of your keywords in one direct request and line up the averages with the stitched ones. When I did that with "java", "python", "rust" and "golang", the stitched averages matched within 0.04. The largest gap was on "golang", the smallest term.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things that bite
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Search terms aren't topics.&lt;/strong&gt; "swift" counts searches for Taylor Swift, "rust" includes the video game, "python" the snake, "dart" the pub game. Google's topic IDs fix this: &lt;code&gt;pytrends.suggestions('Taylor Swift')&lt;/code&gt; returns entries with an &lt;code&gt;mid&lt;/code&gt; (&lt;code&gt;/m/0dl567&lt;/code&gt; for Taylor Swift) that you can pass to &lt;code&gt;build_payload&lt;/code&gt; instead of a word. In one request, the Taylor Swift topic averaged 24.2 next to 28.9 for the plain word "swift". Topic lookup is hit-and-miss for programming languages, though: searching suggestions for the Swift language mostly returned books. Often it's easier to qualify the term ("swift programming") and check what you're actually measuring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rate limits.&lt;/strong&gt; In my testing Google started answering HTTP 429 after 3 or 4 quick requests from one IP. The 5 requests behind this article went through with 4–7 second pauses. For 50 keywords (13 batches) you'll want retries with growing waits, and probably more than one IP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tiny values.&lt;/strong&gt; "kotlin" ends at 0.8 on this scale. That's correct relative to the others, but at that size the values are coarse. If small terms matter most to you, put them in a separate comparison with a smaller anchor.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you'd rather not run it yourself
&lt;/h2&gt;

&lt;p&gt;Disclosure: I built a hosted version of this method, &lt;a href="https://apify.com/datasmithhq/google-trends-scraper" rel="noopener noreferrer"&gt;Google Trends Scraper&lt;/a&gt; on Apify. It takes any number of keywords, does the batching, anchoring and retries, flags rows where the anchor was too weak, and exports JSON, CSV or Excel. It costs $3 per 1,000 results.&lt;/p&gt;

&lt;p&gt;For a few dozen keywords and a bit of patience, the script above does the same job for free.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I wrote this with help from an AI assistant and checked every claim and code sample myself. The data was fetched on 2026-10-23.&lt;/em&gt;&lt;/p&gt;

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