<?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>Alibaba reverse image search: a supplier CSV with price and MOQ</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Fri, 23 Oct 2026 08:23:15 +0000</pubDate>
      <link>https://dev.to/lmslay/alibaba-reverse-image-search-a-supplier-csv-with-price-and-moq-pfn</link>
      <guid>https://dev.to/lmslay/alibaba-reverse-image-search-a-supplier-csv-with-price-and-moq-pfn</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build TubeText Labs' &lt;a href="https://apify.com/tubetext/alibaba-yiwu-image-search" rel="noopener noreferrer"&gt;Alibaba &amp;amp; Yiwu Supplier Finder by Image&lt;/a&gt;. This is a documentation-based workflow, checked on October 23, 2026, not a new sourcing test or customer case study. The inputs and decision example below are illustrative.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You have a product photo and need a shortlist of wholesale listings, with minimum order quantity (MOQ), price and a link back to each supplier. Searching only by an English product name can miss the visual details you care about.&lt;/p&gt;

&lt;p&gt;This walkthrough uses a product image to discover similar listings on &lt;strong&gt;Alibaba.com and Yiwugo&lt;/strong&gt;, then turns the results into a reviewable CSV. It stops at candidate discovery: the matches do not establish who made the photographed item, whether the goods are identical, or which supplier you should pay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Alibaba image search do you need?
&lt;/h2&gt;

&lt;p&gt;There are two different jobs behind this search phrase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search an image collection you manage.&lt;/strong&gt; Alibaba Cloud's &lt;a href="https://www.alibabacloud.com/help/en/image-search/developer-reference/api-calls-search-for-images" rel="noopener noreferrer"&gt;Image Search documentation&lt;/a&gt; describes searching within a specified Image Search instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discover supplier listings from a product photo.&lt;/strong&gt; The TubeText Actor searches Alibaba.com and Yiwugo and returns listing and supplier fields. It is an independent Apify tool, not Alibaba's official API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article covers the second job. It does not search 1688, Taobao, JD or AliExpress. An AliExpress product can supply a reference image; that does not make AliExpress one of the supplier-search destinations.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start with one public product image
&lt;/h2&gt;

&lt;p&gt;In the Actor's &lt;a href="https://apify.com/tubetext/alibaba-yiwu-image-search/input-schema" rel="noopener noreferrer"&gt;Input tab&lt;/a&gt;, use &lt;strong&gt;Product image URLs&lt;/strong&gt;, not the product page URL. Choose a clear photo of one item that you have permission to use and share. Avoid private customer photos or confidential designs.&lt;/p&gt;

&lt;p&gt;Illustrative input, &lt;strong&gt;not ready to run&lt;/strong&gt;: replace the placeholder with your permitted, publicly accessible image URL.&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;"imageUrls"&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://example.com/replace-with-your-product-photo.jpg"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sources"&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;"alibaba"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yiwugo"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxResultsPerImage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&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;Here, &lt;code&gt;maxResultsPerImage&lt;/code&gt; limits matches &lt;strong&gt;per image and per source&lt;/strong&gt;. Five is a small starting limit, not a promise that either source will return five usable candidates. English mode adds Yiwugo's English titles and shop names while retaining the Chinese originals; Alibaba.com results are documented as English.&lt;/p&gt;

&lt;p&gt;The input supports separate price filters for Alibaba (&lt;code&gt;minPriceUSD&lt;/code&gt;, &lt;code&gt;maxPriceUSD&lt;/code&gt;) and Yiwugo (&lt;code&gt;minPriceCNY&lt;/code&gt;, &lt;code&gt;maxPriceCNY&lt;/code&gt;). For a first pass, leaving them unset can help you see whether the photo returns the right product category before narrowing on listed price.&lt;/p&gt;

&lt;p&gt;When you choose to run it, review the &lt;a href="https://apify.com/tubetext/alibaba-yiwu-image-search/pricing" rel="noopener noreferrer"&gt;current event pricing&lt;/a&gt; first. Each selected source is a separate image search. Match limits, extra-match events and Actor Start charges matter; fewer returned rows do not automatically mean the entire run is free.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Build a CSV that preserves the evidence
&lt;/h2&gt;

&lt;p&gt;After a run finishes, inspect the dataset before exporting CSV or Excel. Keep JSON as well if you need array fields such as certifications.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://apify.com/tubetext/alibaba-yiwu-image-search/output-schema" rel="noopener noreferrer"&gt;documented output fields&lt;/a&gt; support this shortlist:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Review question&lt;/th&gt;
&lt;th&gt;Fields to keep&lt;/th&gt;
&lt;th&gt;How to use them&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Which image produced this candidate?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;input&lt;/code&gt;, &lt;code&gt;sourceImage&lt;/code&gt;, &lt;code&gt;scrapedAt&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Preserve the reference and observation time.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where is the listing?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;source&lt;/code&gt;, &lt;code&gt;productId&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;urlEn&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Use source plus listing identity, not the title alone. &lt;code&gt;urlEn&lt;/code&gt; is for Yiwugo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is it visually relevant?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;title&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt;, &lt;code&gt;rank&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;matchConfidence&lt;/code&gt;, &lt;code&gt;similarity&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Open the listing and compare the item, not just its rank. &lt;code&gt;similarity&lt;/code&gt; is Alibaba-specific.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What price is being advertised?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;price&lt;/code&gt;, &lt;code&gt;currency&lt;/code&gt;, &lt;code&gt;priceMin&lt;/code&gt;, &lt;code&gt;priceMax&lt;/code&gt;, &lt;code&gt;priceText&lt;/code&gt;, &lt;code&gt;priceCNY&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Keep currency and any range or original text. Missing is not zero.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does the order size fit?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;moq&lt;/code&gt;, &lt;code&gt;moqUnit&lt;/code&gt;, &lt;code&gt;moqText&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Check the unit and original wording together.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who is behind the listing?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;shopName&lt;/code&gt;, &lt;code&gt;shopUrl&lt;/code&gt;, &lt;code&gt;supplierCountry&lt;/code&gt;, &lt;code&gt;supplierProfileUrl&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Preserve the source links for later review. Some fields are source-specific.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All of these fields are optional in the public schema. Do not assume a complete row. Keep non-&lt;code&gt;ok&lt;/code&gt; statuses and errors in a separate review tab instead of silently deleting them or treating them as a zero-priced offer.&lt;/p&gt;

&lt;p&gt;Add your own columns for &lt;code&gt;requested_quantity&lt;/code&gt;, &lt;code&gt;variant_checked&lt;/code&gt;, &lt;code&gt;unit_checked&lt;/code&gt;, &lt;code&gt;review_decision&lt;/code&gt; and &lt;code&gt;review_notes&lt;/code&gt;. These are reviewer-added columns, not Actor output. If you collect several photos, keep each image-to-listing relationship even when the same listing appears more than once.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Filter for MOQ before ranking by price
&lt;/h2&gt;

&lt;p&gt;Suppose your intended order is &lt;strong&gt;200 pieces&lt;/strong&gt;. This is a made-up decision example, not returned data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Candidate A has an MOQ of 1,000 pieces. A low displayed unit price does not make it suitable for the 200-piece brief.&lt;/li&gt;
&lt;li&gt;Candidate B has an MOQ of 100, but its unit is boxes. Its quantity is not comparable until you know pieces per box.&lt;/li&gt;
&lt;li&gt;Candidate C shows no price. Keep it as “quote needed,” not “free.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use the same checks on actual rows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the listing and confirm that the photo match is the intended item, rather than a visually similar accessory.&lt;/li&gt;
&lt;li&gt;Check variant, size, material and pack size. A shared image does not prove equivalent goods.&lt;/li&gt;
&lt;li&gt;Compare MOQ only after resolving the unit. Preserve the original &lt;code&gt;moqText&lt;/code&gt; when parsing is uncertain.&lt;/li&gt;
&lt;li&gt;Compare advertised prices within the same currency and price basis. A low end of a range may not apply to your quantity or variant.&lt;/li&gt;
&lt;li&gt;Record which candidates need clarification before they enter a price comparison.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alibaba USD prices and Yiwugo CNY prices should not be sorted together as raw numbers. Even after currency conversion, a listing price is not a landed quote: shipping, packaging, duties, taxes, samples and payment terms still need separate confirmation. Subtracting it from a retail price does not establish profit.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Keep supplier verification separate
&lt;/h2&gt;

&lt;p&gt;Alibaba-specific fields can include &lt;code&gt;supplierYears&lt;/code&gt;, &lt;code&gt;supplierRating&lt;/code&gt;, &lt;code&gt;supplierReviews&lt;/code&gt;, &lt;code&gt;goldSupplier&lt;/code&gt;, &lt;code&gt;certifications&lt;/code&gt; and &lt;code&gt;isAd&lt;/code&gt;. Yiwugo can include a market booth or location.&lt;/p&gt;

&lt;p&gt;Use those fields to decide what to inspect, not as proof of manufacturing ownership, product quality or regulatory compliance. A certification label in a listing is not a verified certificate for your exact product and destination. A high visual score is not a supplier trust score.&lt;/p&gt;

&lt;p&gt;The next stage is a reviewed specification, a supplier quote and, when appropriate, sample and document checks. This workflow does not contact suppliers, order samples or make a purchasing decision for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Already have an AliExpress product dataset?
&lt;/h2&gt;

&lt;p&gt;The existing &lt;a href="https://github.com/LMSlay/tubetext-examples/blob/main/recipes/products_to_suppliers.py" rel="noopener noreferrer"&gt;products-to-suppliers Python recipe&lt;/a&gt; first collects AliExpress product candidates, then passes that run's dataset to this image-search Actor. You do not need that first step if you already have a suitable image.&lt;/p&gt;

