<?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: LMSlay</title>
    <description>The latest articles on DEV Community by LMSlay (@lmslay).</description>
    <link>https://dev.to/lmslay</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%2F4170335%2F07eedcc6-0bda-40fc-82f5-fc8060bbde36.png</url>
      <title>DEV Community: LMSlay</title>
      <link>https://dev.to/lmslay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lmslay"/>
    <language>en</language>
    <item>
      <title>Instagram Reels to text in bulk (no login): transcripts, hooks and on-screen text</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Fri, 09 Oct 2026 06:47:44 +0000</pubDate>
      <link>https://dev.to/lmslay/instagram-reels-to-text-in-bulk-no-login-transcripts-hooks-and-on-screen-text-n2d</link>
      <guid>https://dev.to/lmslay/instagram-reels-to-text-in-bulk-no-login-transcripts-hooks-and-on-screen-text-n2d</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build the Apify Actor used in this post (TubeText Labs).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Instagram doesn't give you transcripts for Reels, and copying captions misses what people actually &lt;em&gt;say&lt;/em&gt;. If you research hooks, repurpose content, or feed creators' videos into an LLM, you want the spoken words as text – for many reels at once. Here's a way to do it without logging in.&lt;/p&gt;

&lt;h2&gt;
  
  
  A creator's latest reels → text
&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/tubetext~instagram-reels-transcript/run-sync-get-dataset-items?timeout=300"&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;'{"urls": ["@natgeo"], "maxReelsPerProfile": 10}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can mix &lt;code&gt;@usernames&lt;/code&gt;, profile links and single reel links in the same list.&lt;/p&gt;

&lt;p&gt;Each row has the transcript (plain, timestamped, or SRT), the opening &lt;code&gt;hook&lt;/code&gt; line, the caption, plays, likes and posting time. The speech is transcribed with Whisper, so it handles 90+ languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that save you money
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Music-only reels and songs are free.&lt;/strong&gt; A reel that's only a song comes back as &lt;code&gt;no_speech&lt;/code&gt; or &lt;code&gt;lyrics&lt;/code&gt; (with the song text) and isn't charged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only new reels.&lt;/strong&gt; Turn on &lt;em&gt;Only new reels&lt;/em&gt; and schedule the run daily: each run transcribes just what the creator posted since last time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional on-screen text.&lt;/strong&gt; Many reels put the message in captions on screen, not in the audio. &lt;code&gt;includeOnScreenText&lt;/code&gt; reads those overlays with a vision model (+$0.002 per reel, only when text is found) – useful for recipe and listicle reels with no speech at all.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;About 15 reels per minute with default settings, $0.006 per reel (the first 3 minutes of audio are included; almost every reel is shorter). Private, deleted and failed reels are free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ideas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build a swipe file of the opening hooks of the 50 latest reels in your niche.&lt;/li&gt;
&lt;li&gt;Turn a coach's reels into a searchable knowledge base for an AI assistant.&lt;/li&gt;
&lt;li&gt;Track competitors daily with &lt;em&gt;Only new reels&lt;/em&gt; and send new transcripts to Slack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Actor: &lt;a href="https://apify.com/tubetext/instagram-reels-transcript" rel="noopener noreferrer"&gt;https://apify.com/tubetext/instagram-reels-transcript&lt;/a&gt;&lt;/p&gt;

</description>
      <category>instagram</category>
      <category>ai</category>
      <category>api</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Google Hotels prices per booking site (and a 90-day price calendar) as JSON</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Fri, 09 Oct 2026 03:51:29 +0000</pubDate>
      <link>https://dev.to/lmslay/google-hotels-prices-per-booking-site-and-a-90-day-price-calendar-as-json-3b8a</link>
      <guid>https://dev.to/lmslay/google-hotels-prices-per-booking-site-and-a-90-day-price-calendar-as-json-3b8a</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build the Apify Actor used in this post (TubeText Labs).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Google Hotels shows, for every hotel, what each booking site charges for your dates – Booking.com, Expedia, Hotels.com, the hotel's own site and many smaller agencies. There is no public API for those prices (Google's Hotel Prices API is for partners sending prices &lt;em&gt;in&lt;/em&gt;, not for reading them). Here's how to get them as JSON, plus a 90-day price calendar for a single hotel.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Every hotel in a city, with prices per booking site
&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/tubetext~google-hotels-scraper/run-sync-get-dataset-items?timeout=300"&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;'{"locations": ["Lisbon"], "checkInDate": "2026-11-20", "checkOutDate": "2026-11-22",
       "currency": "USD", "maxHotelsPerLocation": 20, "includeBookingOffers": true}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each hotel comes back with its rating, star class, location and the lowest price. With &lt;code&gt;includeBookingOffers&lt;/code&gt; it also gets a &lt;code&gt;bookingOffers&lt;/code&gt; list – vendor, nightly and total price, room types, whether it's the official site and whether it's an ad – cheapest first, plus &lt;code&gt;cheapestVendor&lt;/code&gt;. In our Lisbon test each hotel had between 9 and 28 booking sites, and for one of them the cheapest offer came from a small agency rather than a big OTA.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. When is this hotel cheapest? A price calendar