&lt;p&gt;For an existing dataset, the supplier Actor accepts &lt;code&gt;datasetId&lt;/code&gt; and &lt;code&gt;maxDatasetItems&lt;/code&gt;. The schema describes using each product's main image and carrying its title, URL and price into the results. Check those images and cap the number of products before scaling. Dataset access may require the read-only permission shown by Apify.&lt;/p&gt;

&lt;p&gt;The recipe's console output is deliberately minimal. Use the full supplier dataset for review, retaining source links, statuses, units and currencies as above. Its two Actor calls have separate event charges. The recipe was inspected for this article but not executed, and it has not been turned into a verified purchasing workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; open the &lt;a href="https://apify.com/tubetext/alibaba-yiwu-image-search/input-schema" rel="noopener noreferrer"&gt;Actor input&lt;/a&gt;, review the &lt;a href="https://apify.com/tubetext/alibaba-yiwu-image-search/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;, and start with one permitted product photo when you are ready. The useful first result is a small, traceable candidate list you can review, not a claim to have found the original factory.&lt;/p&gt;

</description>
      <category>api</category>
      <category>ecommerce</category>
      <category>webscraping</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Spotify play counts to CSV: compare your own snapshots</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Fri, 23 Oct 2026 07:54:54 +0000</pubDate>
      <link>https://dev.to/lmslay/spotify-play-counts-to-csv-compare-your-own-snapshots-2jhl</link>
      <guid>https://dev.to/lmslay/spotify-play-counts-to-csv-compare-your-own-snapshots-2jhl</guid>
      <description>&lt;p&gt;Disclosure: this tutorial is published by TubeText Labs, the developer of the &lt;a href="https://apify.com/tubetext/spotify-play-count-scraper" rel="noopener noreferrer"&gt;Spotify Play Count Scraper&lt;/a&gt;. It describes an illustrative research workflow based on the public documentation checked on October 23, 2026. No new Actor run was performed for this article.&lt;/p&gt;

&lt;p&gt;A music researcher following a group of releases needs a repeatable way to answer: what public counts did I observe last time, and what changed since then?&lt;/p&gt;

&lt;p&gt;You can export Spotify track and artist metrics, save each collection separately, and compare matching records. The important part is keeping cumulative play counts, monthly listeners and missing observations distinct.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Choose a fixed set of links
&lt;/h2&gt;

&lt;p&gt;Open the Actor and put public Spotify artist, album or track links in &lt;strong&gt;Spotify links&lt;/strong&gt; (&lt;code&gt;items&lt;/code&gt;). For a stable release panel, use explicit album or track URLs rather than assuming an artist's current popular releases will stay the same.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://apify.com/tubetext/spotify-play-count-scraper/input-schema" rel="noopener noreferrer"&gt;current input schema&lt;/a&gt; also accepts playlist links, but limits &lt;code&gt;maxPlaylistTracks&lt;/code&gt; to 100. It describes coverage as the tracks listed by Spotify's embed player. Do not treat a long playlist export as a guaranteed complete playlist.&lt;/p&gt;

&lt;p&gt;For artist links, leave &lt;code&gt;maxReleasesPerArtist&lt;/code&gt; at &lt;code&gt;0&lt;/code&gt; if you only want artist summaries, including their top tracks. Setting it above zero requests additional popular releases and albums, with a schema maximum of 50 releases per artist. That expands the data collected and the billable album/track events.&lt;/p&gt;

&lt;p&gt;Keep your link list and input settings alongside each export so you can tell a metric change from a change in collection scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Export the fields you actually need
&lt;/h2&gt;

&lt;p&gt;Run the Actor when you are ready to incur its published charges, then open the output and export the &lt;strong&gt;Tracks&lt;/strong&gt;, &lt;strong&gt;Artists&lt;/strong&gt; or &lt;strong&gt;Albums&lt;/strong&gt; view as CSV/Excel. Keep JSON too if you need nested fields such as cities or top tracks.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://apify.com/tubetext/spotify-play-count-scraper/output-schema" rel="noopener noreferrer"&gt;documented output&lt;/a&gt; includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track rows: &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;playcount&lt;/code&gt;, &lt;code&gt;artists&lt;/code&gt;, &lt;code&gt;albumName&lt;/code&gt; and &lt;code&gt;releaseDate&lt;/code&gt;. &lt;code&gt;playcount&lt;/code&gt; is the cumulative track count, not a count for your research interval.&lt;/li&gt;
&lt;li&gt;Artist rows: &lt;code&gt;monthlyListeners&lt;/code&gt;, &lt;code&gt;followers&lt;/code&gt;, &lt;code&gt;worldRank&lt;/code&gt;, &lt;code&gt;topCities&lt;/code&gt; and &lt;code&gt;topTracks&lt;/code&gt;. World rank is documented for the top 500 only.&lt;/li&gt;
&lt;li&gt;Album rows: &lt;code&gt;label&lt;/code&gt;, &lt;code&gt;totalTracks&lt;/code&gt; and &lt;code&gt;totalPlays&lt;/code&gt;; the last is a sum of track play counts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These fields are optional and nullable in the schema. Retain &lt;code&gt;status&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt;, and never replace an unavailable value with zero. Top-city listener counts are location aggregates, not individual listener records or demographic profiles.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Preserve two separate snapshots
&lt;/h2&gt;

&lt;p&gt;Save the first dataset and its run identifier. In your own research table, add an observation label, the run's collection window and an export timestamp in UTC. These are workflow metadata you add, not fields this article claims the Actor returns.&lt;/p&gt;

&lt;p&gt;Later, repeat the same inputs and save a second dataset without overwriting the first. Match successful track rows by their documented Spotify &lt;code&gt;url&lt;/code&gt; and &lt;code&gt;type&lt;/code&gt;, after checking that the URLs refer to the same entity. Do not join only on a song title, and do not combine album totals with track counts.&lt;/p&gt;

&lt;p&gt;In a spreadsheet or database, calculate:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;observed change = later playcount - earlier playcount&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Only calculate it when both matched rows have &lt;code&gt;status = ok&lt;/code&gt; and numeric values. Leave unmatched or unavailable observations missing, and investigate duplicate records or negative differences rather than silently fixing them.&lt;/p&gt;

&lt;p&gt;Call this &lt;strong&gt;change between observed cumulative counts&lt;/strong&gt;. It is not an independently verified count of streams during a calendar day: collection times, source updates and missing observations can affect the comparison. A difference in &lt;code&gt;monthlyListeners&lt;/code&gt; is a change in that reported metric, not a count of newly acquired listeners.&lt;/p&gt;

&lt;p&gt;This workflow starts building your own history from saved observations. It does not backfill past counts, estimate royalties or establish why a metric changed. Availability and completeness can vary.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Budget for every event type
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://apify.com/tubetext/spotify-play-count-scraper/pricing" rel="noopener noreferrer"&gt;live pricing page&lt;/a&gt;, checked October 23, lists Free-plan event rates of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$0.001 per track ($1 per 1,000 track events).&lt;/li&gt;
&lt;li&gt;$0.003 per artist report.&lt;/li&gt;
&lt;li&gt;$0.002 per album summary, with its tracks charged separately.&lt;/li&gt;
&lt;li&gt;$0.00005 per Actor Start event. The number of start events depends on allocated memory: one per GB, with a minimum of one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For illustration, 20 chargeable track events, one album summary, one artist report and one start event add up to &lt;strong&gt;$0.02505&lt;/strong&gt;. That is cost arithmetic, not a measured run or a fixed-price promise. Repeated snapshots incur their own events; higher Apify plans have different result-event rates. Check your selected plan before running.&lt;/p&gt;

&lt;p&gt;The documentation describes failed or empty items as unbilled result rows, but that does not eliminate the separate start charge. Optional artist-release expansion can add album and track charges; the current public schema lists no AI option or AI event.&lt;/p&gt;

&lt;p&gt;For a first research panel, keep the scope small and explicit. Export one observation, inspect the fields and missing values, then decide whether a recurring comparison would answer your actual research question.&lt;/p&gt;

&lt;p&gt;Which comparison would you need: a fixed release panel, artist monthly-listener snapshots, or a playlist's changing membership? Those require different handling of scope and missing records.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>analytics</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>Turn competitor video ads into an original creative brief, with source links</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Thu, 22 Oct 2026 14:57:57 +0000</pubDate>
      <link>https://dev.to/lmslay/turn-competitor-video-ads-into-an-original-creative-brief-with-source-links-27if</link>
      <guid>https://dev.to/lmslay/turn-competitor-video-ads-into-an-original-creative-brief-with-source-links-27if</guid>
      <description>&lt;p&gt;Disclosure: I maintain TubeText Labs, including the Video Ad Analyzer discussed here.&lt;/p&gt;

&lt;p&gt;A folder of saved ads is useful until someone asks, “What should we actually make?” The missing step is a brief that separates what another advertiser did from what your own brand can honestly demonstrate.&lt;/p&gt;

&lt;p&gt;Here is a small, review-first workflow. It uses an existing public sample and a hypothetical brief, not a newly tested campaign or a claim about conversion performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Keep the reference attached to the analysis
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/tubetext/video-ad-analyzer" rel="noopener noreferrer"&gt;Video Ad Analyzer&lt;/a&gt; accepts Google advertiser names or domains, Meta brands or Facebook pages, existing video links, or an ad scraper's dataset. Its analysis includes the hook, persuasion angle, offer, CTA, transcript and shot breakdown.&lt;/p&gt;

&lt;p&gt;For the downstream brief, keep three groups separate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source context: advertiser, original video or ad-library link, country and available dates.&lt;/li&gt;
&lt;li&gt;Observations: what the opening shows, what the speaker says, what the offer includes.&lt;/li&gt;
&lt;li&gt;Interpretation: why a hook might work, which audience it might address, what to test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not turn a model's interpretation into a fact about sales. An ad being visible in a library does not establish its profitability.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Inspect a sample before spending anything
&lt;/h2&gt;

&lt;p&gt;The Actor's README already includes a shortened Grammarly example. It shows source identifiers alongside a problem-led opening, an offer, a CTA and a shot count. Read that static sample first; there is no need to start a run to see the intended output shape.&lt;/p&gt;

&lt;p&gt;If the fields fit your process, explicitly limit a later run. The &lt;a href="https://apify.com/tubetext/video-ad-analyzer/input-schema" rel="noopener noreferrer"&gt;input documentation&lt;/a&gt; lets you set the ads per brand and maximum video length. Also set Maximum cost per run in the run options. Avoid scheduling repeated collection before checking whether the first results are useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Write your own brief
&lt;/h2&gt;

&lt;p&gt;The following is hypothetical, written for this article, and not Actor output. Imagine a desk-organizer brand whose approved product facts include removable dividers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audience problem: small desk items are difficult to find.&lt;/li&gt;
&lt;li&gt;Opening concept: film your own untidy drawer, then show the same items arranged using the dividers.&lt;/li&gt;
&lt;li&gt;Proof required: record the actual product in use, with no staged capacity or speed claim.&lt;/li&gt;
&lt;li&gt;Message: explain the divider layout in your own words.&lt;/li&gt;
&lt;li&gt;CTA: link to your actual product details; include only a currently approved offer.&lt;/li&gt;
&lt;li&gt;Review gate: check product claims, footage rights, accessibility and destination before publishing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reusable learning is a problem → demonstration structure. Do not copy another advertiser's script, footage, music, identity or unsupported promises. Keep the reference link in your research notes so a reviewer can distinguish inspiration from source material.&lt;/p&gt;

&lt;p&gt;This brief-writing step belongs to your team or a separately reviewed downstream process. The Actor does not provide an end-to-end video-production and publishing service.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Check quality and the full bill
&lt;/h2&gt;

&lt;p&gt;AI analysis uses sampled frames and can miss context. Review the original video, advertiser match, offer conditions and relevant timestamps. Inspect row status before using a result; a completed run alone is not a quality check.&lt;/p&gt;

&lt;p&gt;As of October 22, 2026, the &lt;a href="https://apify.com/tubetext/video-ad-analyzer/pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt; lists Free-plan events at $0.05 per ad analysis, $0.01 per extra video minute, and $0.00005 for Actor Start. The README includes the first three minutes and bills additional started minutes. Meta discovery adds separate fetching charges; check the &lt;a href="https://apify.com/tubetext/meta-ad-library-videos/pricing" rel="noopener noreferrer"&gt;Meta fetching Actor's current pricing&lt;/a&gt; too. A waived analysis charge does not make the whole workflow free. Downstream AI or automation services can add their own costs.&lt;/p&gt;

&lt;p&gt;Start with the public sample. Which missing brief field would make this useful in your review process?&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>automation</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>A TikTok Shop API for public product data: price, units sold and stock per SKU as JSON</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Sun, 18 Oct 2026 03:26:45 +0000</pubDate>
      <link>https://dev.to/lmslay/a-tiktok-shop-api-for-public-product-data-price-units-sold-and-stock-per-sku-as-json-37c8</link>
      <guid>https://dev.to/lmslay/a-tiktok-shop-api-for-public-product-data-price-units-sold-and-stock-per-sku-as-json-37c8</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apify.com/tubetext" rel="noopener noreferrer"&gt;TubeText&lt;/a&gt;. This post uses our TikTok Shop Actor on Apify. The numbers below are from a run I did today.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you search for a "TikTok Shop API", you mostly find TikTok's Partner/Seller APIs. Those are for managing &lt;strong&gt;your own&lt;/strong&gt; shop: orders, listings, fulfillment. They won't tell you what a competitor's product costs, how many units it has sold or how much stock is left.&lt;/p&gt;

&lt;p&gt;For that public product data, here's the one-call setup I use: the &lt;a href="https://apify.com/tubetext/tiktok-shop-product-scraper" rel="noopener noreferrer"&gt;TikTok Shop Data API &amp;amp; Scraper&lt;/a&gt; on Apify.&lt;/p&gt;

&lt;h2&gt;
  
  
  One request: product and store links in, JSON out
&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?token=&lt;/span&gt;&lt;span class="nv"&gt;$APIFY_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"urls":["https://www.tiktok.com/shop/pdp/1729527313880355335","https://www.tiktok.com/shop/store/goli-nutrition/7495794203056835079"],"maxProductsPerListing":8}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can mix product links, store links and category links. A store link expands to its products, up to &lt;code&gt;maxProductsPerListing&lt;/code&gt;. My run returned &lt;strong&gt;8 products in 24 seconds&lt;/strong&gt;, and the call waited and returned the rows directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What came back
&lt;/h2&gt;

&lt;p&gt;The top rows from one supplement brand's store (US region):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product (shortened)&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;List price&lt;/th&gt;
&lt;th&gt;Sold&lt;/th&gt;
&lt;th&gt;Rating (reviews)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ashwagandha &amp;amp; Vitamin D Gummy&lt;/td&gt;
&lt;td&gt;$19.47&lt;/td&gt;
&lt;td&gt;$24.70&lt;/td&gt;
&lt;td&gt;1,305,110&lt;/td&gt;
&lt;td&gt;4.5 (94,569)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero Sugar Best Seller Trio&lt;/td&gt;
&lt;td&gt;$49.37&lt;/td&gt;
&lt;td&gt;$74.10&lt;/td&gt;
&lt;td&gt;1,036,888&lt;/td&gt;
&lt;td&gt;4.4 (48,836)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 Bottles of Ashwagandha &amp;amp; Vitamin D&lt;/td&gt;
&lt;td&gt;$58.47&lt;/td&gt;
&lt;td&gt;$74.10&lt;/td&gt;
&lt;td&gt;865,774&lt;/td&gt;
&lt;td&gt;4.7 (71,524)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3-bottle Best Seller Bundle&lt;/td&gt;
&lt;td&gt;$49.37&lt;/td&gt;
&lt;td&gt;$74.10&lt;/td&gt;
&lt;td&gt;556,764&lt;/td&gt;
&lt;td&gt;4.6 (41,460)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One product row, shortened:&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;"productId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1729527313880355335"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"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;"discount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-21%"&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;1305110&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;94569&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalStock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;332597&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;332597&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"freeShipping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deliveryEstimate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Oct 22 - Oct 25"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"shopName"&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 Nutrition"&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;601523&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;5791276&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"charged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three fields I find most useful for monitoring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;soldCount&lt;/code&gt;&lt;/strong&gt;: diff it between two runs and you have units sold per day, per product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;totalStock&lt;/code&gt; and per-SKU &lt;code&gt;stock&lt;/code&gt;&lt;/strong&gt;: see which variant is running low, and when a restock happens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;price&lt;/code&gt; vs &lt;code&gt;originalPrice&lt;/code&gt;&lt;/strong&gt;: the discount depth. Here every product was 21–33% off its list price.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Choose listing cards or SKU-level stock details
&lt;/h2&gt;

&lt;p&gt;For a single-product request and a short Python snapshot-diff example, start with the &lt;a href="https://dev.to/lmslay/how-to-get-tiktok-shop-product-data-price-sales-stock-per-sku-as-json-in-2026-52aa"&gt;earlier TikTok Shop JSON quickstart&lt;/a&gt;. For the mixed product/store request above, choose the detail level before budgeting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Need SKU stock, specifications, shipping and shop stats?&lt;/strong&gt; Keep &lt;code&gt;includeDetails: true&lt;/code&gt; (the default) for store/category products. Full-detail results cost $0.004 per product on the Free plan. The 8-product example has $0.032 in product-detail fees; 1,000 such results have $4 in product-detail fees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only need title, price, sold count and rating from a store/category listing?&lt;/strong&gt; Set &lt;code&gt;includeDetails: false&lt;/code&gt;. Listing cards cost $0.0015 each on the Free plan. Do not use listing-card mode when your workflow needs the SKU stock shown above. This setting applies to store/category products, not direct product URLs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are result-event prices, not a promise of the total run cost. Unavailable products and errors do not incur the product-detail fee; a row's &lt;code&gt;charged&lt;/code&gt; flag is not an itemized run bill. Actor Start is separate, currently $0.00005 per event, with the event count based on memory (one per GB, minimum one). Check the &lt;a href="https://apify.com/tubetext/tiktok-shop-product-scraper/pricing" rel="noopener noreferrer"&gt;current Pricing tab&lt;/a&gt; and itemized run charges; a run containing only failures is not guaranteed to cost zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it daily
&lt;/h2&gt;

&lt;p&gt;Save the input as an Apify task, schedule it daily, and add a webhook to your endpoint. Each day's dataset is a snapshot you can diff. Or call it from n8n or Make with the Apify node. The data is US TikTok Shop and needs no login.&lt;/p&gt;

&lt;p&gt;Questions or a field you need? Open an issue on the Actor's page. I read every one.&lt;/p&gt;

</description>
      <category>api</category>
      <category>ecommerce</category>
      <category>tiktok</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>Reverse-engineer a creator's style: an AI persona and style guide from their latest videos</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Sun, 18 Oct 2026 01:40:13 +0000</pubDate>
      <link>https://dev.to/lmslay/reverse-engineer-a-creators-style-an-ai-persona-and-style-guide-from-their-latest-videos-435o</link>
      <guid>https://dev.to/lmslay/reverse-engineer-a-creators-style-an-ai-persona-and-style-guide-from-their-latest-videos-435o</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apify.com/tubetext" rel="noopener noreferrer"&gt;TubeText&lt;/a&gt;. This post uses our Video Breakdown AI Actor on Apify. The output below is from a run I did today.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When you study a creator, the useful question isn't "what is this video about?" but "what does this person do every time?": which hooks they open with, how fast they cut, what they sell, how they end. Answering that means watching a dozen videos with a notepad.&lt;/p&gt;