&lt;/h2&gt;

&lt;p&gt;Take any hotel's &lt;code&gt;googleHotelsUrl&lt;/code&gt; from step 1 and ask for a calendar:&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;"calendarHotelUrls"&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;"https://www.google.com/travel/hotels/entity/…"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checkInDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-11-20"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"calendarDays"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"calendarNights"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&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;You get one row per check-in date with &lt;code&gt;lowestPricePerNight&lt;/code&gt;, &lt;code&gt;lowestVendor&lt;/code&gt; and all vendor prices. Dates with no rates come back as &lt;code&gt;no_rates&lt;/code&gt; and aren't charged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things to know
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prices are what Google shows US visitors, taxes and fees included (&lt;code&gt;priceIncludesTaxesAndFees&lt;/code&gt; tells you per row). Visitors from other countries can see different rates.&lt;/li&gt;
&lt;li&gt;Google returns at most about 420 hotels per search. For more, split a city into neighbourhoods.&lt;/li&gt;
&lt;li&gt;Price monitoring is just a schedule: run the same hotels and dates daily and compare &lt;code&gt;pricePerNight&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;$3 per 1,000 hotels with a price, +$2 per 1,000 for the booking-site breakdown, and $3 per 1,000 priced calendar dates. Sold-out hotels, no-rate dates and failed searches are free. A 30-day calendar for 5 hotels is at most 150 dates, about $0.45.&lt;/p&gt;

&lt;p&gt;Actor: &lt;a href="https://apify.com/tubetext/google-hotels-scraper" rel="noopener noreferrer"&gt;https://apify.com/tubetext/google-hotels-scraper&lt;/a&gt;&lt;/p&gt;