&lt;p&gt;Here's how I get a first draft of that notepad from one API call: a persona and style guide built from a creator's latest videos, using &lt;a href="https://apify.com/tubetext/video-breakdown-ai" rel="noopener noreferrer"&gt;Video Breakdown AI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  One call: a channel in, a style guide out
&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~video-breakdown-ai/run-sync-get-dataset-items?token=&lt;/span&gt;&lt;span class="nv"&gt;$APIFY_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"urls":["https://www.youtube.com/@mkbhd/shorts"],"maxVideosPerSource":5,"accountSummary":true}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Actor takes the 5 newest Shorts, breaks each one down (hook, shot list, cut pacing, products shown, script), then condenses them into one extra row with &lt;code&gt;"rowType": "account_summary"&lt;/code&gt;. It works with a YouTube channel or an Instagram profile, and it needs at least 3 analyzed videos.&lt;/p&gt;

&lt;h2&gt;
  
  
  What came back for MKBHD's Shorts
&lt;/h2&gt;

&lt;p&gt;The summary row, shortened:&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;"rowType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"account_summary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Marques Brownlee"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"videosAnalyzed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"medianDurationSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"medianCutsPerMinute"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9.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;"medianShotCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"medianViews"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7170706&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accountSummary"&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;"content_pillars"&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="nl"&gt;"pillar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Product Reviews &amp;amp; Deep Dives"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"share_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&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;"pillar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tech Industry News &amp;amp; Analysis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"share_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&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;"pillar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Concept &amp;amp; Speculative Tech"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"share_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&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;"hook_patterns"&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="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;"visual surprise"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"share_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"example"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hey Benny. Do a flip."&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;"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;"bold claim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"share_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"example"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"All right, the folding iPhone is here. It's real. It's called the iPhone Duo."&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;"ctas"&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;"Get subscribed for more"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Watch the full video"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Follow for more"&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_performs_best"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Videos featuring high-interest, 'impossible' tech concepts or viral-worthy hardware (like the iPhone Duo or Benny robot) significantly outperform standard industry analysis…"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also returns a persona, tone and voice, on-screen text style, products and brands, posting cadence, and a style guide of 5 to 8 rules. Three of the seven it wrote for this channel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Start with an immediate visual or auditory hook that defies expectations."&lt;/li&gt;
&lt;li&gt;"Prioritize 'show, don't tell' by using high-quality B-roll to demonstrate features."&lt;/li&gt;
&lt;li&gt;"Keep on-screen text minimal, using it only for critical data points or emphasis."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two things I find more useful than the prose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The hook mix is countable.&lt;/strong&gt; 3 of 5 Shorts open on a visual surprise and 2 on a bold spoken claim. Run it on three competitors and you can compare those shares directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The medians give you a brief.&lt;/strong&gt; About 66 seconds, about 10 cuts a minute, 11 shots. That's a concrete target for an editor, not "make it punchy".&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The per-video rows are still there
&lt;/h2&gt;

&lt;p&gt;Each of the 5 videos also gets its own row, so you can check the summary against the evidence. For example, the hook row for "Apple's Big Price Hike":&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;"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;"All right, so the memory price hikes have finally hit Apple and they have really hit."&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;"bold claim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"delivered_as"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"voice"&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 addresses a major tech news story with a sense of urgency and direct impact on the viewer's wallet."&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;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;Analysis costs $0.03 per video on the Free plan, plus $0.01 per additional started minute past 3 minutes. The account summary row has &lt;strong&gt;no separate fee during beta&lt;/strong&gt;. For the five Shorts in this example, the analysis subtotal was about $0.15; the reported run took about 3½ minutes. Optional YouTube residential traffic and any Actor Start charge are additional. A failed download or analysis has no analysis-result fee, but that is not a promise that the whole run costs zero. Check the current &lt;a href="https://apify.com/tubetext/video-breakdown-ai/pricing" rel="noopener noreferrer"&gt;Pricing tab&lt;/a&gt; and itemized run charges.&lt;/p&gt;

&lt;p&gt;If a channel posts long videos, set &lt;code&gt;"channelSort": "popular"&lt;/code&gt; to study its most-viewed uploads instead of the newest, and keep &lt;code&gt;maxVideosPerSource&lt;/code&gt; small at first.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;5 videos is a small sample. The shares (60%, 40%) are counts, not statistics. Use 10 to 20 videos for anything you'll act on.&lt;/li&gt;
&lt;li&gt;The persona and style guide are a model's reading of the videos. Treat them as a first draft to check against the per-video rows, not as fact.&lt;/li&gt;
&lt;li&gt;Instagram profiles often hide view counts. When that happens, the summary says so instead of guessing what performs best.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Questions or a platform you need? Open an issue on the Actor's page. I read every one.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>youtube</category>
      <category>contentcreation</category>
    </item>
    <item>
      <title>Idealo price API: compare shop offers across 6 European markets</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Thu, 15 Oct 2026 01:37:13 +0000</pubDate>
      <link>https://dev.to/lmslay/idealo-price-data-across-6-eu-markets-as-json-one-product-id-every-shop-1j6f</link>
      <guid>https://dev.to/lmslay/idealo-price-data-across-6-eu-markets-as-json-one-product-id-every-shop-1j6f</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apify.com/tubetext" rel="noopener noreferrer"&gt;TubeText&lt;/a&gt;. This post uses our idealo Actor on Apify. The sample prices below are from the original October 15, 2026 post, not live quotes. Documentation reviewed October 23, 2026; the sample was not rerun for this update.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a retailer comparing competitor offers or a pricing analyst preparing a daily snapshot, the &lt;a href="https://apify.com/tubetext/idealo-price-scraper" rel="noopener noreferrer"&gt;Idealo Price Scraper&lt;/a&gt; returns shop offers and a price summary as JSON, CSV or Excel. Start with idealo product links, product IDs or keywords, then choose Germany, Austria, France, Italy, Spain or the UK.&lt;/p&gt;

&lt;p&gt;The Actor checks the supplied product ID in the selected markets and returns offers up to &lt;code&gt;maxOffersPerMarket&lt;/code&gt;. Availability and offer counts can differ by market. Before treating two prices as comparable, review the offer title, variant, condition, currency and shipping terms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idealo API example: one product, three markets
&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~idealo-price-scraper/run-sync-get-dataset-items?token=&lt;/span&gt;&lt;span class="nv"&gt;$APIFY_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"products":["https://www.idealo.de/preisvergleich/OffersOfProduct/202092559_-airpods-pro-2-apple.html"],"markets":["de","fr","it"],"maxOffersPerMarket":20}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original example contains 45 shop offers plus one summary row per market. These historical rows illustrate the output for Apple AirPods Pro 2; they are not today's prices or a speed guarantee:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Market&lt;/th&gt;
&lt;th&gt;Offers&lt;/th&gt;
&lt;th&gt;Shops&lt;/th&gt;
&lt;th&gt;Lowest&lt;/th&gt;
&lt;th&gt;Median&lt;/th&gt;
&lt;th&gt;Highest&lt;/th&gt;
&lt;th&gt;Lowest incl. shipping&lt;/th&gt;
&lt;th&gt;Cheapest shop&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DE&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;€183.00&lt;/td&gt;
&lt;td&gt;€244.41&lt;/td&gt;
&lt;td&gt;€387.99&lt;/td&gt;
&lt;td&gt;€188.99&lt;/td&gt;
&lt;td&gt;eBay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FR&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;€199.98&lt;/td&gt;
&lt;td&gt;€246.26&lt;/td&gt;
&lt;td&gt;€387.99&lt;/td&gt;
&lt;td&gt;€199.98&lt;/td&gt;
&lt;td&gt;Cdiscount.com (Marketplace)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IT&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;€195.99&lt;/td&gt;
&lt;td&gt;€238.03&lt;/td&gt;
&lt;td&gt;€387.99&lt;/td&gt;
&lt;td&gt;€202.99&lt;/td&gt;
&lt;td&gt;prezzoforte.it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read these as summaries of the offers returned, not an exhaustive market census:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep price and shipping together.&lt;/strong&gt; The sample German minimum is €183 before shipping and €188.99 including listed shipping. Check &lt;code&gt;totalPriceWithShipping&lt;/code&gt; and the delivery destination; this field alone does not establish cross-border landed cost or account for every tax, duty or discount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the comparison consistent.&lt;/strong&gt; The three sample medians are within €10 of each other, but one snapshot cannot establish price stability. Use the same product, market, currency and offer limit for repeated comparisons. UK prices are in GBP; the other five markets use EUR. Do not rank those raw numbers as if they were the same currency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What an offer row looks like
&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;"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;"offer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"productName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Apple AirPods Pro 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"market"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"de"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"position"&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;"shopName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eBay"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"offerTitle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Apple AirPods Pro 2 mit USB-C MagSafe Case"&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="mi"&gt;183&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"shippingCost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalPriceWithShipping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;188.99&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;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deliveryTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Do. 15.10.–Di. 20.10.2026"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"shopRating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"shopReviews"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2012&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;
  
  
  Export competitor shop offers to CSV
&lt;/h2&gt;

&lt;p&gt;If you need a spreadsheet of competing shops' offers, first distinguish that task from publishing your own catalogue. &lt;a href="https://partner.idealo.com/partner-idealo-com/uk/learning-center/faq-technical-integration" rel="noopener noreferrer"&gt;Idealo's merchant integration FAQ&lt;/a&gt; describes sending your product and offer data to idealo through its offer API or an exported feed. That merchant-upload workflow does not answer the competitor-read question here. TubeText's Actor is a third-party tool, not idealo's official merchant API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build a reviewable shop-level export
&lt;/h3&gt;

&lt;p&gt;Use reviewed product links or IDs, select the markets, keep &lt;code&gt;includeOfferRows: true&lt;/code&gt;, and choose a consistent &lt;code&gt;maxOffersPerMarket&lt;/code&gt;. After a completed run, choose the &lt;strong&gt;Offers&lt;/strong&gt; view and export CSV. If you export the mixed dataset instead, keep &lt;code&gt;type: "offer"&lt;/code&gt; rows for the offer table and retain summary/error/no-offer rows separately. A summary row is not another shop.&lt;/p&gt;

&lt;p&gt;Keep these columns from the &lt;a href="https://apify.com/tubetext/idealo-price-scraper/output-schema" rel="noopener noreferrer"&gt;documented output&lt;/a&gt;. Fields are optional; a column name is not a guarantee that every row contains a value.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Comparison column&lt;/th&gt;
&lt;th&gt;Documented field&lt;/th&gt;
&lt;th&gt;How to use it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Product reference&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;productId&lt;/code&gt;, &lt;code&gt;productName&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Preserve the reviewed input ID/link alongside the export. If an offer row lacks its ID, attach it only from unambiguous run context, never from a name-only guess.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market and currency&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;market&lt;/code&gt;, &lt;code&gt;marketSite&lt;/code&gt;, &lt;code&gt;currency&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partition comparisons by market and currency.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shop and offer&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;shopName&lt;/code&gt;, &lt;code&gt;offerTitle&lt;/code&gt;, &lt;code&gt;offerUrl&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Retain the title and source link for variant, condition and offer checks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Item price&lt;/td&gt;
&lt;td&gt;&lt;code&gt;price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compare the item's stated price separately from delivery.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shipping&lt;/td&gt;
&lt;td&gt;&lt;code&gt;shippingCost&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep missing or unclear shipping unknown, not zero.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Listed delivered total&lt;/td&gt;
&lt;td&gt;&lt;code&gt;totalPriceWithShipping&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use only when the amount and delivery basis are comparable; this is not a guaranteed checkout or cross-border landed cost.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Add your own observation timestamp and run/dataset reference beside each export. These are bookkeeping columns you maintain, not timestamp fields promised by this output schema. Preserve &lt;code&gt;position&lt;/code&gt; if useful, but do not use a changing rank as an offer identifier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worked example: item price and delivered price give different orders
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Everything in this table is fictional:&lt;/strong&gt; the shops, product and prices are invented to demonstrate a comparison, not collected results. Assume one reviewed product, the same variant and condition, market &lt;code&gt;de&lt;/code&gt;, currency &lt;code&gt;EUR&lt;/code&gt;, and the same delivery destination and terms. The labels below correspond to &lt;code&gt;shopName&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt;, &lt;code&gt;shippingCost&lt;/code&gt; and &lt;code&gt;totalPriceWithShipping&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fictional shop&lt;/th&gt;
&lt;th&gt;Item price (EUR)&lt;/th&gt;
&lt;th&gt;Listed shipping (EUR)&lt;/th&gt;
&lt;th&gt;Listed delivered total (EUR)&lt;/th&gt;
&lt;th&gt;Delivered-price treatment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Demo Shop A&lt;/td&gt;
&lt;td&gt;189.00&lt;/td&gt;
&lt;td&gt;8.00&lt;/td&gt;
&lt;td&gt;197.00&lt;/td&gt;
&lt;td&gt;Comparable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Demo Shop B&lt;/td&gt;
&lt;td&gt;192.00&lt;/td&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;td&gt;192.00&lt;/td&gt;
&lt;td&gt;Comparable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Demo Shop C&lt;/td&gt;
&lt;td&gt;188.00&lt;/td&gt;
&lt;td&gt;Unknown&lt;/td&gt;
&lt;td&gt;Unknown&lt;/td&gt;
&lt;td&gt;Retain, but do not rank&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sorting item prices gives &lt;strong&gt;C, A, B&lt;/strong&gt;. Sorting the comparable delivered totals gives &lt;strong&gt;B, A&lt;/strong&gt;, with C unresolved. B is the lowest known delivered total among these rows, not a proven cheapest offer across all shops. C's missing shipping must not silently become free delivery. In CSV, leave unknown numeric cells empty and add a separate review/status note; do not insert a numeric zero or mix the word “Unknown” into a numeric calculation.&lt;/p&gt;

&lt;p&gt;Where price and shipping are both explicit, you can check their sum against the returned total. If values conflict, or shipping terms are unclear, flag the row for source review rather than silently replacing the returned value. The &lt;a href="https://apify.com/tubetext/idealo-price-scraper/input-schema" rel="noopener noreferrer"&gt;current input&lt;/a&gt; caps returned offers at your selected limit, so this table describes the collected set, not every seller in the market. EUR totals from different countries still need delivery, tax and product checks; GBP and EUR require a recorded exchange-rate date and conversion method before any cross-currency ranking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compare two snapshots you collected yourself
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Save both original exports, their collection times and run references. Keep the reviewed product list, markets and offer limit consistent. A later keyword search can select different products, so it is not a substitute for a fixed-product watchlist.&lt;/li&gt;
&lt;li&gt;Match the product and market, then review the shop, offer title and source link for the same variant, condition and delivery basis. The &lt;a href="https://apify.com/tubetext/idealo-price-scraper" rel="noopener noreferrer"&gt;Actor's FAQ&lt;/a&gt; says marketplace offers are recorded under the marketplace name; individual seller names are not collected. The schema does not document a durable seller ID or offer ID. Do not merge all rows named eBay, or assume an unchanged title/link proves the same underlying seller. Keep ambiguous matches unresolved.&lt;/li&gt;
&lt;li&gt;Calculate changes only for reviewed matches with comparable values at both times. For example, if fictional Shop B changes from item &lt;strong&gt;192 + shipping 0 = 192 EUR&lt;/strong&gt; at observation A to &lt;strong&gt;190 + 5 = 195 EUR&lt;/strong&gt; at observation B, its item price fell by 2 EUR but its delivered total rose by 3 EUR. If Shop C has a total only in the second snapshot, its delivered-price change remains unknown.&lt;/li&gt;
&lt;li&gt;Label unmatched rows “newly observed,” “not observed in this snapshot” or “needs review.” Missing rows, errors or a position outside the offer limit do not prove a shop stopped selling, and they are not zero prices. Compare each offer separately before summarizing the market.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This builds history from your own saved observations. It does not retrieve earlier dates you never collected, establish native historical backfill, or make a run-completion webhook into a price-change alert. The comparisons are downstream work in your spreadsheet or database. No new Actor run was performed for this worked example; review the cost below before collecting your first small snapshot.&lt;/p&gt;

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

&lt;p&gt;As verified on October 23, 2026, the Apify Free-plan rate is &lt;strong&gt;$0.003 per delivered product-market&lt;/strong&gt;, including its summary and shop offers up to your selected limit. Three delivered product-markets therefore incur $0.009 in result-event fees; 1,000 products in two markets incur $6 in result-event fees if all 2,000 checks deliver results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actor Start is additional:&lt;/strong&gt; $0.00005 per GB of allocated memory, with a minimum of one event. At the current default 512 MB allocation, that is $0.00005 per start. A market with no offers has no product-market result fee, but that does not make the whole run free. Check the &lt;a href="https://apify.com/tubetext/idealo-price-scraper/pricing" rel="noopener noreferrer"&gt;current Pricing tab&lt;/a&gt; for your plan and any other applicable account or service charges before scheduling.&lt;/p&gt;

&lt;p&gt;If you only need the price summary, turn off offer rows (&lt;code&gt;includeOfferRows: false&lt;/code&gt;); billing remains per product-market. Without product links, &lt;code&gt;searchQueries&lt;/code&gt; discovers top matches on idealo.de. Review those matches before using them for a fixed-product comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it daily
&lt;/h2&gt;

&lt;p&gt;Save a reviewed input as an Apify task and use an Apify schedule when you need recurring snapshots. Keep each run's dataset and collection time so your own spreadsheet or database can compare dates. A run-completion webhook reports that a run finished; detecting a price change or sending a threshold alert requires downstream comparison logic.&lt;/p&gt;

&lt;p&gt;Missing offers or failed rows should stay separate from comparable prices, not become a zero price or an assumption that nothing changed. Start with a small product list, inspect the source offers, and review the cost before enabling a recurring schedule.&lt;/p&gt;

&lt;p&gt;Questions or a market you need? Open an issue on the Actor's page. I read every one.&lt;/p&gt;

</description>
      <category>api</category>
      <category>ecommerce</category>
      <category>webscraping</category>
      <category>pricing</category>
    </item>
    <item>
      <title>Agoda reviews API: Booking.com reviews via Agoda and event costs</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Tue, 13 Oct 2026 16:09:13 +0000</pubDate>
      <link>https://dev.to/lmslay/an-agoda-and-bookingcom-reviews-api-for-reputation-dashboards-real-output-real-cost-3o5l</link>
      <guid>https://dev.to/lmslay/an-agoda-and-bookingcom-reviews-api-for-reputation-dashboards-real-output-real-cost-3o5l</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apify.com/tubetext" rel="noopener noreferrer"&gt;TubeText&lt;/a&gt;. This post uses our Agoda reviews Actor on Apify. The output examples below are from the original October 2026 article. Pricing and coverage notes were rechecked on 23 October 2026; this update does not report a new test run.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you build a hotel reputation dashboard or a guest-feedback report, you need review text and source labels, not just an overall score. This Agoda reviews API returns Agoda reviews plus the Booking.com reviews that Agoda displays for the property. It does not read every Booking.com review directly, guarantee both sources for every hotel, or post replies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Export Agoda reviews and Booking.com reviews shown on Agoda
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://apify.com/tubetext/agoda-reviews-scraper" rel="noopener noreferrer"&gt;Agoda &amp;amp; Booking.com Hotel Reviews Scraper&lt;/a&gt; takes Agoda hotel links (or hotel IDs, or names) and returns one row per review, plus a hotel summary row. From a back end it's a single HTTP call to the Apify 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 &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/tubetext~agoda-reviews-scraper/run-sync-get-dataset-items?token=&lt;/span&gt;&lt;span class="nv"&gt;$APIFY_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"hotels":["https://www.agoda.com/the-peninsula-bangkok/hotel/bangkok-th.html"],"sources":["agoda","booking"],"sort":"recent","maxReviewsPerHotel":15}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What comes back
&lt;/h2&gt;