</description>
      <category>travel</category>
      <category>api</category>
      <category>python</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>How to get TikTok Shop product data (price, sales, stock per SKU) as JSON in 2026</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Fri, 09 Oct 2026 03:41:28 +0000</pubDate>
      <link>https://dev.to/lmslay/how-to-get-tiktok-shop-product-data-price-sales-stock-per-sku-as-json-in-2026-52aa</link>
      <guid>https://dev.to/lmslay/how-to-get-tiktok-shop-product-data-price-sales-stock-per-sku-as-json-in-2026-52aa</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build the Apify Actor used in this post (TubeText Labs).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;TikTok Shop has no public API for product data. Most "TikTok Shop spy" dashboards build on the same public product-page numbers: the price, the "sold" count and the shop stats. If you only need that data for your own research, a dashboard subscription is overkill. Here's how to get it as JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can get from a public TikTok Shop product page
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;price, original price and discount&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;items sold&lt;/strong&gt; (TikTok's "sold since listing" counter)&lt;/li&gt;
&lt;li&gt;rating and review count&lt;/li&gt;
&lt;li&gt;every variant (SKU) with its own price and &lt;strong&gt;stock&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;specifications, shipping, delivery estimate&lt;/li&gt;
&lt;li&gt;the shop's stats: rating, followers, products, total sold, number of videos&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One API call
&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/tubetext~tiktok-shop-product-scraper/run-sync-get-dataset-items?timeout=300"&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;'{"urls": ["https://www.tiktok.com/shop/pdp/1729527313880355335"]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also pass a &lt;strong&gt;store page&lt;/strong&gt; (you get its first 20 products) or a &lt;strong&gt;category page&lt;/strong&gt; (a sample of up to 100 products).&lt;/p&gt;

&lt;h2&gt;
  
  
  Real output (shortened)
&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="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Goli Ashwagandha &amp;amp; Vitamin D Gummy - Mixed Berry…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;19.47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"originalPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;24.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"soldCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1304190&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.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;"reviewCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;94525&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"skus"&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="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Size: 1 Bottle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;19.47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"stock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;336485&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"shopFollowers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;601031&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"shopSoldCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5777630&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Turning it into "daily sales"
&lt;/h2&gt;

&lt;p&gt;TikTok only shows a running total, so daily sales are the difference between two snapshots:&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="c1"&gt;# yesterday.json and today.json are two runs over the same product URLs
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;productId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yesterday.json&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;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;today.json&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;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;productId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;y&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;p&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="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;soldCount&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;y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;productId&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;soldCount&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;sold in 24h&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;Schedule the run daily on Apify (or from n8n/Make), and you have a small competitor tracker. Per-SKU &lt;code&gt;stock&lt;/code&gt; tells you which variant is actually moving.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits (so you don't waste time)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;US TikTok Shop only for now.&lt;/li&gt;
&lt;li&gt;No keyword search yet: use product, store or category links.&lt;/li&gt;
&lt;li&gt;Store pages return their first 20 products.&lt;/li&gt;
&lt;li&gt;"Sold" is TikTok's displayed counter, not audited sales.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pricing is $4 per 1,000 products with full details ($1.50 per 1,000 if you only need listing cards), and failures are free.&lt;/p&gt;

&lt;p&gt;Actor: &lt;a href="https://apify.com/tubetext/tiktok-shop-product-scraper" rel="noopener noreferrer"&gt;https://apify.com/tubetext/tiktok-shop-product-scraper&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tiktok</category>
      <category>ecommerce</category>
      <category>api</category>
      <category>python</category>
    </item>
    <item>
      <title>youtube-transcript-api RequestBlocked on your server? What actually works in 2026</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Fri, 09 Oct 2026 01:47:40 +0000</pubDate>
      <link>https://dev.to/lmslay/youtube-transcript-api-requestblocked-on-your-server-what-actually-works-in-2026-1pak</link>
      <guid>https://dev.to/lmslay/youtube-transcript-api-requestblocked-on-your-server-what-actually-works-in-2026-1pak</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build one of the hosted options mentioned below (TubeText Labs on Apify).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;youtube-transcript-api&lt;/code&gt; works on your laptop and then fails on the server with &lt;code&gt;RequestBlocked&lt;/code&gt;, &lt;code&gt;IpBlocked&lt;/code&gt; or a misleading &lt;code&gt;TranscriptsDisabled&lt;/code&gt;. Here's why, and the four fixes in order of effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it breaks on servers
&lt;/h2&gt;

&lt;p&gt;YouTube answers requests from datacenter IP ranges (AWS, GCP, Azure, DigitalOcean…) with "Sign in to confirm you're not a bot". The library turns that into &lt;code&gt;RequestBlocked&lt;/code&gt;; HTTP 429 becomes &lt;code&gt;IpBlocked&lt;/code&gt;. Even home IPs get rate-limited after a few dozen fast requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 1 – upgrade and slow down
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;youtube-transcript-api&lt;/code&gt; 1.2.4+ and add backoff between requests. This is enough for a handful of videos from a home connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 2 – run the fetch from a non-cloud IP
&lt;/h2&gt;

&lt;p&gt;Move only the transcript step to a machine with a residential IP (your own box) and push results to your server. Free, but you maintain it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 3 – rotating residential proxies
&lt;/h2&gt;

&lt;p&gt;The library supports proxy configs (e.g. &lt;code&gt;WebshareProxyConfig&lt;/code&gt;). Rotate on every retry: retrying through the same blocked IP just fails slower.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 4 – call a hosted transcript API
&lt;/h2&gt;

&lt;p&gt;If you'd rather not run proxies, use a hosted scraper. With the Apify Actor I maintain, one HTTP call returns the transcripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/tubetext~youtube-transcript-fast/run-sync-get-dataset-items?timeout=300"&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;'{"urls": ["https://www.youtube.com/watch?v=aircAruvnKk"]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It takes videos, Shorts, playlists and whole channels; when a video has no captions it falls back to Whisper AI (in our 47-video test runs, 16 of 17 caption-less videos got AI transcripts – the other was music only). Failed videos are free; transcripts are $0.004 each. It's not magic: YouTube can still put an individual popular video behind a login wall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one to pick
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A few videos, occasionally → Fix 1 or 2.&lt;/li&gt;
&lt;li&gt;You already run proxies → Fix 3.&lt;/li&gt;
&lt;li&gt;Production pipeline, n8n/Make, or you need captions &lt;em&gt;and&lt;/em&gt; AI fallback → a hosted API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Questions about a specific error? Drop it in the comments.&lt;/p&gt;

</description>
      <category>python</category>
      <category>youtube</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>I reverse-engineered 8 TikTok Shop videos with one API call. Here's what the data says</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Thu, 08 Oct 2026 06:55:00 +0000</pubDate>
      <link>https://dev.to/lmslay/i-reverse-engineered-8-tiktok-shop-videos-with-one-api-call-heres-what-the-data-says-o1c</link>
      <guid>https://dev.to/lmslay/i-reverse-engineered-8-tiktok-shop-videos-with-one-api-call-heres-what-the-data-says-o1c</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I built the Apify Actor used in this post (TubeText Labs).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you run UGC ads or build content for TikTok Shop, you've probably done this by hand: watch a winning video 10 times, pause on every cut, and write down the hook, the product shot and the CTA. I wanted that as JSON, so I could do it for 50 videos at a time and feed it into a sheet or an LLM.&lt;/p&gt;

&lt;p&gt;So I took 8 recent videos from #tiktokmademebuyit and ran each one through an AI breakdown. Each video took one API call. Here's the setup, a real output, and what the 8 videos had in common.&lt;/p&gt;

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

&lt;p&gt;The Actor runs on Apify. &lt;code&gt;run-sync-get-dataset-items&lt;/code&gt; waits for the result, so you don't need polling or webhooks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/tubetext~video-breakdown-ai/run-sync-get-dataset-items?timeout=300"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$APIFY_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="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;'{"urls": ["https://www.tiktok.com/@someone/video/123..."]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python is the same request:&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.apify.com/v2/acts/tubetext~video-breakdown-ai/run-sync-get-dataset-items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;params&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;timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;headers&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;Authorization&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="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&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="si"&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;json&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;urls&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;https://www.tiktok.com/@someone/video/123...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;320&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;video&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;video&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hook&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;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pacing&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;cutsPerMinute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;commercialIntent&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;type&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;In n8n or Make, it's a single HTTP Request node with the same URL and body.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes back (real output, shortened)
&lt;/h2&gt;

&lt;p&gt;This is a 7-second pet-hair laundry video with 1.1M views:&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;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UGC ad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hook"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"problem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A close-up of a black shirt covered in pet hair, with the on-screen text 'your sign to get your laundry fish 🐟'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"why_it_works"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"It immediately identifies a common pain point for pet owners (pet hair on clothes) and offers a specific, intriguing solution."&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;"commercialIntent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"brand ad/sponsored"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"evidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The creator tags @Indigopetco and uses the hashtag #tiktokmademebuyit, indicating a partnership or promotion of the specific product."&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;"products"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laundry fish"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Indigopetco"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"first_seen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.63&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"how_shown"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"held to camera and placed into the washing machine"&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;"pacing"&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;"cutCount"&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;"avgShotSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cutsPerMinute"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;25.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cutTimes"&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="mf"&gt;0.63&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.07&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;"structure"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"beat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.63&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The creator shows a black shirt covered in pet hair to establish the problem."&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="nl"&gt;"beat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"setup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.63&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The creator introduces the 'laundry fish' sponges and places them into the washing machine."&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="nl"&gt;"beat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.07&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The washing machine is shown running with the clothes and sponges inside."&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="nl"&gt;"keyMoments"&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;"time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.07&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"what"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The reveal of the sponges covered in pet hair."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"why_it_matters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"It provides the visual proof that the product actually works, satisfying the viewer's curiosity."&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;"engagementRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0756&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 full output also has a shot-by-shot list (framing, action, on-screen text and the spoken line for each shot), the full transcript, sound info, audience and tone.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the 8 videos had in common
&lt;/h2&gt;

&lt;p&gt;Small sample, so treat these as patterns to test, not laws.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Every hook was one of three types.&lt;/strong&gt; Bold claim (4 videos), visual surprise (2), problem first (2). None opened with a slow intro or a logo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The product shows up fast.&lt;/strong&gt; It was on screen within 1.5 s in 7 of 8 videos. The one exception, a 656K-view holiday product, delayed it until 4.5 s behind a cut-off line of text ("…doesn't exi-"), which is a curiosity gap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More cuts ≠ more engagement.&lt;/strong&gt; The most-viewed video (14.1M) is 8 seconds long with zero cuts: one hand, one gadget, one demo. The fastest-cut video (27.9 cuts/min, 1.9M views) had the lowest engagement of the 8, at 0.6%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The sponsored ad beat the affiliate ones.&lt;/strong&gt; The laundry video above, which the AI flagged as a sponsored brand ad, had the highest engagement at 7.6%. The four videos flagged as TikTok Shop affiliate averaged 2.4%. Its structure is problem → product → proof in about 4 seconds.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cut detection is measured from the video, but descriptions come from a vision-language model. Inside one long continuous shot, details can get merged.&lt;/li&gt;
&lt;li&gt;Song titles come from TikTok's sound info, not from recognising the music.&lt;/li&gt;
&lt;li&gt;Commercial intent is the model's judgment based on the caption, hashtags, tags and what's on screen, with the evidence quoted. Treat it as a strong hint, not ground truth.&lt;/li&gt;
&lt;li&gt;It costs $0.03 per video (up to 3 minutes); invalid, private or unavailable videos aren't charged. It also works on Instagram Reels (beta) and YouTube, including channels and playlists.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Actor: &lt;a href="https://apify.com/tubetext/video-breakdown-ai" rel="noopener noreferrer"&gt;https://apify.com/tubetext/video-breakdown-ai&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An idea to build on top: pull your competitors' outlier videos every week, break them down, and have an LLM write three new hook variations for each one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it on your niche, I'd love to hear which fields are useful and which are missing.&lt;/p&gt;

</description>
      <category>tiktok</category>
      <category>marketing</category>
      <category>api</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