&lt;p&gt;The hotel summary row (shortened) has the score breakdown that dashboards usually chart:&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;"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;"hotel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hotelName"&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 Peninsula Bangkok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewScore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewsCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5314&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subScores"&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;"Cleanliness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9.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;"Facilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Room comfort and quality"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9.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;"Location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Value for money"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewSources"&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;"Agoda"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Booking.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An Agoda review row:&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;"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;"review"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Agoda"&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;9.2&lt;/span&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;"Always a great option"&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;"We have visited the Peninsula Bangkok multiple times as it never fails in quality..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewDate"&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-09-30T18:16:09Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stayMonth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"September 2026"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nights"&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;"travelerType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Group"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"roomType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Grand Deluxe Room"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewerCountry"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Australia"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"charged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Booking.com review displayed on Agoda comes out in the same schema. Booking's "liked" and "disliked" fields are kept separately, which is handy for sentiment work:&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;"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;"review"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Booking.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"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;"Exceptional"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"liked"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Complimentary boat ride to ICONSIAM every 30 minutes was so convenient"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewDate"&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-09-16T17:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"travelerType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Solo traveler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"charged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reviewer names aren't collected. You get the review content, the trip context (traveler type, room, nights, country) and the hotel's reply when there is one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost breakdown: reviews, hotel summaries and optional AI
&lt;/h2&gt;

&lt;p&gt;At the Apify Free-plan event rates checked on 23 October 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reviews: $1 per 1,000 delivered review rows.&lt;/li&gt;
&lt;li&gt;Hotel summary: $0.003 per delivered hotel summary row.&lt;/li&gt;
&lt;li&gt;Optional AI report: $0.05 per hotel, only when requested and delivered.&lt;/li&gt;
&lt;li&gt;Actor Start: $0.00005 per event, with one event per GB of Actor memory and a minimum of one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The original 15-review example corresponds to $0.015 for reviews + $0.003 for the hotel summary = $0.018 in result events, before the separate start event(s). Its reported 20-second runtime was one historical observation, not a speed guarantee.&lt;/p&gt;

&lt;p&gt;For a volume example, 1,000 hotels × 20 returned reviews = 20,000 reviews, or $20. If each hotel also returns one summary, add $3: $23 in result events, before optional AI and start events. Enabling a delivered AI report for all 1,000 hotels would add $50. Higher Apify plans have different event rates; check the &lt;a href="https://apify.com/tubetext/agoda-reviews-scraper/pricing" rel="noopener noreferrer"&gt;current pricing&lt;/a&gt; and the run's charge summary.&lt;/p&gt;

&lt;p&gt;A status row marked &lt;code&gt;charged: false&lt;/code&gt; has no result-event charge for that item. The separate start event may still apply, so an empty or unsuccessful result is not a promise that the total run bill is zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning reviews into a report
&lt;/h2&gt;

&lt;p&gt;If you don't want to run your own LLM step, set &lt;code&gt;aiInsights: true&lt;/code&gt;. It adds one English report per hotel (top complaints, praise and suggested actions) for $0.05 at the Free-plan event rate, using up to 300 reviews. The report describes the selected sample; complaint shares are not hotel-wide prevalence, and suggested actions need human review. For dashboards I'd still store the raw rows and summarize on your side, but it's a quick way to see whether the data answers your question before you build anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling it
&lt;/h2&gt;

&lt;p&gt;On Apify you can save the input as a task, put it on a schedule, and add a webhook that calls your endpoint when the run finishes. Your service then fetches the dataset items by run ID. Keep the raw &lt;code&gt;source&lt;/code&gt;, property identifier, review identifier when present, review date and collection time so the report can be traced back to its input.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;sort: "recent"&lt;/code&gt; and &lt;code&gt;startDate&lt;/code&gt; to restrict the review window. A date filter is not persistent cross-run deduplication: overlapping windows can return an already-seen review. Store and compare review identifiers in your own workflow, and decide how to handle edits or missing identifiers before sending alerts. Do not interpret a missing hotel reply as proof that a guest has never been answered elsewhere.&lt;/p&gt;

&lt;p&gt;For a manual first look, export the Reviews and Hotels views as CSV or Excel. Keep review-source labels in the export, and do not combine the number of sampled reviews with the hotel's total review count as if they were the same measure.&lt;/p&gt;

&lt;p&gt;Questions or a field you're missing? Open an issue on the Actor's page. I read every one.&lt;/p&gt;

</description>
      <category>api</category>
      <category>travel</category>
      <category>webscraping</category>
      <category>saas</category>
    </item>
    <item>
      <title>Give your Dify workflows TikTok Shop, AliExpress and video transcript tools</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Tue, 13 Oct 2026 15:09:52 +0000</pubDate>
      <link>https://dev.to/lmslay/give-your-dify-workflows-tiktok-shop-aliexpress-and-video-transcript-tools-2e3j</link>
      <guid>https://dev.to/lmslay/give-your-dify-workflows-tiktok-shop-aliexpress-and-video-transcript-tools-2e3j</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apify.com/tubetext" rel="noopener noreferrer"&gt;TubeText&lt;/a&gt; and wrote this Dify plugin. It's free and open source. The tools bill per result to your own Apify account.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dify is great at the LLM part of a workflow. The hard part is getting real data in: a product's sales and stock, AliExpress prices, or what a video actually says. The TubeText plugin adds four tools to Dify for exactly that. Each one runs an Apify Actor with your own token and returns clean JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;You give it&lt;/th&gt;
&lt;th&gt;You get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TikTok Shop Products&lt;/td&gt;
&lt;td&gt;product, store or category links (US store)&lt;/td&gt;
&lt;td&gt;price, discount, items sold, rating, stock per SKU, shop stats&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AliExpress Search&lt;/td&gt;
&lt;td&gt;up to 20 keywords&lt;/td&gt;
&lt;td&gt;price, items sold, rating, ships-from country, Choice/deal badges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Video Transcript&lt;/td&gt;
&lt;td&gt;YouTube and TikTok links, mixed&lt;/td&gt;
&lt;td&gt;transcript per video (captions, or Whisper AI if you turn it on)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Get Run Results&lt;/td&gt;
&lt;td&gt;a run ID&lt;/td&gt;
&lt;td&gt;results of a long run, with paging&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Setup (2 minutes)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a free Apify account and copy your API token from &lt;strong&gt;Console → Settings → API &amp;amp; Integrations&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In Dify, install &lt;strong&gt;TubeText&lt;/strong&gt; from the Marketplace.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Tools → TubeText → Authorize&lt;/strong&gt; and paste the token. A wrong token is rejected right there with a clear message, so you'll know immediately.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Workflow example: "what's the hook?" for any video
&lt;/h2&gt;

&lt;p&gt;The simplest useful workflow has three nodes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start&lt;/strong&gt;: one input, &lt;code&gt;video_url&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TubeText → Video Transcript&lt;/strong&gt;: map &lt;code&gt;video_url&lt;/code&gt; into &lt;em&gt;Links&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM&lt;/strong&gt;: prompt it with the tool's &lt;code&gt;text&lt;/code&gt; output, e.g. &lt;em&gt;"Here is a short-form video transcript. Quote the hook (first sentence), name the selling points, and suggest a stronger hook."&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tool returns &lt;code&gt;text&lt;/code&gt; (all transcripts joined, ready for the LLM node) plus &lt;code&gt;json&lt;/code&gt;, which holds the items, the count, and each Apify run's ID and URL.&lt;/p&gt;

&lt;p&gt;In my test, one call with one YouTube link and one TikTok link took &lt;strong&gt;26 seconds&lt;/strong&gt;. The plugin splits the links between the YouTube and TikTok Actors and runs both in parallel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow example: AliExpress price check by market
&lt;/h2&gt;

&lt;p&gt;Add &lt;strong&gt;AliExpress Search&lt;/strong&gt; with a keyword, a ship-to country and a currency. I tested Germany / EUR, sorted by orders, 3 results. You get one row per product with the price in that currency, items sold, rating and where it ships from. Feed that into an LLM node to write a short "price range and best seller" summary, or into a code node to flag products under a target price.&lt;/p&gt;

&lt;p&gt;A detail that matters for price research: AliExpress shows big new-shopper discounts that most buyers never get. The tool flags these deals and sponsored results, and can skip them.&lt;/p&gt;

&lt;h2&gt;
  
  
  In an agent
&lt;/h2&gt;

&lt;p&gt;Enable the TubeText tools in an agent app. Each tool has a description that tells the model when to use it. Prompts it's built for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Get the transcript of this TikTok and tell me what the hook is: [link]"&lt;/li&gt;
&lt;li&gt;"Find yoga mats on AliExpress between $5 and $20, sorted by orders"&lt;/li&gt;
&lt;li&gt;"How many units has this TikTok Shop product sold, and which variant has the most stock? [link]"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(I tested the tools in workflows on a self-hosted Dify. I haven't run agent mode with a model yet, so tell me if a prompt misfires.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Long runs don't block your workflow
&lt;/h2&gt;

&lt;p&gt;Each call waits up to &lt;strong&gt;Max Wait&lt;/strong&gt; seconds (240 by default). If a run takes longer, say a whole YouTube channel, it keeps running on Apify, and the tool returns the run ID right away. Later, a &lt;strong&gt;Get Run Results&lt;/strong&gt; node fetches the rows, with offset and limit for paging. I tested this with Max Wait set to 3 seconds: the tool returned RUNNING plus the run ID, and Get Run Results returned the finished data afterwards.&lt;/p&gt;

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

&lt;p&gt;The plugin is free. These are Apify Free-plan USD rates checked on &lt;strong&gt;23 October 2026&lt;/strong&gt;, not an all-in workflow quote. Dify/model-provider usage is separate.&lt;/p&gt;

&lt;p&gt;Choose the commerce path before estimating the bill:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A US TikTok Shop stock review:&lt;/strong&gt; &lt;a href="https://apify.com/tubetext/tiktok-shop-product-scraper/pricing" rel="noopener noreferrer"&gt;TikTok Shop pricing&lt;/a&gt; is $4 per 1,000 products with full details. Store/category listing cards are $1.50 per 1,000 when &lt;strong&gt;Include Details&lt;/strong&gt; is off, but those cards do not include per-SKU stock. For a per-variant review, keep details on and choose &lt;strong&gt;Full&lt;/strong&gt; output: the plugin's Simplified field list retains total stock, not the SKU array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An AliExpress price shortlist:&lt;/strong&gt; &lt;a href="https://apify.com/tubetext/aliexpress-search-scraper/pricing" rel="noopener noreferrer"&gt;AliExpress pricing&lt;/a&gt; is $2.50 per 1,000 search-result products. Start with one keyword, a fixed ship-to country/currency and a small &lt;strong&gt;Max Products per Keyword&lt;/strong&gt;. Set &lt;strong&gt;Skip New-Shopper Deals&lt;/strong&gt; explicitly; turn on &lt;strong&gt;Skip Sponsored&lt;/strong&gt; if you want organic results. The Dify tool exposes search results, not the underlying Actor's separate product-detail mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep each platform's product ID and source URL. Similar titles or images do not prove that two listings are the same SKU or supplier. Verify the variant, pack size, destination, currency and offer eligibility before comparing. A displayed search price is not a verified checkout total or landed cost; do not treat missing shipping, tax or stock data as zero.&lt;/p&gt;

&lt;p&gt;For the video tool, current caption-result rates are &lt;a href="https://apify.com/tubetext/youtube-transcript-fast/pricing" rel="noopener noreferrer"&gt;YouTube: $4 per 1,000&lt;/a&gt; and &lt;a href="https://apify.com/tubetext/tiktok-transcript/pricing" rel="noopener noreferrer"&gt;TikTok: $1.50 per 1,000&lt;/a&gt;. Optional AI transcription is $0.006 per started audio minute at this plan tier; check the selected Actor's billing conditions before enabling it.&lt;/p&gt;

&lt;p&gt;Items excluded from a result fee do &lt;strong&gt;not&lt;/strong&gt; make the entire run free. All four underlying Actors currently list an &lt;strong&gt;Actor Start&lt;/strong&gt; fee of $0.00005 per GB of memory, with a one-event minimum, and other applicable charges may apply. TikTok Transcript lists a scheduled startup-rate change to $0.0011 per GB from &lt;strong&gt;4 November 2026, 03:53:50 UTC&lt;/strong&gt;; check the live Pricing tab before recurring use.&lt;/p&gt;

&lt;p&gt;Free-plan credit can cover eligible charges only while credit remains. Check the actual run's usage before increasing volume. A timed-out Dify call can still be running on Apify: keep its run ID and use &lt;strong&gt;Get Run Results&lt;/strong&gt;, rather than starting a duplicate run just to retrieve the same job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits worth knowing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TikTok Shop needs links or product IDs. It doesn't search by keyword, and it covers the US store only.&lt;/li&gt;
&lt;li&gt;AliExpress returns search-result data, not product-page details or store names.&lt;/li&gt;
&lt;li&gt;The plugin only calls &lt;code&gt;api.apify.com&lt;/code&gt;. It never logs in to TikTok, AliExpress or YouTube.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/LMSlay/dify-plugin-tubetext" rel="noopener noreferrer"&gt;github.com/LMSlay/dify-plugin-tubetext&lt;/a&gt;. Issues and ideas are welcome there.&lt;/p&gt;

</description>
      <category>dify</category>
      <category>ai</category>
      <category>ecommerce</category>
      <category>nocode</category>
    </item>
    <item>
      <title>How to connect Apify to Claude (MCP) and give it YouTube transcripts in 5 minutes</title>
      <dc:creator>LMSlay</dc:creator>
      <pubDate>Tue, 13 Oct 2026 13:56:35 +0000</pubDate>
      <link>https://dev.to/lmslay/how-to-connect-apify-to-claude-mcp-and-give-it-youtube-transcripts-in-5-minutes-22bd</link>
      <guid>https://dev.to/lmslay/how-to-connect-apify-to-claude-mcp-and-give-it-youtube-transcripts-in-5-minutes-22bd</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apify.com/tubetext" rel="noopener noreferrer"&gt;TubeText&lt;/a&gt;, a set of pay-per-result Apify Actors. The example below uses one of them. The setup works the same for any Actor in Apify Store.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Claude can't watch a YouTube video. If you paste a link, it will either refuse or guess from the title. With the Apify MCP server connected, Claude can fetch the actual transcript and work from that. Caption-based transcription costs a fraction of a cent per video on the Free plan. Videos without captions can instead trigger per-minute AI transcription; check the Actor's current &lt;a href="https://apify.com/tubetext/youtube-transcript-fast/pricing" rel="noopener noreferrer"&gt;Pricing tab&lt;/a&gt; and input settings. Claude access is separate from Apify usage, and you don't write any code.&lt;/p&gt;

&lt;p&gt;Here is the setup, plus what I checked myself.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Claude (Desktop or claude.ai) with custom connectors available on your plan&lt;/li&gt;
&lt;li&gt;A free Apify account. The free plan includes $5 of monthly usage, enough for about 1,200 transcripts with captions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: build your server URL
&lt;/h2&gt;

&lt;p&gt;The Apify MCP server lives at &lt;code&gt;https://mcp.apify.com&lt;/code&gt;. With no parameters, it loads a general tool set: Actor search, docs search, a web browser Actor and a few helpers. Claude then has to search Apify Store for a suitable tool every time.&lt;/p&gt;

&lt;p&gt;For a specific job, give Claude exactly the tool it needs with the &lt;code&gt;tools&lt;/code&gt; parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://mcp.apify.com?tools=tubetext/youtube-transcript-fast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can list several Actors separated by commas. The &lt;a href="https://mcp.apify.com" rel="noopener noreferrer"&gt;MCP configurator&lt;/a&gt; builds the URL for you if you'd rather click than type.&lt;/p&gt;

&lt;p&gt;Why bother? When I asked the server's own &lt;code&gt;search-actors&lt;/code&gt; tool for "youtube transcript", it returned ten different Actors with different inputs and prices. With the tool pinned in the URL, Claude skips that step and calls the same Actor every time, with the same input format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: add it to Claude as a custom connector
&lt;/h2&gt;

&lt;p&gt;Per Apify's Claude Desktop docs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In Claude, open &lt;strong&gt;Settings → Connectors&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add → Add custom connector&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Name it &lt;code&gt;Apify&lt;/code&gt; and paste your URL from step 1 as the &lt;strong&gt;Remote MCP server URL&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Continue&lt;/strong&gt;, keep the detected settings, then &lt;strong&gt;Add&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A browser window opens. Sign in to Apify and approve access.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last step is OAuth, so you never paste an API token into Claude. I checked that the server enforces this: calling the URL above without signing in returns &lt;code&gt;401&lt;/code&gt; with an OAuth challenge. Remote connectors run on Anthropic's side, so the same connector also works on claude.ai.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: ask Claude something
&lt;/h2&gt;

&lt;p&gt;Start a new chat and try:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Get the transcript of &lt;a href="https://www.youtube.com/watch?v=jNQXAC9IVRw" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=jNQXAC9IVRw&lt;/a&gt; and summarize it in one sentence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Behind the scenes Claude calls the Actor, which returns a JSON row per video. Here is the real output for that link (YouTube's first ever video), shortened:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Me at the zoo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"channelName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jawed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"durationSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"captions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"wordCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestampedText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[00:01] All right, so here we are, in front of the elephants&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;[00:05] the cool thing about these guys is that they have really...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;[00:07] really really long trunks ..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&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 run took a few seconds and was billed one transcript ($0.004 on the free plan).&lt;/p&gt;

&lt;p&gt;Other prompts that work well with this one tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Pull the transcripts of the last 10 videos on @channel and list the topics they keep coming back to."&lt;/li&gt;
&lt;li&gt;"Here are 5 product review videos. Make a table of the pros and cons each reviewer mentions, with timestamps."&lt;/li&gt;
&lt;li&gt;"Turn this talk into a blog post outline and quote the three strongest lines."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Things worth knowing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Videos without captions:&lt;/strong&gt; when enabled, Whisper AI fallback is billed per started minute only when a transcript is delivered. Set &lt;code&gt;aiFallback&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; for captions-only requests. &lt;code&gt;maxAiMinutesPerVideo&lt;/code&gt; sets the maximum eligible video length: longer videos are skipped, not partially transcribed. Check your actual input settings before running.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long jobs:&lt;/strong&gt; the MCP &lt;code&gt;call-actor&lt;/code&gt; tool waits up to 45 seconds. For a whole channel, Claude gets a run ID back and can fetch the results with &lt;code&gt;get-dataset-items&lt;/code&gt; once the run finishes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spend control:&lt;/strong&gt; you can pass &lt;code&gt;maxTotalChargeUsd&lt;/code&gt; as a run option, so a single run can't go over a budget you set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick tools on purpose:&lt;/strong&gt; for production use, Apify recommends listing tools explicitly instead of relying on the defaults, so behavior doesn't change when the defaults do.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Same pattern, other data
&lt;/h2&gt;

&lt;p&gt;Swap the Actor name in the URL and Claude gets a different capability. TikTok or Instagram transcripts, Amazon products and Google Flights prices all work the same way. The full list of TubeText tools is on &lt;a href="https://apify.com/tubetext" rel="noopener noreferrer"&gt;our Apify profile&lt;/a&gt;, and Apify Store has thousands more.&lt;/p&gt;

&lt;p&gt;If something breaks, open an issue on the Actor's page. I read every one.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>mcp</category>
      <category>ai</category>
      <category>youtube</category>
    </item>
    <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 have no transcript fee.&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). If optional on-screen text is enabled and text is found, that separate event can still be billed; any Actor Start charge is separate too.&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. On the Free plan, a delivered reel transcript costs $0.006 including its first 3 minutes of audio; longer audio costs $0.003 per extra started minute. Private, deleted and failed reels have no transcript-result fee. Optional on-screen-text events and any Actor Start charge are separate, so no transcript fee does not necessarily mean a zero-cost run. See the current &lt;a href="https://apify.com/tubetext/instagram-reels-transcript/pricing" rel="noopener noreferrer"&gt;Pricing tab&lt;/a&gt; before running a batch.&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 API: booking-site prices and a 90-day price calendar</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;Need Google Hotels prices as JSON or CSV for a travel dashboard or a competitor-rate comparison? This tutorial returns the booking-site offers Google shows for your selected dates, then builds a price calendar for a hotel. It reads Google Hotels; it is not Google's official API or a booking service. Availability and rates can change before you book.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Get hotel prices by booking site for a city and fixed dates
&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;. The original Lisbon example had 9–28 booking sites per hotel. That is a historical sample, not a minimum vendor count or a guarantee of coverage for another search.&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 the vendor prices returned for that date. Sort the rows by &lt;code&gt;checkIn&lt;/code&gt; before charting them. Dates with no rates come back as &lt;code&gt;no_rates&lt;/code&gt; and do not incur the calendar-date event charge; run-start billing is separate.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Track the same event-weekend stay across collection dates
&lt;/h2&gt;

&lt;p&gt;“How much did this weekend's hotel price change since yesterday?” needs two observations of &lt;strong&gt;the same stay&lt;/strong&gt;. Keep check-in and check-out fixed; change only when you collect the quote. A calendar answers a different question: which check-in date is cheaper? For example, &lt;a href="https://serpapi.com/google-hotels-price-calendar-api" rel="noopener noreferrer"&gt;SerpApi's calendar documentation&lt;/a&gt; describes prices for one-night stays beginning on different dates. Those dates are stay dates, not a history of what yesterday's search returned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build the comparison before calculating a change
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Save the fixed-date input from step 1 with explicit &lt;code&gt;checkInDate&lt;/code&gt;, &lt;code&gt;checkOutDate&lt;/code&gt;, &lt;code&gt;adults&lt;/code&gt; and &lt;code&gt;currency&lt;/code&gt;, plus &lt;code&gt;includeBookingOffers: true&lt;/code&gt;. Keep the destination and search settings unchanged. Archive each returned dataset separately, with a collection timestamp and run reference that &lt;strong&gt;you add&lt;/strong&gt;. The documented output does not supply a historical observation series or backfill earlier quotes.&lt;/li&gt;
&lt;li&gt;Flatten &lt;code&gt;bookingOffers&lt;/code&gt; into one row per returned offer. Carry the parent hotel's &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;googleHotelsUrl&lt;/code&gt;, &lt;code&gt;checkIn&lt;/code&gt;, &lt;code&gt;checkOut&lt;/code&gt;, &lt;code&gt;nights&lt;/code&gt;, &lt;code&gt;adults&lt;/code&gt; and &lt;code&gt;currency&lt;/code&gt;; retain the offer's &lt;code&gt;vendor&lt;/code&gt;, &lt;code&gt;roomTypes&lt;/code&gt;, &lt;code&gt;pricePerNight&lt;/code&gt; and &lt;code&gt;totalPrice&lt;/code&gt;. Keep raw values too. These fields are documented in the &lt;a href="https://apify.com/tubetext/google-hotels-scraper/output-schema" rel="noopener noreferrer"&gt;current output schema&lt;/a&gt;, but they are optional, so missing data must remain missing.&lt;/li&gt;
&lt;li&gt;Match hotel identity, stay, occupancy, currency, booking source, room and rate conditions. Use the returned &lt;code&gt;id&lt;/code&gt; and URL as matching evidence, not a promise of a permanent identifier. Do not join by hotel name alone or compare whichever vendor happens to be cheapest each day. &lt;code&gt;roomTypes&lt;/code&gt; text does not establish that a specific room/rate plan stayed identical. Record room count, children, meal plan and cancellation/payment terms in analyst-maintained columns after checking the source. The &lt;a href="https://apify.com/tubetext/google-hotels-scraper/input-schema" rel="noopener noreferrer"&gt;input schema&lt;/a&gt; documents &lt;code&gt;adults&lt;/code&gt;, not controls for all those dimensions.&lt;/li&gt;
&lt;li&gt;Check the tax basis for the specific offer. Preserve the hotel-row &lt;code&gt;priceIncludesTaxesAndFees&lt;/code&gt; value, including &lt;code&gt;null&lt;/code&gt;; do not automatically copy it to every vendor offer. If offer-level inclusion, occupancy or room/terms cannot be verified, label the pair &lt;strong&gt;not comparable / needs review&lt;/strong&gt;, leave the change blank and retain the observations.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Worked comparison: two fictional observations
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Everything below is illustrative, not a test result or a real hotel quote.&lt;/strong&gt; Assume an analyst has independently verified the following matching details for both observations. These are the analyst's comparison keys and review notes, not additional Actor output fields.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fixed comparison key&lt;/th&gt;
&lt;th&gt;Value for both observations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hotel&lt;/td&gt;
&lt;td&gt;Example Riverside Hotel, Lisbon; same property independently checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stay&lt;/td&gt;
&lt;td&gt;Check-in 2026-11-20, check-out 2026-11-22; 2 nights&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Occupancy&lt;/td&gt;
&lt;td&gt;1 room, 2 adults, no children; independently checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Room and rate terms&lt;/td&gt;
&lt;td&gt;Standard double, breakfast excluded, non-refundable, pay now; independently checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Booking source&lt;/td&gt;
&lt;td&gt;Example Travel, the same fictional vendor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Currency and offer tax basis&lt;/td&gt;
&lt;td&gt;USD; both displayed offers independently confirmed to include taxes and mandatory fees&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use an analyst-assigned label such as &lt;code&gt;event_stay_A&lt;/code&gt; for this exact combination. It is not a hotel ID returned by the API. The unknown &lt;strong&gt;breakdown amounts&lt;/strong&gt; below remain unknown even though inclusion in these fictional totals has been confirmed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Collection time (UTC)&lt;/th&gt;
&lt;th&gt;Comparison label&lt;/th&gt;
&lt;th&gt;Nightly quote (USD)&lt;/th&gt;
&lt;th&gt;Stay total (USD)&lt;/th&gt;
&lt;th&gt;Tax amount / fee amount&lt;/th&gt;
&lt;th&gt;Review&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2026-10-21 09:00&lt;/td&gt;
&lt;td&gt;event_stay_A&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;360&lt;/td&gt;
&lt;td&gt;unknown / unknown&lt;/td&gt;
&lt;td&gt;Comparable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-10-22 09:00&lt;/td&gt;
&lt;td&gt;event_stay_A&lt;/td&gt;
&lt;td&gt;198&lt;/td&gt;
&lt;td&gt;396&lt;/td&gt;
&lt;td&gt;unknown / unknown&lt;/td&gt;
&lt;td&gt;Comparable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After that review, the two-night stay increased by &lt;strong&gt;396 - 360 = USD 36&lt;/strong&gt;, or &lt;strong&gt;(396 - 360) / 360 × 100 = 10%&lt;/strong&gt;. The nightly change is USD 18, also 10%; do not compare one observation's nightly price with the other's stay total. Use the returned stay total when available rather than replacing it with a rounded nightly rate multiplied by nights. A zero or missing baseline has no valid percentage change.&lt;/p&gt;

&lt;p&gt;For a real event-weekend shortlist, this tells you which verified offer to recheck, not whether to book. If the second observation has no matching offer, record &lt;strong&gt;not observed&lt;/strong&gt; rather than zero, unchanged or sold out. If the room, vendor or terms change, start a separate comparison. You can build a history only from observations you retain; returned coverage and a later bookable price are not guaranteed.&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;For a comparable price history, keep the stay dates, guest count and currency fixed, save each run's observation time, and compare &lt;code&gt;pricePerNight&lt;/code&gt; for the same hotel &lt;code&gt;id&lt;/code&gt;. A changing default stay date is a different search.&lt;/li&gt;
&lt;li&gt;Treat nightly prices and stay totals as different measures. Keep the dates, room details and tax/fee flag alongside the price; the cheapest headline offer is not proof that cancellation rules or room conditions match.&lt;/li&gt;
&lt;li&gt;To export without code, run the Actor in Apify and use the dataset's Export option for CSV or Excel. Overlapping destination searches may contain the same hotel, so deduplicate your combined table by hotel and stay.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Pricing checked on 23 October 2026: at the Apify Free-plan event rates, $3 per 1,000 hotels with a price, an additional $2 per 1,000 hotels whose booking-site breakdown is delivered, and $3 per 1,000 priced calendar dates. Higher plans have their own rates.&lt;/p&gt;

&lt;p&gt;The separate Actor Start event is $0.00005 per event, with one event per GB of Actor memory and a minimum of one. No-rate dates and failed searches have no corresponding result-event charge, but that does not make the whole run free.&lt;/p&gt;

&lt;p&gt;For example, 20 priced hotels with 20 delivered booking-site breakdowns cost $0.06 + $0.04 = $0.10 in result events. A 30-day calendar for 5 hotels has at most 150 priced dates, or $0.45 in calendar events. Add the start event(s) in either case. These are event-charge examples, not measured bills or a guarantee of returned rows. Check the &lt;a href="https://apify.com/tubetext/google-hotels-scraper/pricing" rel="noopener noreferrer"&gt;current pricing&lt;/a&gt; and the run's charge summary.&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>
  </channel>
</rss>
