<?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: Integration Yard</title>
    <description>The latest articles on DEV Community by Integration Yard (@integrationyard).</description>
    <link>https://dev.to/integrationyard</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%2F4195559%2F76cc0ed3-3b8e-4473-80f6-573b7bac2b07.png</url>
      <title>DEV Community: Integration Yard</title>
      <link>https://dev.to/integrationyard</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/integrationyard"/>
    <language>en</language>
    <item>
      <title>Catch Google Merchant Center Disapprovals Before Google Does</title>
      <dc:creator>Integration Yard</dc:creator>
      <pubDate>Thu, 22 Oct 2026 17:08:51 +0000</pubDate>
      <link>https://dev.to/integrationyard/catch-google-merchant-center-disapprovals-before-google-does-538g</link>
      <guid>https://dev.to/integrationyard/catch-google-merchant-center-disapprovals-before-google-does-538g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most "Mismatched value (page crawl) [price]" and "Mismatched availability" disapprovals in Google Merchant Center come from &lt;strong&gt;drift&lt;/strong&gt;: your product feed and your live storefront briefly disagree, and Googlebot crawls at that moment.&lt;/li&gt;
&lt;li&gt;Drift risk is everywhere in real catalogs. In four public Shopify stores we probed on Oct 20, 2026, &lt;strong&gt;15–85% of variants were on sale&lt;/strong&gt; (compare-at price set) and &lt;strong&gt;13–82% were sold out&lt;/strong&gt;. One brand's 250 products expanded to &lt;strong&gt;2,720 variants, each a separate feed item&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Google says it re-crawls disapproved products over "the next few hours or days" and may take &lt;strong&gt;up to 12 hours&lt;/strong&gt; to review a website check, so every drift costs you visibility for a while.&lt;/li&gt;
&lt;li&gt;Do the free manual audit below once. Then automate a &lt;strong&gt;daily storefront-vs-feed diff&lt;/strong&gt;. With DriftGuard, 500 variants with no new drift cost about &lt;strong&gt;$0.10 a check&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's how it usually goes. You change a price in Shopify, start a sale, or sell out of a size. A few days later Merchant Center shows &lt;strong&gt;"Mismatched value (page crawl) [price]"&lt;/strong&gt; or &lt;strong&gt;"Mismatched availability"&lt;/strong&gt;. The product is disapproved, Shopping stops serving it, and if it happens often enough, the account gets a warning about inaccurate prices.&lt;/p&gt;

&lt;p&gt;Google's fix guidance always comes down to one rule: the price and availability in your feed must match your landing page, your structured data and your checkout. The rule is simple. The hard part is noticing that the feed and the store have drifted apart &lt;strong&gt;before Googlebot does&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This guide covers why drift happens, what it costs you, a manual audit you can do today, and how to automate the check. It also includes real data from public Shopify stores on how much of a typical catalog is exposed to drift at any given moment.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: we built DriftGuard, the actor used in part 4. Parts 1–3 are useful with or without it.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What Google actually checks&lt;/li&gt;
&lt;li&gt;Why feeds drift from the storefront&lt;/li&gt;
&lt;li&gt;How exposed is a real catalog? Data from four stores&lt;/li&gt;
&lt;li&gt;The manual audit (do this once, today)&lt;/li&gt;
&lt;li&gt;Who this protects, and what it's worth&lt;/li&gt;
&lt;li&gt;Automate it: storefront vs feed, every day&lt;/li&gt;
&lt;li&gt;Get alerted&lt;/li&gt;
&lt;li&gt;What it costs&lt;/li&gt;
&lt;li&gt;Caveats&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Try it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Google actually checks
&lt;/h2&gt;

&lt;p&gt;Google's &lt;a href="https://support.google.com/merchants/answer/7052112?hl=en" rel="noopener noreferrer"&gt;product data specification&lt;/a&gt; says to &lt;em&gt;"accurately submit the product's price and currency, and match with the price from your landing page, structured data, and at checkout."&lt;/em&gt; The same applies to sale prices and availability. When they don't match:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Google's crawler visits the landing page and reads the visible price and the structured data (JSON-LD or Microdata).&lt;/li&gt;
&lt;li&gt;If those disagree with your feed, the item gets a &lt;strong&gt;mismatched value&lt;/strong&gt; issue and is disapproved.&lt;/li&gt;
&lt;li&gt;After you fix it, Google says it re-crawls the product &lt;em&gt;"over the next few hours or days"&lt;/em&gt; (&lt;a href="https://support.google.com/merchants/answer/12159029?hl=en" rel="noopener noreferrer"&gt;Mismatched product price help page&lt;/a&gt;). A requested website check can take &lt;em&gt;"up to 12 hours"&lt;/em&gt;, and you can't submit a new request during that window.&lt;/li&gt;
&lt;li&gt;If mismatches are systematic, policy reviewers can flag the account for &lt;strong&gt;inaccurate prices&lt;/strong&gt; (&lt;a href="https://support.google.com/merchants/answer/9773429?hl=en" rel="noopener noreferrer"&gt;Google help: inconsistency between feed and landing page&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So every drift costs you some hours of visibility per product. Repeated drift puts the account at risk. Google's own list of common causes includes sales that start or end without a feed update, structured data that disagrees with the page, multiple prices on the page, and prices that change by location, cookie or device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why feeds drift from the storefront
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sync lag&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your feed app pushes updates on its own schedule. Price changes can take hours or days to reach Merchant Center, and deleted variants can linger for weeks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sales and compare-at prices&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The storefront shows the sale price, but the feed still has the regular price, or the sale's effective-date window is in the wrong timezone.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sold-out variants&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The feed says in stock, but the variant sold out an hour ago. "Continue selling when out of stock" may be handled differently by the feed and the theme.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Price-test and B2B apps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A/B pricing apps, wholesale apps and currency converters change what visitors (and Googlebot) see without touching the feed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shopify Markets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;There's a feed per country and prices per market, and one of them doesn't update.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deleted or renamed products&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The product is still in the feed but gone from the store (404, then disapproval), or a new product never made it into the feed at all.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Google's &lt;strong&gt;automatic item updates&lt;/strong&gt; soften minor lag by updating price and availability from the crawl. Google is clear, though, that they're not a fix for systematic mismatches. If too many items mismatch, you need to fix the source.&lt;/p&gt;

&lt;h2&gt;
  
  
  How exposed is a real catalog? Data from four stores
&lt;/h2&gt;

&lt;p&gt;Drift can only happen on fields that &lt;em&gt;change&lt;/em&gt;. To see how much of a real catalog is in a changeable state at any moment, we read the public storefront catalogs of four well-known Shopify brands on Oct 20, 2026 (first 250 products each). We've anonymized them by category.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvzefmum1i08zs599fymq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvzefmum1i08zs599fymq.png" alt="Grouped bar chart of the share of variants on sale and sold out in four Shopify stores on Oct 20 2026: footwear brand 55 percent on sale and 82 percent sold out, bedding brand 17 and 15, cosmetics brand 15 and 21, watch brand 85 and 13" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Store&lt;/th&gt;
&lt;th&gt;Products&lt;/th&gt;
&lt;th&gt;Variants&lt;/th&gt;
&lt;th&gt;On sale (compare-at &amp;gt; price)&lt;/th&gt;
&lt;th&gt;Sold out&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Footwear brand&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;2,720&lt;/td&gt;
&lt;td&gt;1,496 (55%)&lt;/td&gt;
&lt;td&gt;2,238 (82%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bedding brand&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;3,005&lt;/td&gt;
&lt;td&gt;510 (17%)&lt;/td&gt;
&lt;td&gt;442 (15%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cosmetics brand&lt;/td&gt;
&lt;td&gt;245&lt;/td&gt;
&lt;td&gt;695&lt;/td&gt;
&lt;td&gt;105 (15%)&lt;/td&gt;
&lt;td&gt;145 (21%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watch brand&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;212 (85%)&lt;/td&gt;
&lt;td&gt;32 (13%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What this means for your feed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sale prices are the norm, not the exception.&lt;/strong&gt; Every on-sale variant needs &lt;code&gt;price&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;sale_price&lt;/code&gt; in the feed, plus a correct &lt;code&gt;sale_price_effective_date&lt;/code&gt; if the sale is scheduled. When a sale starts or ends, every one of those variants has to change in the feed at the same moment it changes on the site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stock flips are constant.&lt;/strong&gt; A footwear catalog where 82% of size/colour variants are sold out has thousands of availability values that can go stale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variants multiply the work.&lt;/strong&gt; Feeds list each size and colour separately:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7u1u7eoukrhs2p4jqzkm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7u1u7eoukrhs2p4jqzkm.png" alt="Bar chart of products vs variants: footwear brand 250 products to 2,720 variants (10.9 per product), bedding brand 250 to 3,005 (12.0), cosmetics brand 245 to 695 (2.8), watch brand 250 to 250 (1.0)" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A manual spot check of "a few products" covers a tiny fraction of a catalog with 10–12 variants per product. That's why disapprovals feel random. The ones you checked were fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The manual audit (do this once, today)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;In Merchant Center, go to &lt;strong&gt;Products → Needs attention&lt;/strong&gt;. Filter for &lt;em&gt;Mismatched price&lt;/em&gt; and &lt;em&gt;Mismatched availability&lt;/em&gt; and open &lt;strong&gt;View samples&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open a sample product's attributes and compare the submitted values with what Google collected from the page. For variant products, check that the landing URL &lt;strong&gt;includes the variant id&lt;/strong&gt;, so it preselects the advertised variant.&lt;/li&gt;
&lt;li&gt;Open the landing page and confirm that the visible price and stock match the feed.&lt;/li&gt;
&lt;li&gt;Run the URL through Google's &lt;strong&gt;Rich Results Test&lt;/strong&gt;. The &lt;code&gt;Offer&lt;/code&gt; price and availability in your JSON-LD should match too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix the root cause&lt;/strong&gt; (sync schedule, sale timing, theme schema, app conflict), re-fetch the feed, and request a website check if the products were flagged.&lt;/li&gt;
&lt;li&gt;For bulk issues, &lt;strong&gt;download the affected-products CSV&lt;/strong&gt; from &lt;em&gt;Needs attention&lt;/em&gt; and cross-reference it with your feed, as Google's help page suggests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That works for 10 products. With 500+ variants and daily price changes, you need to automate step 3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this protects, and what it's worth
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shopify merchants:&lt;/strong&gt; keep best-sellers live on Google Shopping and free listings instead of losing them for hours or days to a re-crawl.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paid-search and Shopping teams:&lt;/strong&gt; stop wasting budget on campaigns whose top products are quietly disapproved, and protect the account from inaccurate-price warnings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agencies:&lt;/strong&gt; run one daily check per client feed and send clients a drift report before they notice a drop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feed and catalog managers:&lt;/strong&gt; see feed-only (stale) and storefront-only (missing) items, the silent catalog shrinkage that never shows up as an error.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automate it: storefront vs feed, every day
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/dheerajitbhu/driftguard" rel="noopener noreferrer"&gt;DriftGuard&lt;/a&gt; does step 3 at scale. On each run it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reads your live storefront&lt;/strong&gt; as any visitor sees it. No login, no API keys, no app install.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Downloads the feed&lt;/strong&gt; you submit to Google, as RSS/XML or TSV (auto-detected).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matches every feed item to the right variant&lt;/strong&gt; with multi-signal product matching, so renamed products, missing SKUs and multi-country feed ids still line up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reports every difference&lt;/strong&gt; with a severity and a fix hint.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Drift&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;price_mismatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;The most common disapproval cause. Active sale-price windows are respected.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;availability_mismatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;The feed says in stock but the storefront is sold out, or vice versa.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feed_only&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;In the feed but gone from the store: a stale listing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;storefront_only&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;A live product missing from the feed: invisible on Shopping.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title_mismatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;The feed title diverges sharply from the product title.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;attribute_gap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;free section&lt;/td&gt;
&lt;td&gt;Missing GTIN/MPN, brand or image.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Find your feed URL.&lt;/strong&gt; This is the URL your feed app (Simprosys, DataFeedWatch, Mulwi, etc.) publishes and Merchant Center fetches. It's in the feed app's settings, or in Merchant Center under your data source's fetch URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run it once:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&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;"storeUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://your-store.myshopify.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;"feedUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://feeds.your-feed-app.com/your-store/google.xml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"storeCurrency"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxProductsPerStore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxChargeUsd"&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="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;Leave both URLs empty to see a demo run first.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the output.&lt;/strong&gt; Each drift row looks like this:
&lt;/li&gt;
&lt;/ol&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;"driftType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"price_mismatch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&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;"Ceramic Mug - 12oz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MUG-12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"feedItemId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shopify_US_7012345678901_41234567890123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"storefrontValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16.50"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"feedValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"14.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Feed shows 14.00 but the storefront charges 16.50."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fixHint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Update the feed price to match the storefront (or fix the storefront), then re-upload the feed."&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Schedule it.&lt;/strong&gt; Save the input as a Task, then create a Schedule. &lt;code&gt;0 6 * * *&lt;/code&gt; (daily) is enough for most stores. Run it more often around sales and launches, which is exactly when the data above says the most fields change.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Get alerted
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplest:&lt;/strong&gt; on the task, go to &lt;strong&gt;Integrations → Slack&lt;/strong&gt; or &lt;strong&gt;Send email&lt;/strong&gt;, triggered on &lt;em&gt;Run succeeded&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only high-severity drifts (Zapier):&lt;/strong&gt; Apify → &lt;em&gt;Finished Task Run&lt;/em&gt; → Apify → &lt;em&gt;Fetch Dataset Items&lt;/em&gt; → Filter &lt;code&gt;recordType = drift&lt;/code&gt; and &lt;code&gt;severity = high&lt;/code&gt; → Slack or email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make:&lt;/strong&gt; &lt;em&gt;Watch Task Runs&lt;/em&gt; → &lt;em&gt;Get Dataset Items&lt;/em&gt; → filter → Slack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repeat drifts are &lt;strong&gt;reported every run but billed once&lt;/strong&gt;, so a daily schedule doesn't keep charging you for the same unfixed issue.&lt;/p&gt;

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

&lt;p&gt;Pricing is pay-per-event: &lt;strong&gt;$0.001 per run + $0.0002 per variant checked + $0.02 per &lt;em&gt;new&lt;/em&gt; drift.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc153zqij62m1ivez0dhz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc153zqij62m1ivez0dhz.png" alt="Grouped bar chart of cost per run: 500 variants 0.10 dollars with no drift, 0.20 with 5 new drifts, 0.60 with 25; 2,000 variants 0.40, 0.50, 0.90; 5,000 variants 1.00, 1.10, 1.50" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variants&lt;/th&gt;
&lt;th&gt;No new drift&lt;/th&gt;
&lt;th&gt;5 new drifts&lt;/th&gt;
&lt;th&gt;25 new drifts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;td&gt;$0.20&lt;/td&gt;
&lt;td&gt;$0.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;td&gt;$0.40&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;td&gt;$0.90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5,000&lt;/td&gt;
&lt;td&gt;$1.00&lt;/td&gt;
&lt;td&gt;$1.10&lt;/td&gt;
&lt;td&gt;$1.50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;attribute_gap&lt;/code&gt; findings and skipped rows are free, and &lt;code&gt;maxChargeUsd&lt;/code&gt; caps every run. A daily check of 500 variants with no drift is about &lt;strong&gt;$3 a month&lt;/strong&gt;. Compare that with what one disapproved best-seller costs you in Shopping traffic over the hours to days Google takes to re-crawl it.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It compares your storefront with your feed.&lt;/strong&gt; It doesn't log into Merchant Center, so it catches the drift that &lt;em&gt;would&lt;/em&gt; cause disapprovals rather than reading Google's verdict. Theme or JSON-LD problems where the feed and store agree but your schema says something else still need the Rich Results Test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public storefronts only.&lt;/strong&gt; It reads your public storefront and feed, so password-protected stores aren't supported.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Currency.&lt;/strong&gt; Feed prices in a different currency from &lt;code&gt;storeCurrency&lt;/code&gt; are skipped, not flagged. If you use Markets, run one task per country feed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Large catalogs.&lt;/strong&gt; Raise &lt;code&gt;maxProductsPerStore&lt;/code&gt;. Items past the cutoff are reported as skipped, never as false drifts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shopify only&lt;/strong&gt; for the storefront side. For WooCommerce catalogs, see our &lt;a href="https://apify.integrationyard.com/blog/woocommerce-competitor-price-alerts/" rel="noopener noreferrer"&gt;competitor price alerts guide&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;What does "Mismatched value (page crawl) [price]" mean?&lt;/strong&gt;&lt;br&gt;
Google's crawler saw a different price on your landing page (or in its structured data) than the one in your feed. Fix whichever side is wrong, then request a website check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aren't automatic item updates enough?&lt;/strong&gt;&lt;br&gt;
They help with occasional lag by updating price and availability from the crawl. Google says they're not a substitute for accurate data, and widespread mismatches can still lead to disapprovals or account warnings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long does a disapproval last after I fix it?&lt;/strong&gt;&lt;br&gt;
Google says it re-crawls over "the next few hours or days". A requested website check can take up to 12 hours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to install a Shopify app or give API access?&lt;/strong&gt;&lt;br&gt;
No. DriftGuard reads your public storefront, exactly as any visitor sees it, plus your feed URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which feed formats are supported?&lt;/strong&gt;&lt;br&gt;
Google Merchant Center RSS/XML and TSV feeds, auto-detected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How are feed items matched to variants?&lt;/strong&gt;&lt;br&gt;
With multi-signal product matching that combines several identifiers, so it keeps working when SKUs are missing, titles change or you run feeds for several countries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will I be charged every day for the same unfixed problem?&lt;/strong&gt;&lt;br&gt;
No. A drift is billed once when it first appears and reported, free, on later runs until it's fixed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it work for Meta or TikTok catalogs?&lt;/strong&gt;&lt;br&gt;
The check works for any feed in Google's RSS/XML or TSV format. Many Meta catalog feeds use the same format, but it's built and tested for Google Merchant Center.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://apify.com/dheerajitbhu/driftguard" rel="noopener noreferrer"&gt;DriftGuard: Google Merchant Center Feed Price &amp;amp; Stock Checker&lt;/a&gt; on Apify. Run the demo with empty inputs, then point it at your store and feed URL and schedule it daily. Questions? Email &lt;a href="mailto:apify@integrationyard.com"&gt;apify@integrationyard.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Data in this post: public storefront catalogs of four Shopify stores (first 250 products each), read-only, Oct 20, 2026. Google Merchant Center help pages checked Oct 20, 2026. Prices are the actor's published pay-per-event prices.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>shopify</category>
      <category>ecommerce</category>
      <category>automation</category>
      <category>seo</category>
    </item>
    <item>
      <title>Weibo Hot Search (微博热搜) Data in 2026: Track China's Trending Topics Without Code</title>
      <dc:creator>Integration Yard</dc:creator>
      <pubDate>Wed, 21 Oct 2026 17:14:29 +0000</pubDate>
      <link>https://dev.to/integrationyard/weibo-hot-search-wei-bo-re-sou-data-in-2026-track-chinas-trending-topics-without-code-4n86</link>
      <guid>https://dev.to/integrationyard/weibo-hot-search-wei-bo-re-sou-data-in-2026-track-chinas-trending-topics-without-code-4n86</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;微博热搜 (Weibo Hot Search)&lt;/strong&gt; is Weibo's live, ranked board of what's trending in China right now — a mix of news, entertainment, product launches and public debate, refreshed continuously.&lt;/li&gt;
&lt;li&gt;In a live export on Oct 21, 2026, the top 50 board came back as 50 ranked rows. Heat scores ranged from &lt;strong&gt;113,821 to 893,934&lt;/strong&gt; (median &lt;strong&gt;200,505&lt;/strong&gt;) — the &lt;strong&gt;#1 topic carried 7.9x the heat of #50&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Attention is front-loaded: the &lt;strong&gt;top 10 topics held 42%&lt;/strong&gt; of the combined heat across all 50 rows at that moment.&lt;/li&gt;
&lt;li&gt;We also pulled the posts behind one trending topic (rank #3 that day). Of &lt;strong&gt;12 merged, deduplicated posts&lt;/strong&gt;, &lt;strong&gt;11 came from verified accounts&lt;/strong&gt;, and nearly all the engagement sat on a single post from a major state news account (&lt;strong&gt;683 likes, 399 reposts, 75 comments&lt;/strong&gt; vs. single digits on the rest).&lt;/li&gt;
&lt;li&gt;No login, no cookies, no Weibo account needed. $3 per 1,000 rows.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Weibo had &lt;strong&gt;561 million monthly active users and 254 million daily active users&lt;/strong&gt; as of June 2026 (&lt;a href="https://www.prnewswire.com/news-releases/weibo-announces-second-quarter-2026-unaudited-financial-results-302855055.html" rel="noopener noreferrer"&gt;Weibo Q2 2026 results&lt;/a&gt;) — one of the largest public social platforms anywhere, and the default place Chinese-speaking audiences go to see what's happening right now. The &lt;strong&gt;热搜 (hot search) board&lt;/strong&gt; sits at the center of that: a constantly updating, ranked list of the topics, hashtags and breaking stories pulling the most attention at any given moment.&lt;/p&gt;

&lt;p&gt;If you track China-facing brands, follow Chinese public opinion, or build products that need a pulse on what's trending in the Chinese-language internet, 热搜 is usually the first place to look — and historically the hardest to pull into your own tools without manual copy-paste. This guide shows what the hot search board actually looks like in data form, who uses it and why, and how to get it on a schedule. Every number below comes from real runs on Oct 21, 2026.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: we build and maintain the Weibo Scraper used here.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why 微博热搜 matters&lt;/li&gt;
&lt;li&gt;The board in one chart: heat is front-loaded&lt;/li&gt;
&lt;li&gt;From a trending topic to the posts behind it&lt;/li&gt;
&lt;li&gt;Who uses this data&lt;/li&gt;
&lt;li&gt;What you get&lt;/li&gt;
&lt;li&gt;Scheduling: building a trend history&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Try it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why 微博热搜 matters
&lt;/h2&gt;

&lt;p&gt;China's internet population passed &lt;strong&gt;1.125 billion&lt;/strong&gt; users as of December 2025, at &lt;strong&gt;80.1% penetration&lt;/strong&gt; (&lt;a href="https://english.www.gov.cn/archive/statistics/202602/05/content_WS698442cac6d00ca5f9a08edc.html" rel="noopener noreferrer"&gt;CNNIC 57th Statistical Report&lt;/a&gt;). Weibo's hot search board is one of the main places that much attention converges — it's referenced in Chinese entertainment coverage, cited by news outlets as a measure of public interest, and watched closely by brands the moment their name or a competitor's shows up on it.&lt;/p&gt;

&lt;p&gt;Because the board updates continuously and ranks everything by a live "heat" score, it works as a real-time signal for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What's breaking right now&lt;/strong&gt; — news, product launches, entertainment and sports moments as they happen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How big something actually got&lt;/strong&gt; — rank and heat give you a rough but comparable measure of a topic's pull relative to everything else trending that moment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where public conversation is heading&lt;/strong&gt; — a snapshot today, a trend line over weeks of scheduled snapshots.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The board in one chart: heat is front-loaded
&lt;/h2&gt;

&lt;p&gt;One &lt;code&gt;hot_search&lt;/code&gt; run returns the full top-50 board: rank, keyword, a heat score, and Weibo's own label (热 "hot", 新 "new", 沸 "surging", or none).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fda1x3yovmat8tdzdjgss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fda1x3yovmat8tdzdjgss.png" alt="Weibo hot search heat by rank" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heat scores on Oct 21, 2026 ranged from &lt;strong&gt;113,821 (rank 50) to 893,934 (rank 1)&lt;/strong&gt; — a &lt;strong&gt;7.9x&lt;/strong&gt; spread top to bottom.&lt;/li&gt;
&lt;li&gt;Of the 50 rows, &lt;strong&gt;15 carried a "新" (new) label, 6 were "热" (hot), 3 were "沸" (surging)&lt;/strong&gt;, and 26 had no label at that moment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;31 of the 50&lt;/strong&gt; were hashtag-style topics (marked &lt;code&gt;isTopic&lt;/code&gt;), the rest standalone keywords.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiiqh1sqtc9wweqn8qh9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiiqh1sqtc9wweqn8qh9o.png" alt="Where the heat concentrates on the board" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;top 10 ranked topics held 42%&lt;/strong&gt; of the combined heat across the whole board, and the next 20 held another third. In other words: the board is long, but a handful of topics are doing most of the pulling at any one moment — which is exactly why rank and heat, not just presence on the list, matter for monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  From a trending topic to the posts behind it
&lt;/h2&gt;

&lt;p&gt;A rank and a heat number tell you &lt;em&gt;that&lt;/em&gt; something is trending. To see &lt;em&gt;what people are actually posting&lt;/em&gt;, you look up the posts behind a specific hot-search topic by keyword. We did this for the #3 topic from the same board snapshot above, a Long March history feature (长征硬核知识点十问十答).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhbn04bq5co5b7vyhu42j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhbn04bq5co5b7vyhu42j.png" alt="Engagement on the posts behind one trending topic" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The search returned &lt;strong&gt;12 merged, deduplicated posts&lt;/strong&gt; from Weibo's search tabs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;11 of the 12 posting accounts were verified&lt;/strong&gt; — official and institutional accounts dominate the conversation around this kind of topic.&lt;/li&gt;
&lt;li&gt;Nearly all the engagement sat on one post from a major state news account: &lt;strong&gt;683 likes, 399 reposts and 75 comments&lt;/strong&gt;, versus single digits (often zero) on the other 11.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That pattern — a handful of large accounts carrying most of the visible engagement on a given trending topic — is a useful thing to know before you draw conclusions from raw post counts alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who uses this data
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Brands and agencies:&lt;/strong&gt; track mentions of a product, campaign or spokesperson the moment they surface on the board, and catch a complaint or crisis thread early.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Market and media researchers:&lt;/strong&gt; measure topic momentum over time, compare how different stories or launches performed relative to each other, and build a dataset of what actually trends in China and when.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analysts and competitive intelligence teams:&lt;/strong&gt; watch a sector or competitor's share of public attention, benchmarked against everything else trending that day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI / LLM teams:&lt;/strong&gt; fresh, timestamped, Chinese-language trending topics and posts for retrieval-augmented generation, trend summarization or sentiment models that need to know what's current.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;th&gt;Typical use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hot search board (热搜)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Rank, keyword, heat score, label (热/新/沸), whether it's a hashtag topic&lt;/td&gt;
&lt;td&gt;real-time trend tracking, topic momentum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Posts by keyword&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Text, engagement counts, author and verification status, timestamp, for a specific trending topic or any keyword&lt;/td&gt;
&lt;td&gt;seeing what's actually being said about a trend&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Post comments&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reactions to a specific post&lt;/td&gt;
&lt;td&gt;sentiment on a particular story or statement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User profiles&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Follower counts, verification, bio&lt;/td&gt;
&lt;td&gt;checking who's driving a topic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No login, no cookies and no Weibo account are needed for any of it. Results export as JSON, CSV or Excel, and there's a compact, token-optimized format for feeding straight into an LLM pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling: building a trend history
&lt;/h2&gt;

&lt;p&gt;A single hot-search snapshot is a moment in time. The real value shows up when you schedule it: run the hot search board hourly (or as often as you need) and you build your own history of what trended, when, and how its heat score moved — something a one-off search can't give you. The same applies to tracking posts for a specific keyword or hashtag over the life of a story.&lt;/p&gt;

&lt;p&gt;To set it up: save your input as a &lt;strong&gt;Task&lt;/strong&gt; in Apify Console, then attach a &lt;strong&gt;Schedule&lt;/strong&gt;. Send results where you work through Apify's built-in integrations — Google Sheets, Slack or email alerts, webhooks, Make/Zapier/n8n, or directly into an AI agent through the Apify MCP server.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Is there an official Weibo API for hot search data?&lt;/strong&gt;&lt;br&gt;
Weibo's open platform requires a Chinese developer account and an approval process, and access is limited. This gives you the hot search board and related post data right away, with no account needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does "heat" mean on the hot search board?&lt;/strong&gt;&lt;br&gt;
It's Weibo's own composite score reflecting how much attention a topic is currently pulling — useful for ranking and comparing topics against each other, not a number with an independently documented formula.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often does the board change?&lt;/strong&gt;&lt;br&gt;
Continuously. Scheduling hourly runs is the usual way to capture how it moves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I track a specific brand or keyword instead of the whole board?&lt;/strong&gt;&lt;br&gt;
Yes — search by keyword at any time, whether or not that term is currently on the hot search board.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need a Weibo account or a Chinese phone number?&lt;/strong&gt;&lt;br&gt;
No. Everything in this guide works without login.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use this with AI agents or LLM pipelines?&lt;/strong&gt;&lt;br&gt;
Yes. It works through the Apify MCP server, and there's a compact, token-optimized output format built for feeding results into an LLM.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://apify.com/dheerajitbhu/weibo-scraper" rel="noopener noreferrer"&gt;Weibo Scraper on Apify Store&lt;/a&gt;: the input form opens prefilled with a sample run — press Start.&lt;/li&gt;
&lt;li&gt;More China data: &lt;a href="https://apify.com/dheerajitbhu/bilibili-scraper" rel="noopener noreferrer"&gt;Bilibili Scraper&lt;/a&gt; for China's biggest video community, or the &lt;a href="https://apify.com/dheerajitbhu/douban-scraper" rel="noopener noreferrer"&gt;Douban Scraper&lt;/a&gt; for movie, TV and book ratings and reviews.&lt;/li&gt;
&lt;li&gt;Related guide: &lt;a href="https://apify.integrationyard.com/blog/scrape-weibo-bilibili-2026/" rel="noopener noreferrer"&gt;Weibo and Bilibili data in 2026&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webscraping</category>
      <category>data</category>
      <category>china</category>
      <category>api</category>
    </item>
    <item>
      <title>Get an Alert When a Competitor Changes Prices on Their WooCommerce Store</title>
      <dc:creator>Integration Yard</dc:creator>
      <pubDate>Wed, 21 Oct 2026 17:04:57 +0000</pubDate>
      <link>https://dev.to/integrationyard/get-an-alert-when-a-competitor-changes-prices-on-their-woocommerce-store-10ga</link>
      <guid>https://dev.to/integrationyard/get-an-alert-when-a-competitor-changes-prices-on-their-woocommerce-store-10ga</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most WooCommerce stores publish their full catalog publicly, including prices, sale prices, SKUs and stock, so a competitor's catalog can be monitored &lt;strong&gt;without logins, plugins or page-by-page scraping&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The useful part is &lt;strong&gt;diffing&lt;/strong&gt;: snapshot the catalog on a schedule and send only what changed (new, removed, price changed, stock changed) to Slack, email or Sheets.&lt;/li&gt;
&lt;li&gt;In three real stores we checked on Oct 20, 2026, &lt;strong&gt;13–36% of products were out of stock&lt;/strong&gt; and &lt;strong&gt;1–15% were on sale&lt;/strong&gt;. Those are the fields that move day to day.&lt;/li&gt;
&lt;li&gt;A daily check of a 1,000-product competitor with 10 changes costs about &lt;strong&gt;$0.25 a run&lt;/strong&gt; with our monitor actor. The first (baseline) run is never charged for changes.&lt;/li&gt;
&lt;li&gt;Full setup below: the scheduled actor, Zapier, Make, built-in Apify integrations and Python.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you sell products that other shops also sell, you've probably done this: open a few competitor tabs every Monday, scroll their catalogs, and try to remember what things cost last week. That works for 20 products. It breaks at 200, and it misses the things that matter most: the sale that started Tuesday night, the best-seller that went out of stock on Thursday, the new product line that appeared over the weekend.&lt;/p&gt;

&lt;p&gt;Price-monitoring tools exist, but many are built around &lt;strong&gt;matching URLs one product at a time&lt;/strong&gt;, or need a WooCommerce REST API key, which you can only get for &lt;em&gt;your own&lt;/em&gt; store. For competitor stores built on WooCommerce, there's a sturdier path: monitor the whole catalog and get told only what changed.&lt;/p&gt;

&lt;p&gt;This guide shows that path end to end. Every number in it comes from real public stores or from our actor's published pricing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: we built the WooCommerce Product Feed &amp;amp; Catalog Monitor actor used in this guide.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why competitor price monitoring matters&lt;/li&gt;
&lt;li&gt;What a competitor's catalog tells you&lt;/li&gt;
&lt;li&gt;Step 1: snapshot and diff on a schedule&lt;/li&gt;
&lt;li&gt;What it costs&lt;/li&gt;
&lt;li&gt;Step 2: alerts with Zapier, Make or Apify integrations&lt;/li&gt;
&lt;li&gt;Step 3: the code version&lt;/li&gt;
&lt;li&gt;Which alerts are actually worth sending&lt;/li&gt;
&lt;li&gt;Caveats&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Try it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why competitor price monitoring matters
&lt;/h2&gt;

&lt;p&gt;Competitor signals are some of the cheapest market data you can get, and they're perishable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Price drops&lt;/strong&gt; on products you both sell decide whether you lose the click on Google Shopping, the marketplace comparison, or the customer who checks two tabs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stock-outs&lt;/strong&gt; are the most underused signal. When a competitor sells out of a popular item, demand moves to whoever still has it. That's the moment to hold your price, not cut it, and maybe to raise ad spend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New products&lt;/strong&gt; show where a competitor is investing before they announce it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Removed products&lt;/strong&gt; show what didn't sell.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these need a perfect real-time feed. A &lt;strong&gt;daily diff&lt;/strong&gt; catches nearly all of them, and every few hours is plenty in fast categories.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a competitor's catalog tells you
&lt;/h2&gt;

&lt;p&gt;WooCommerce is one of the most widely used e-commerce platforms, so many of your competitors probably run on it. Their public catalog is far more structured than it looks from the storefront: every product has a current price, a regular price, a sale price, a stock status and usually a SKU, and all of it is visible to any visitor.&lt;/p&gt;

&lt;p&gt;Turning that into a reliable feed is the hard part. Themes differ, prices are stored in different currencies and units, variations hide inside parent products, and stores change over time. Our actors handle all of that and are maintained against WooCommerce changes, so you get clean rows instead of a parsing project.&lt;/p&gt;

&lt;p&gt;Even a single snapshot is informative. Here are three real public WooCommerce stores on Oct 20, 2026: a 39-product drinkware shop, a 69-product online butcher and a 101-product outdoor-bottle brand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4r1wqry030mb88vkku42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4r1wqry030mb88vkku42.png" alt="Stacked bars of in-stock vs out-of-stock products in a store's first 100 catalog products, Oct 20 2026: Store A 14 of 39 out of stock and 6 on sale, Store B 9 of 69 out of stock and 1 on sale, Store C 18 of 100 out of stock and 10 on sale" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the day we checked, &lt;strong&gt;13–36% of products were out of stock&lt;/strong&gt; and &lt;strong&gt;1–15% were on sale&lt;/strong&gt;. Those are exactly the fields that change from one day to the next, and the changes are what you want alerts for.&lt;/p&gt;

&lt;p&gt;What that's worth to different teams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce managers:&lt;/strong&gt; match or hold prices on overlapping products, and push ads when a rival sells out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category and merchandising teams:&lt;/strong&gt; see new launches and discontinued lines as they happen, not at the next quarterly review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agencies and analysts:&lt;/strong&gt; run the same watch across dozens of stores for clients, with one schedule and one dataset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brands with resellers:&lt;/strong&gt; spot resellers undercutting your price policy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: snapshot and diff on a schedule
&lt;/h2&gt;

&lt;p&gt;Reading a catalog once is easy. The useful part is remembering last run's catalog and reporting only what changed. &lt;a href="https://apify.com/dheerajitbhu/woocommerce-catalog-monitor" rel="noopener noreferrer"&gt;WooCommerce Product Feed &amp;amp; Catalog Monitor&lt;/a&gt; does exactly that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;first run&lt;/strong&gt; for a store records a baseline and is &lt;strong&gt;never charged for "changes"&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every later run&lt;/strong&gt; compares against the stored snapshot and emits one dataset row per change, typed &lt;code&gt;new&lt;/code&gt;, &lt;code&gt;removed&lt;/code&gt;, &lt;code&gt;price_changed&lt;/code&gt; or &lt;code&gt;stock_changed&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&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;"storeUrls"&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://competitor-one.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://competitor-two.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;"maxProductsPerStore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outputMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"changes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stateName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"competitor-watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxChargeUsd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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 change row looks like this:&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;"recordType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"change"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://competitor-one.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;"changeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"price_changed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ceramic Mug - 12oz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MUG-12"&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;1650&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"oldPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1400&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stock_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;"instock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permalink"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://competitor-one.com/product/ceramic-mug-12oz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detectedAt"&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-10-16T09:00:00+00:00"&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;Keep &lt;code&gt;stateName&lt;/code&gt; &lt;strong&gt;identical across runs&lt;/strong&gt;. It names the key-value store that holds the snapshot. Change it only when you want a fresh baseline, for example when you start watching a different set of stores.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Schedule it.&lt;/strong&gt; In Apify Console, go to &lt;strong&gt;Schedules → Create new&lt;/strong&gt;. Pick the actor, or better, save the input above as a &lt;strong&gt;Task&lt;/strong&gt; first, then set a cron expression:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0 7 * * *&lt;/code&gt; runs daily at 07:00, which is enough for most categories;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0 */4 * * *&lt;/code&gt; runs every four hours, for fast-moving categories or during sale seasons.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Pricing is pay-per-event:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Run started&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product checked&lt;/td&gt;
&lt;td&gt;$0.0002 ($0.20 per 1,000)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change detected&lt;/td&gt;
&lt;td&gt;$0.005&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1tp1x8enqv2iz4wcfnly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1tp1x8enqv2iz4wcfnly.png" alt="Grouped bar chart of cost per run by catalog size and number of changes: 100 products 0.02 to 0.27 dollars, 500 products 0.10 to 0.35, 1,000 products 0.20 to 0.45, 5,000 products 1.00 to 1.25" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;1,000-product competitor checked daily with about 10 changes a day costs roughly $0.25 a run&lt;/strong&gt;, or about $7.50 a month. Three competitors of the three sizes we probed (39, 69 and 101 products) would cost about &lt;strong&gt;$0.04 a run combined&lt;/strong&gt; before changes. To spend less, lower &lt;code&gt;maxProductsPerStore&lt;/code&gt; or the schedule frequency. &lt;code&gt;maxChargeUsd&lt;/code&gt; is a hard per-run cap, and stores that fail (no public API, network errors) return an error row that isn't charged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: alerts with Zapier, Make or Apify integrations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option A: Zapier
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Trigger:&lt;/strong&gt; Apify → &lt;em&gt;Finished Task Run&lt;/em&gt;. Connect your Apify account and pick the task from step 2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; Apify → &lt;em&gt;Fetch Dataset Items&lt;/em&gt;, using the &lt;code&gt;defaultDatasetId&lt;/code&gt; from the trigger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter:&lt;/strong&gt; only continue if &lt;code&gt;recordType&lt;/code&gt; exactly matches &lt;code&gt;change&lt;/code&gt; and &lt;code&gt;changeType&lt;/code&gt; exactly matches &lt;code&gt;price_changed&lt;/code&gt;. Add another path for &lt;code&gt;stock_changed&lt;/code&gt; or &lt;code&gt;new&lt;/code&gt; if you want those too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formatter → Numbers → Perform Math Operation:&lt;/strong&gt; divide &lt;code&gt;price&lt;/code&gt; and &lt;code&gt;oldPrice&lt;/code&gt; by 100 to show dollars instead of cents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; Slack → &lt;em&gt;Send Channel Message&lt;/em&gt; with the formatted values and the &lt;code&gt;permalink&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a run returns many changes, Zapier sends one message per row by default. Use &lt;em&gt;Formatter → Utilities → Line-item to Text&lt;/em&gt; to send a single digest message per run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option B: Make
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Apify → &lt;em&gt;Watch Task Runs&lt;/em&gt; (an instant trigger; Make creates the webhook for you).&lt;/li&gt;
&lt;li&gt;Apify → &lt;em&gt;Get Dataset Items&lt;/em&gt;, with Dataset ID = &lt;code&gt;defaultDatasetId&lt;/code&gt; from module 1.&lt;/li&gt;
&lt;li&gt;Add a filter between modules 2 and 3: &lt;code&gt;recordType = change&lt;/code&gt; and &lt;code&gt;changeType = price_changed&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Google Sheets → &lt;em&gt;Add a Row&lt;/em&gt; (a price-history log), and/or Slack → &lt;em&gt;Create a Message&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Add a &lt;strong&gt;Router&lt;/strong&gt; with one route per &lt;code&gt;changeType&lt;/code&gt;. Send &lt;code&gt;new&lt;/code&gt; products to a "competitor launches" channel and &lt;code&gt;stock_changed&lt;/code&gt; to an out-of-stock channel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option C: no automation tool at all
&lt;/h3&gt;

&lt;p&gt;Every Apify task has built-in integrations: Slack, email, Google Drive and webhooks. Open the task, go to &lt;strong&gt;Integrations&lt;/strong&gt;, and add Slack or &lt;em&gt;Send email&lt;/em&gt; triggered on &lt;em&gt;Run succeeded&lt;/em&gt;. You won't get per-row filtering, but you get a free "the run finished, here's the dataset" notification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: the code version
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_APIFY_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dheerajitbhu/woocommerce-catalog-monitor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;storeUrls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://competitor-one.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outputMode&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;changes&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;stateName&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;competitor-watch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recordType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;change&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;changeType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price_changed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;oldPrice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
        &lt;span class="n"&gt;pct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pct&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%) &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;permalink&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scheduling, cloud state, many stores per run, error rows instead of crashes, per-run spend caps and the Zapier and Make integrations all come built in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which alerts are actually worth sending
&lt;/h2&gt;

&lt;p&gt;An alert for every change becomes noise within a week. Pricing-strategy guides such as &lt;a href="https://valyupeak.com/blog/woocommerce-competitor-price-tracking" rel="noopener noreferrer"&gt;Valyupeak's WooCommerce price-tracking setup&lt;/a&gt; and &lt;a href="https://pricerr.io/blog/woocommerce-price-monitoring" rel="noopener noreferrer"&gt;Pricerr's monitoring guide&lt;/a&gt; make the same point: design alerts around decisions you'd actually act on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Price drops beyond a threshold&lt;/strong&gt; on products you also sell. Valyupeak suggests something like 8–15% as the point where a deliberate response is warranted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stock-outs on overlapping products.&lt;/strong&gt; Hold your price and consider raising ad spend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New products&lt;/strong&gt; from your main competitors, in a separate, lower-priority channel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weekly digest for everything else.&lt;/strong&gt; Put all changes in a Google Sheet and review it on Mondays.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Set a &lt;strong&gt;price floor&lt;/strong&gt; before you let any of this drive automatic repricing. A competitor's clearance sale shouldn't set your price.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public prices only.&lt;/strong&gt; Member-only pricing, coupons applied at checkout and B2B price tables aren't in public catalog data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Currencies and minor units.&lt;/strong&gt; Prices come back in the store's own currency and minor units. Convert before comparing across stores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variable products.&lt;/strong&gt; For products with variations (sizes, colours), the top-level price may not reflect every variation's price. Check the variations you care about if sizes are priced differently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matching your catalog to theirs&lt;/strong&gt; (which of their products equals which of yours) is a separate problem. SKUs rarely match across brands, so most teams keep a small mapping sheet for their key products.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be a good citizen.&lt;/strong&gt; The actor reads catalogs lightly and politely. Daily or every few hours is plenty. Use the data in line with each store's terms.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Is it legal to monitor a competitor's catalog?&lt;/strong&gt;&lt;br&gt;
The actor reads only the public catalog data the store shows any visitor, without login. You're still responsible for following each site's terms and local law, so treat this as public price intelligence, not a way into anything private.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I know if a store is on WooCommerce?&lt;/strong&gt;&lt;br&gt;
Just add its URL. Stores that can't be read come back as an error row and aren't charged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it work for Shopify stores?&lt;/strong&gt;&lt;br&gt;
No, this actor is WooCommerce-only. Shopify has its own public storefront JSON, which our &lt;a href="https://apify.com/dheerajitbhu/driftguard" rel="noopener noreferrer"&gt;DriftGuard&lt;/a&gt; actor reads for a different job: checking your own Google Merchant Center feed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should I run it?&lt;/strong&gt;&lt;br&gt;
Daily for most categories. Every 4 hours around big sale events or in fast-moving categories. Each run is charged per product checked, so frequency is the main cost lever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens on the very first run?&lt;/strong&gt;&lt;br&gt;
It records the baseline snapshot and isn't charged for changes. Alerts start from the second run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I watch several competitors at once?&lt;/strong&gt;&lt;br&gt;
Yes. Put them all in &lt;code&gt;storeUrls&lt;/code&gt;. One run checks every store and diffs each against its own previous snapshot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I monitor my own store with it?&lt;/strong&gt;&lt;br&gt;
Yes. Some merchants use it as a cheap audit log of their own price and stock changes.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://apify.com/dheerajitbhu/woocommerce-catalog-monitor" rel="noopener noreferrer"&gt;WooCommerce Product Feed &amp;amp; Catalog Monitor&lt;/a&gt; on Apify: add your competitors' store URLs, keep &lt;code&gt;stateName&lt;/code&gt; fixed, schedule it daily, and connect Slack. Questions? Email &lt;a href="mailto:apify@integrationyard.com"&gt;apify@integrationyard.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Data in this post: read-only checks of three public WooCommerce stores on Oct 20, 2026, plus the actor's published pricing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>woocommerce</category>
      <category>ecommerce</category>
      <category>automation</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>How to Scrape Weibo and Bilibili Without Login in 2026</title>
      <dc:creator>Integration Yard</dc:creator>
      <pubDate>Tue, 20 Oct 2026 14:17:41 +0000</pubDate>
      <link>https://dev.to/integrationyard/how-to-scrape-weibo-and-bilibili-without-login-in-2026-68c</link>
      <guid>https://dev.to/integrationyard/how-to-scrape-weibo-and-bilibili-without-login-in-2026-68c</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can collect a lot of public &lt;strong&gt;Weibo&lt;/strong&gt; and &lt;strong&gt;Bilibili&lt;/strong&gt; data in 2026 &lt;strong&gt;without logging in&lt;/strong&gt;: search results, comments, hot search, trending videos, creator profiles and danmaku summaries. Between them, our two actors cover &lt;strong&gt;11 no-login modes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The hard limits are real. Without a session, &lt;strong&gt;Weibo search returns only the first page&lt;/strong&gt; (about 10 posts per tab, about 30 unique posts per keyword per run). &lt;strong&gt;Bilibili hides subtitle text and creator upload lists&lt;/strong&gt; behind login. Work with these limits, not against them: schedule frequent runs, and search instead of browsing a creator's space page.&lt;/li&gt;
&lt;li&gt;In a live run on Oct 20, 2026, the Weibo hot search board came back as &lt;strong&gt;50 rows in 9.3 seconds&lt;/strong&gt;. The #1 topic had &lt;strong&gt;13x the heat&lt;/strong&gt; of #50.&lt;/li&gt;
&lt;li&gt;Engagement is extremely concentrated. In our export of 200 Bilibili comments, the &lt;strong&gt;top 10% held 90% of all likes&lt;/strong&gt;, so sort before you read.&lt;/li&gt;
&lt;li&gt;Price on Apify Store: &lt;strong&gt;$3 per 1,000 Weibo rows&lt;/strong&gt; and &lt;strong&gt;$2 per 1,000 Bilibili rows&lt;/strong&gt; with our actors. The most-used alternatives charge &lt;strong&gt;$35 and $20&lt;/strong&gt; per 1,000.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Weibo (微博) and Bilibili (哔哩哔哩, "B站") are two of the most useful public data sources on the Chinese internet. Weibo is where news breaks and brands get discussed. Its hot search board (热搜) is effectively China's live trending list. Bilibili is the largest long-form video community, with a young, very engaged audience and an overlay comment layer called danmaku (弹幕) that no Western platform has.&lt;/p&gt;

&lt;p&gt;If you do market research, brand monitoring, academic work or trend tracking on China, you need both. Most guides start with "log in with Playwright and export your cookies". That works until the account gets rate-limited, the cookie expires in a few days, or someone asks whether you should be scraping under a personal account at all.&lt;/p&gt;

&lt;p&gt;This guide takes the other route. It covers what you can reliably get &lt;strong&gt;without any login&lt;/strong&gt;, what you can't, and how to build a monitoring loop around those limits. Every number in it comes from real runs of our actors, our benchmark exports, or the public Apify Store API.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: we build and maintain the Weibo Scraper and Bilibili Scraper used here.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why scrape Weibo and Bilibili&lt;/li&gt;
&lt;li&gt;Login vs no login: the honest trade-off&lt;/li&gt;
&lt;li&gt;Scraping Bilibili without login&lt;/li&gt;
&lt;li&gt;Scraping Weibo without login&lt;/li&gt;
&lt;li&gt;What the data looks like&lt;/li&gt;
&lt;li&gt;What it costs&lt;/li&gt;
&lt;li&gt;Building a monitoring loop&lt;/li&gt;
&lt;li&gt;Code: Python and the Apify API&lt;/li&gt;
&lt;li&gt;Limits, ethics and data protection&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Try it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why scrape Weibo and Bilibili
&lt;/h2&gt;

&lt;p&gt;China had &lt;strong&gt;1.125 billion internet users&lt;/strong&gt; at the end of 2025, and &lt;strong&gt;602 million&lt;/strong&gt; of them had used generative AI (&lt;a href="https://english.www.gov.cn/archive/statistics/202602/05/content_WS698442cac6d00ca5f9a08edc.html" rel="noopener noreferrer"&gt;CNNIC 57th Statistical Report&lt;/a&gt;). Almost none of that conversation happens on platforms Western tools cover. Weibo and Bilibili are two of the biggest public windows into it:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Weibo (微博)&lt;/th&gt;
&lt;th&gt;Bilibili (哔哩哔哩)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monthly active users&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;561 million&lt;/strong&gt; (June 2026)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;371 million&lt;/strong&gt; (Q2 2026)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily active users&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;254 million&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;116.5 million&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audience&lt;/td&gt;
&lt;td&gt;broad, national; news, celebrities, brands, public debate&lt;/td&gt;
&lt;td&gt;young: average user age &lt;strong&gt;26.5&lt;/strong&gt;; &lt;strong&gt;113 minutes&lt;/strong&gt; a day on the platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What it's for&lt;/td&gt;
&lt;td&gt;breaking news, the hot search board, brand campaigns, public reaction&lt;/td&gt;
&lt;td&gt;long-form video reviews, tutorials, gaming, tech, anime; comments and danmaku&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Why brands care&lt;/td&gt;
&lt;td&gt;real-time share of voice, crisis detection, campaign feedback&lt;/td&gt;
&lt;td&gt;Gen Z product opinions, creator (UP主) marketing; top ad verticals are games, consumer electronics, internet services, e-commerce and automotive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Sources: &lt;a href="https://www.prnewswire.com/news-releases/weibo-announces-second-quarter-2026-unaudited-financial-results-302855055.html" rel="noopener noreferrer"&gt;Weibo Q2 2026 results&lt;/a&gt;; &lt;a href="https://ir.bilibili.com/media/ywxkb3pf/bilibili-inc-announces-second-quarter-2026-financial-results.pdf" rel="noopener noreferrer"&gt;Bilibili Q2 2026 results&lt;/a&gt; and &lt;a href="https://www.fool.com/earnings/call-transcripts/2026/08/31/bilibili-bili-q2-2026-earnings-call-transcript/" rel="noopener noreferrer"&gt;earnings call&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Who uses this data, and for what:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Brands and agencies:&lt;/strong&gt; track mentions, measure campaign reaction, find the creators who move your category, and catch a PR problem while it's still a comment thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Market researchers:&lt;/strong&gt; compare share of voice, follow topic momentum hour by hour, and benchmark engagement across categories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI and LLM teams:&lt;/strong&gt; fresh, timestamped, opinionated Chinese text for sentiment models, trend summarisation, evaluation sets and RAG over current events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few common, concrete use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Brand and product monitoring.&lt;/strong&gt; What are people saying about 小米, 比亚迪 or your own brand this week? What's in the comments under the top reviews of your product category?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trend detection.&lt;/strong&gt; Which topics are rising on the hot search board right now, and which are labelled 新 (new) or 热 (hot)?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creator research.&lt;/strong&gt; Which Bilibili creators (UP主) in a niche have the most followers and the most engaged audiences?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content and sentiment analysis.&lt;/strong&gt; Comments and danmaku are short, opinionated and timestamped, which makes them good raw material for sentiment models and LLM summaries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Academic research&lt;/strong&gt; on public discourse, media and online communities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these need &lt;em&gt;public&lt;/em&gt; data at a steady cadence. None of them needs a logged-in account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Login vs no login: the honest trade-off
&lt;/h2&gt;

&lt;p&gt;Popular Weibo guides, including &lt;a href="https://www.webscrapinghq.com/blog/weibo-scraper-guide" rel="noopener noreferrer"&gt;WebscrapingHQ's 2026 Weibo scraper guide&lt;/a&gt; and open-source projects like &lt;a href="https://github.com/NanmiCoder/MediaCrawler" rel="noopener noreferrer"&gt;MediaCrawler&lt;/a&gt;, log in with a real account and reuse its cookies. That gets you deep search pagination and full timelines. It also gets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cookies that expire within days, which means session-refresh code and monitoring;&lt;/li&gt;
&lt;li&gt;account-level rate limits and bans that land on a real person's account;&lt;/li&gt;
&lt;li&gt;a weaker legal and ethical position, because you're accessing data as a logged-in user rather than as any visitor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The no-login approach gives up depth in exchange for reliability and a much simpler compliance story. Here's what it can and can't reach:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Without login (our actors)&lt;/th&gt;
&lt;th&gt;Needs login&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Weibo hot search board&lt;/td&gt;
&lt;td&gt;✅ full board&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weibo keyword search&lt;/td&gt;
&lt;td&gt;✅ first page per tab (~30 unique posts per keyword per run)&lt;/td&gt;
&lt;td&gt;deep pagination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weibo post detail and comments&lt;/td&gt;
&lt;td&gt;✅ paged with Weibo's own cursor&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weibo user profile and latest posts&lt;/td&gt;
&lt;td&gt;✅ profile, about 10 latest posts&lt;/td&gt;
&lt;td&gt;full timeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili search&lt;/td&gt;
&lt;td&gt;✅ up to ~1,000 results per keyword&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili video stats, comments, replies&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili popular board, creator profiles&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili danmaku&lt;/td&gt;
&lt;td&gt;✅ as a per-video summary&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili subtitles / AI subtitles&lt;/td&gt;
&lt;td&gt;only &lt;code&gt;hasSubtitles&lt;/code&gt; true/false&lt;/td&gt;
&lt;td&gt;✅ subtitle text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili creator upload list (space page)&lt;/td&gt;
&lt;td&gt;❌ blocked by risk control. Search by creator name instead.&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For most monitoring work, the left column is enough. Where it isn't, the fix is usually &lt;strong&gt;frequency, not depth&lt;/strong&gt;: if you can only see the newest 30 posts for a keyword, look every hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scraping Bilibili without login
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/dheerajitbhu/bilibili-scraper" rel="noopener noreferrer"&gt;Bilibili Scraper&lt;/a&gt; has five modes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Videos matching keywords, with sort, length and date filters&lt;/td&gt;
&lt;td&gt;&lt;code&gt;searchQueries&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;video_detail&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Views, likes, coins, favorites, shares, danmaku count, comment count, parts, &lt;code&gt;hasSubtitles&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;videoUrls&lt;/code&gt; (links or BV ids)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;video_comments&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Top-level comments (popular or newest first), plus optional replies&lt;/td&gt;
&lt;td&gt;&lt;code&gt;videoUrls&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;popular&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The popular / trending board&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;user_profile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creator followers, following, video count, total likes, level, verification, bio&lt;/td&gt;
&lt;td&gt;&lt;code&gt;userIds&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;includeComments&lt;/code&gt;, &lt;code&gt;includeReplies&lt;/code&gt;, &lt;code&gt;includeDanmaku&lt;/code&gt; and &lt;code&gt;includeVideoDetails&lt;/code&gt; add-ons work on &lt;code&gt;search&lt;/code&gt;, &lt;code&gt;video_detail&lt;/code&gt; and &lt;code&gt;popular&lt;/code&gt;, so one run can return videos &lt;em&gt;and&lt;/em&gt; their comments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"searchQueries"&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;"机械键盘"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxResults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sortOrder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pubdate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"includeComments"&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;"maxComments"&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="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;&lt;strong&gt;Danmaku&lt;/strong&gt; are the bullet comments that fly across a Bilibili video. A popular video can have thousands. Rather than bill you for each one, &lt;code&gt;includeDanmaku&lt;/code&gt; adds &lt;strong&gt;one summary row per video&lt;/strong&gt;: number of danmaku fetched, unique senders, per-minute rate, peak minute and a timeline sample. That's usually what you want for analysis anyway, because the peak minute tells you which moment of the video people reacted to.&lt;/p&gt;

&lt;p&gt;Plan around three Bilibili limits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Subtitles need login.&lt;/strong&gt; The actor reports &lt;code&gt;hasSubtitles&lt;/code&gt; but can't download the text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creator upload lists need login.&lt;/strong&gt; A creator's space page is blocked by risk control for anonymous visitors. To find a creator's videos, &lt;code&gt;search&lt;/code&gt; for their name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search tops out at about 1,000 results per keyword.&lt;/strong&gt; Split broad topics into narrower keywords or date windows.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's what the popular board looked like on the morning of Oct 20, 2026, from one &lt;code&gt;popular&lt;/code&gt; run of 50 videos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzru2ma4mh6e9j7uizsw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzru2ma4mh6e9j7uizsw2.png" alt="Horizontal bar chart of median engagement per 1,000 views on 50 Bilibili popular videos, Oct 20 2026: likes 76.2, favorites 15.7, coins 13.7, shares 4.5, comments 3.2, danmaku 2.4" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The median video had about 535,000 views and was about 6.5 minutes long. Viewers left a median &lt;strong&gt;76 likes per 1,000 views&lt;/strong&gt;, but only about &lt;strong&gt;3 comments and 2 danmaku&lt;/strong&gt;. Likes measure reach. Comments and danmaku are rarer and say much more, which is why most research projects want them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scraping Weibo without login
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/dheerajitbhu/weibo-scraper" rel="noopener noreferrer"&gt;Weibo Scraper&lt;/a&gt; has six modes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Posts from the 综合 / 实时 / 热门 tabs, merged and deduplicated&lt;/td&gt;
&lt;td&gt;&lt;code&gt;searchQueries&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hot_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The live hot search board: rank, keyword, heat, label&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;post_detail&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full text, counts, images, hashtags and author&lt;/td&gt;
&lt;td&gt;&lt;code&gt;postUrls&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;post_comments&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Comments, paged with Weibo's own cursor&lt;/td&gt;
&lt;td&gt;&lt;code&gt;postUrls&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;user_profile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Followers, following, post count, verification, bio&lt;/td&gt;
&lt;td&gt;&lt;code&gt;userIds&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;user_posts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A user's latest posts&lt;/td&gt;
&lt;td&gt;&lt;code&gt;userIds&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The main limit: &lt;strong&gt;without a logged-in account, Weibo serves only the first page of search results.&lt;/strong&gt; That's about 10 posts per tab, so up to about 30 unique posts per keyword per run after merging the three tabs. User timelines stop at about 10 latest posts. Comments, post details, profiles and the hot search board aren't limited this way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"searchQueries"&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;"小米"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"includeComments"&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;"maxComments"&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="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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hot_search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxResults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&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 hot search board is the fastest, cheapest signal Weibo offers. Our live run at 7:02 AM PT on Oct 20, 2026 returned 50 rows in 9.3 seconds, with no blocks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foeb8nxhltsxx8888khgj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foeb8nxhltsxx8888khgj.png" alt="Bar chart of Weibo hot search heat by rank for the top 50 on Oct 20 2026: rank 1 had about 1.88 million heat, falling to about 146 thousand at rank 50; 25 entries labelled new and 5 labelled hot" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two things stand out. First, the curve is steep: #1 had &lt;strong&gt;1,875,414&lt;/strong&gt; heat and #50 had &lt;strong&gt;145,560&lt;/strong&gt;, almost 13x less, and the top 10 entries held 41% of the board's total heat. Second, &lt;strong&gt;half the board (25 of 50) was labelled 新 (new)&lt;/strong&gt;. The board turns over fast, so snapshot it hourly if you want to catch topics on the way up rather than at the peak.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the data looks like
&lt;/h2&gt;

&lt;p&gt;Each actor writes one row per item to an Apify dataset. Rows have a &lt;code&gt;type&lt;/code&gt; field, so posts, comments and replies can share a dataset:&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;"comment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"postId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5355477305394531"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"commentId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5355484431519240"&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;"…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"likesCount"&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;"replyCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"authorName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"authorId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"createdAt"&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-10-18T…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"scrapedAt"&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-10-18T…"&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;Some shape numbers from our 882-row benchmark export (Oct 18, 2026):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Row type&lt;/th&gt;
&lt;th&gt;Rows&lt;/th&gt;
&lt;th&gt;Fields per row&lt;/th&gt;
&lt;th&gt;Median text length&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Weibo post&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;70.5 characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weibo comment&lt;/td&gt;
&lt;td&gt;99&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;18 characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili comment&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;25 characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili reply&lt;/td&gt;
&lt;td&gt;206&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;16.5 characters&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Chinese comments are short. A median of 18–25 characters is a phrase, not a paragraph. That matters for analysis: one comment rarely carries enough context alone, so models do better with many comments together.&lt;/p&gt;

&lt;p&gt;Likes are also very unevenly spread:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5czdmpwoqjddaisg7dbv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5czdmpwoqjddaisg7dbv.png" alt="Bar chart of the share of all likes held by the top 10 percent of rows: Bilibili comments 90 percent, Bilibili replies 72 percent, Weibo comments 66 percent, Weibo posts 59 percent" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our Bilibili export, the &lt;strong&gt;top 10% of comments held 90% of all likes&lt;/strong&gt;, and the median comment had &lt;strong&gt;2 likes&lt;/strong&gt;. Weibo comments were less extreme, but the top 10% still held 66%. In practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sort by likes first&lt;/strong&gt; if you're reading by hand or sending a sample to an LLM. The top 20 comments are what most viewers actually saw.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't average likes.&lt;/strong&gt; The mean is dominated by a few outliers. Use medians or percentiles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;popular&lt;/code&gt; ordering&lt;/strong&gt; for Bilibili comments when you want the consensus view, and newest-first when you're monitoring for new complaints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're sending these rows to an LLM, both actors also support &lt;code&gt;"outputFormat": "compact"&lt;/code&gt;. In &lt;a href="https://apify.integrationyard.com/blog/compact-json-output-for-llm-agents/" rel="noopener noreferrer"&gt;our token benchmark&lt;/a&gt; it cut tokens by &lt;strong&gt;41.9% for Bilibili&lt;/strong&gt; and &lt;strong&gt;24.8% for Weibo&lt;/strong&gt; versus pretty JSON.&lt;/p&gt;

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

&lt;p&gt;Both actors use pay-per-event pricing. You pay per row returned, and error rows are free:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Weibo Scraper&lt;/th&gt;
&lt;th&gt;Bilibili Scraper&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Run start&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Row (post, comment, reply, profile, hot-search entry, video)&lt;/td&gt;
&lt;td&gt;$0.003 ($3 per 1,000)&lt;/td&gt;
&lt;td&gt;$0.002 ($2 per 1,000)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Danmaku summary&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;$0.01 per video&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-run cap&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;maxChargeUsd&lt;/code&gt; (default $5)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;maxChargeUsd&lt;/code&gt; (default $5)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example costs: 100 Bilibili search results are $0.20. Ten videos with 50 comments each come to 510 rows, about $1.02. Hourly Weibo hot search (50 rows) costs about $0.15 a run.&lt;/p&gt;

&lt;p&gt;For context, here's what the most-used alternatives on Apify Store charge per result as of today:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnpvnk07drjr5efrqa58d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnpvnk07drjr5efrqa58d.png" alt="Bar chart of per-row price per 1,000 rows on Apify Store, Oct 20 2026. Weibo: zhorex 35 dollars, piotrv1001 5, socialdatax 4.99, ours 3. Bilibili: zhorex 20, resourceful_mandate 10, socialdatax 2.99, ours 2" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are per-result event prices from the public Apify Store API on Oct 20, 2026. Run-start fees and proxy costs aren't included, and the actors don't return identical fields, so compare what each one outputs as well as the price. The most-used Weibo actor charges &lt;strong&gt;$35 per 1,000&lt;/strong&gt; and the most-used Bilibili actor &lt;strong&gt;$20 per 1,000&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a monitoring loop
&lt;/h2&gt;

&lt;p&gt;Because no-login Weibo search only shows the newest page, the winning pattern is &lt;strong&gt;small, frequent runs plus deduplication&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Save each input as an Apify Task&lt;/strong&gt;: "brand-weibo-search", "hot-search", "category-bilibili-search".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schedule them.&lt;/strong&gt; Use &lt;code&gt;0 * * * *&lt;/code&gt; (hourly) for Weibo search and hot search, and &lt;code&gt;0 6 * * *&lt;/code&gt; (daily) for Bilibili search and comments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deduplicate on id.&lt;/strong&gt; Use &lt;code&gt;id&lt;/code&gt; for Weibo posts, &lt;code&gt;commentId&lt;/code&gt; for comments and &lt;code&gt;bvid&lt;/code&gt; for Bilibili videos. An hourly run will return many posts you already have, and that's expected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send the results somewhere.&lt;/strong&gt; Use Apify's Google Sheets or webhook integrations, or Zapier or Make, or pull the dataset from your own code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summarize.&lt;/strong&gt; A daily job reads the last 24 hours of rows and writes a trend or sentiment report. This is a good use of an LLM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At 24 hourly hot-search runs a day, that's about &lt;strong&gt;$3.60 a day&lt;/strong&gt; for a complete hourly record of China's trending list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code: Python and the Apify API
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_APIFY_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Bilibili: search + top comments
&lt;/span&gt;&lt;span class="n"&gt;bili&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dheerajitbhu/bilibili-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search&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;searchQueries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;原神&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;maxResults&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;includeComments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxComments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bili&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;likeCount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;likeCount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Weibo: hot search board
&lt;/span&gt;&lt;span class="n"&gt;weibo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dheerajitbhu/weibo-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hot_search&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;maxResults&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="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weibo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rank&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keyword&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;heat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;label&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;Both actors run a &lt;strong&gt;daily self-test against the live sites&lt;/strong&gt;. If Bilibili or Weibo blocks every request in a run, the run is marked &lt;em&gt;failed&lt;/em&gt; instead of quietly finishing "green" with zero rows, so your schedule's failure alert actually fires. Both are maintained daily against the platforms' site changes and handle their access protections for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits, ethics and data protection
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public data only.&lt;/strong&gt; Neither actor ever logs in. Comment and post rows carry only the author's public nickname and numeric id. No avatars, no IP-region tags, no private fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personal data is still personal data.&lt;/strong&gt; Nicknames and ids can identify people. If you're subject to GDPR, PIPL (China's Personal Information Protection Law) or similar rules, aggregate where you can, and keep only what your purpose needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be gentle.&lt;/strong&gt; Hourly is plenty for monitoring. The actors pace their requests. Don't run 50 copies in parallel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Respect the platforms' terms&lt;/strong&gt; and your own legal advice for your use case. This post explains what's technically reachable without login. It isn't legal advice.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Can I scrape Weibo without an account in 2026?&lt;/strong&gt;&lt;br&gt;
Yes, for the hot search board, comments, post details, profiles and the first page of search results. Deep search pagination and full timelines need a logged-in session, which these actors deliberately don't use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do I only get about 30 posts per Weibo keyword?&lt;/strong&gt;&lt;br&gt;
That's what Weibo serves to anonymous visitors: one page from each of the 综合, 实时 and 热门 tabs, merged and deduplicated. Schedule hourly runs and deduplicate on post id to build a continuous feed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I download Bilibili subtitles or danmaku text?&lt;/strong&gt;&lt;br&gt;
Subtitle text needs login, so the actor reports &lt;code&gt;hasSubtitles&lt;/code&gt; instead. Danmaku come as a per-video summary (count, unique senders, per-minute rate, peak minute, timeline sample) billed at $0.01 per video.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I get all videos from one Bilibili creator?&lt;/strong&gt;&lt;br&gt;
The creator's space page is blocked for anonymous visitors. Use &lt;code&gt;search&lt;/code&gt; with the creator's name, and use &lt;code&gt;user_profile&lt;/code&gt; for their follower and video counts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need Chinese proxies?&lt;/strong&gt;&lt;br&gt;
No. Access is handled for you inside the actors, with nothing to configure. Our live hot search run finished in 9.3 seconds with no blocks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How fresh is the data?&lt;/strong&gt;&lt;br&gt;
It's fetched live at run time. &lt;code&gt;scrapedAt&lt;/code&gt; is on every row.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I feed the output to an LLM?&lt;/strong&gt;&lt;br&gt;
Yes. Set &lt;code&gt;"outputFormat": "compact"&lt;/code&gt; to cut input tokens (by 42% for Bilibili and 25% for Weibo in our benchmark), and sort by likes before sampling.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://apify.com/dheerajitbhu/weibo-scraper" rel="noopener noreferrer"&gt;Weibo Scraper&lt;/a&gt;: search, hot search, comments, profiles. $3 per 1,000 rows.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apify.com/dheerajitbhu/bilibili-scraper" rel="noopener noreferrer"&gt;Bilibili Scraper&lt;/a&gt;: search, video stats, comments, popular, creators, danmaku summaries. $2 per 1,000 rows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leave the inputs at their defaults for a first run, or paste one of the JSON examples above. Questions or a mode you need? Email &lt;a href="mailto:apify@integrationyard.com"&gt;apify@integrationyard.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Data in this post: live runs on Oct 20, 2026 (Weibo hot search run alIwu4CFqqhdwEd2T, Bilibili popular, 50 videos), our 882-row benchmark export from Oct 18, 2026, and the public Apify Store API on Oct 20, 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>python</category>
      <category>datascience</category>
      <category>china</category>
    </item>
    <item>
      <title>Compact, Lossless JSON Output for LLM Agents: How Much Do You Actually Save?</title>
      <dc:creator>Integration Yard</dc:creator>
      <pubDate>Tue, 20 Oct 2026 07:53:13 +0000</pubDate>
      <link>https://dev.to/integrationyard/compact-lossless-json-output-for-llm-agents-how-much-do-you-actually-save-30d7</link>
      <guid>https://dev.to/integrationyard/compact-lossless-json-output-for-llm-agents-how-much-do-you-actually-save-30d7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We measured &lt;strong&gt;882 real rows&lt;/strong&gt; scraped by five of our Apify actors in three encodings: pretty JSON, minified JSON and our lossless compact output.&lt;/li&gt;
&lt;li&gt;With OpenAI's &lt;code&gt;o200k_base&lt;/code&gt; tokenizer (GPT-4o / GPT-5 family), compact output used &lt;strong&gt;33.8% fewer tokens than pretty JSON&lt;/strong&gt; and &lt;strong&gt;18.3% fewer than minified JSON&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Savings per actor ranged from &lt;strong&gt;43% (AliExpress)&lt;/strong&gt; down to &lt;strong&gt;13% (WeChat Articles)&lt;/strong&gt;. Short, repetitive rows win big; long free-text rows barely move.&lt;/li&gt;
&lt;li&gt;Every file passed a lossless round-trip check. No rows or fields dropped.&lt;/li&gt;
&lt;li&gt;At 300,000 rows a month on GPT-5.4, that is about &lt;strong&gt;$171 vs $113&lt;/strong&gt; in input tokens, or roughly &lt;strong&gt;$58 a month&lt;/strong&gt; saved for changing one input flag.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you've ever pasted a scraper export into ChatGPT or sent one to an agent as a tool result, you've paid for the same key names hundreds of times. &lt;code&gt;"title"&lt;/code&gt;, &lt;code&gt;"likeCount"&lt;/code&gt;, &lt;code&gt;"authorName"&lt;/code&gt;, &lt;code&gt;"scrapedAt"&lt;/code&gt;: in an array of JSON objects every row repeats every key, and the model bills you for each copy before it reads a single value.&lt;/p&gt;

&lt;p&gt;That cost is easy to ignore on one prompt and hard to ignore in production. An agent that pulls a few thousand rows a day, re-reads them on every turn, and runs on a frontier model can spend a real share of its budget on punctuation and repeated field names.&lt;/p&gt;

&lt;p&gt;This post is the full benchmark behind the &lt;code&gt;outputFormat: "compact"&lt;/code&gt; option in our Bilibili, Weibo, WeChat Articles, AliExpress and Douban actors on Apify. It covers what the format is, how we measured it, the per-actor results (including the ones that don't look good), what that means in dollars at current prices, when you should &lt;em&gt;not&lt;/em&gt; use it, and how to plug it into LangChain or a plain LLM call.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: we build and maintain these actors.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why tokens cost money&lt;/li&gt;
&lt;li&gt;The format: what changes, and what doesn't&lt;/li&gt;
&lt;li&gt;Methodology&lt;/li&gt;
&lt;li&gt;Results by actor&lt;/li&gt;
&lt;li&gt;What it saves in dollars&lt;/li&gt;
&lt;li&gt;How this compares to TOON, CSV and lossy compressors&lt;/li&gt;
&lt;li&gt;When not to use it&lt;/li&gt;
&lt;li&gt;Using it with LangChain and LLM pipelines&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Try it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why tokens cost money
&lt;/h2&gt;

&lt;p&gt;LLM APIs bill per token, and input tokens are usually most of the bill for data-heavy work. Your prompt holds the data, and the answer is short. Here are list prices per million input tokens as of October 2026:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input $ / 1M tokens&lt;/th&gt;
&lt;th&gt;Output $ / 1M tokens&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI GPT-5.4&lt;/td&gt;
&lt;td&gt;$2.50&lt;/td&gt;
&lt;td&gt;$15.00&lt;/td&gt;
&lt;td&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;OpenAI pricing&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI GPT-5&lt;/td&gt;
&lt;td&gt;$1.25&lt;/td&gt;
&lt;td&gt;$10.00&lt;/td&gt;
&lt;td&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;OpenAI pricing&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI GPT-5 mini&lt;/td&gt;
&lt;td&gt;$0.25&lt;/td&gt;
&lt;td&gt;$2.00&lt;/td&gt;
&lt;td&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;OpenAI pricing&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic Claude Sonnet 5.5&lt;/td&gt;
&lt;td&gt;$2.00&lt;/td&gt;
&lt;td&gt;$10.00&lt;/td&gt;
&lt;td&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Anthropic pricing&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A token is not a character or a word. Tokenizers split text into chunks they've learned are common. That means JSON's structure isn't free: quotes, colons, commas, braces, the newlines and indentation in pretty-printed JSON, and above all the repeated key names all become tokens.&lt;/p&gt;

&lt;p&gt;Here's a quick way to see it. In our benchmark, one pretty-printed row averaged &lt;strong&gt;228 tokens&lt;/strong&gt; with the &lt;code&gt;o200k_base&lt;/code&gt; tokenizer. The same row averaged &lt;strong&gt;185 tokens&lt;/strong&gt; minified and &lt;strong&gt;151 tokens&lt;/strong&gt; in compact form. The data didn't change. Only the packaging did.&lt;/p&gt;

&lt;p&gt;Three things make this worse in agent workloads than in one-off prompts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Re-reading.&lt;/strong&gt; An agent loop sends the whole conversation, tool results included, back to the model on each turn. A 40,000-token tool result read five times costs 200,000 input tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context limits.&lt;/strong&gt; Even with very large context windows, fewer tokens per row means more rows fit before you hit the limit or have to chunk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency.&lt;/strong&gt; Prompt processing time grows with input length, so a smaller prompt also comes back faster.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Prompt caching and batch discounts help too, and they stack with what follows. Fewer tokens is still fewer tokens, whether they're billed at the full or the cached rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The format: what changes, and what doesn't
&lt;/h2&gt;

&lt;p&gt;A normal scraper export is an array of JSON objects, and every row repeats every key name:&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BV1xx"&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;"2026 keyboard roundup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"views"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12034&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BV2yy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"views"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;877&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;Compact output is our token-optimized encoding of exactly the same rows. It removes the structural repetition that LLMs bill you for, and keeps everything that matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lossless.&lt;/strong&gt; Every value, type and &lt;code&gt;null&lt;/code&gt; survives, and so does the difference between a field that's &lt;code&gt;null&lt;/code&gt; and a field that's absent. Plenty of "compact" formats quietly lose that last one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Still JSON.&lt;/strong&gt; Any JSON parser reads it. No new parser, no new library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robust on messy, real data.&lt;/strong&gt; Mixed row shapes, Chinese text, nested lists and unusual characters are all handled. We verify the round trip on every format change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Additive.&lt;/strong&gt; Your normal dataset is untouched. The compact copy is an extra record on the same run, at no extra cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Getting all of that right at once is harder than it looks, which is why we built it into the actors rather than leaving it as an exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Methodology
&lt;/h2&gt;

&lt;p&gt;We wanted numbers we'd be comfortable defending, so the benchmark is deliberately boring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real data, not synthetic.&lt;/strong&gt; 882 rows exported from real runs of five actors: AliExpress (130 rows), Bilibili (406), Douban (150), Weibo (119) and WeChat Articles (77). They're mostly flat rows (a few fields hold small lists), and some exports mix row shapes, such as Bilibili comments next to replies and Weibo posts next to comments, because that's what real exports look like.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three encodings of the exact same rows.&lt;/strong&gt; Pretty JSON (&lt;code&gt;json.dumps(rows, indent=2, ensure_ascii=False)&lt;/code&gt;), minified JSON (&lt;code&gt;separators=(",", ":")&lt;/code&gt;), and compact output, exactly as the actor writes it to the &lt;code&gt;OUTPUT_COMPACT&lt;/code&gt; key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A lossless check first.&lt;/strong&gt; Each file had to round-trip back to the exact original rows before we measured it. A format that drops data can always look smaller, so this check comes first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two real tokenizers.&lt;/strong&gt; &lt;code&gt;tiktoken&lt;/code&gt; with &lt;code&gt;o200k_base&lt;/code&gt; (GPT-4o, GPT-4.1 and GPT-5 family) and &lt;code&gt;cl100k_base&lt;/code&gt; (GPT-4 / GPT-3.5). The headline numbers use &lt;code&gt;o200k_base&lt;/code&gt;. &lt;code&gt;cl100k_base&lt;/code&gt; came out within about two points (31.7% vs pretty, 17.1% vs minified).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two baselines.&lt;/strong&gt; Many "X% smaller than JSON" claims compare against pretty JSON, which is the easy baseline. We report both, and we think &lt;strong&gt;minified JSON is the honest one&lt;/strong&gt;, because it's what a careful pipeline already sends.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What we did &lt;strong&gt;not&lt;/strong&gt; measure: downstream answer accuracy, and non-OpenAI tokenizers such as Claude's, Llama's or Qwen's. Independent TOON benchmarks show savings vary by tokenizer, so measure on the model you actually use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fudjyzqwtm0njqcf1c55q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fudjyzqwtm0njqcf1c55q.png" alt="Horizontal bar chart of total tokens for the same 882 rows: pretty JSON 201,384, minified JSON 163,131, compact output 133,220" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Results by actor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6ekcf4dik3qyibyb2ip4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6ekcf4dik3qyibyb2ip4.png" alt="Bar chart of token savings per actor. Versus pretty JSON: AliExpress 43.1%, Bilibili 41.9%, Douban 39.6%, Weibo 24.8%, WeChat Articles 12.8%. Versus minified JSON: 25.6%, 25.9%, 22.3%, 4.9%, 6.2%" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;Rows&lt;/th&gt;
&lt;th&gt;Pretty&lt;/th&gt;
&lt;th&gt;Minified&lt;/th&gt;
&lt;th&gt;Compact&lt;/th&gt;
&lt;th&gt;vs pretty&lt;/th&gt;
&lt;th&gt;vs minified&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AliExpress Scraper&lt;/td&gt;
&lt;td&gt;130&lt;/td&gt;
&lt;td&gt;42,425&lt;/td&gt;
&lt;td&gt;32,461&lt;/td&gt;
&lt;td&gt;24,154&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;43.1%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;25.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bilibili Scraper&lt;/td&gt;
&lt;td&gt;406&lt;/td&gt;
&lt;td&gt;67,672&lt;/td&gt;
&lt;td&gt;53,034&lt;/td&gt;
&lt;td&gt;39,320&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;41.9%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;25.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Douban Scraper&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;td&gt;26,632&lt;/td&gt;
&lt;td&gt;20,696&lt;/td&gt;
&lt;td&gt;16,091&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;39.6%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;22.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weibo Scraper&lt;/td&gt;
&lt;td&gt;119&lt;/td&gt;
&lt;td&gt;22,611&lt;/td&gt;
&lt;td&gt;17,879&lt;/td&gt;
&lt;td&gt;17,010&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;24.8%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WeChat Articles Scraper&lt;/td&gt;
&lt;td&gt;77&lt;/td&gt;
&lt;td&gt;42,044&lt;/td&gt;
&lt;td&gt;39,061&lt;/td&gt;
&lt;td&gt;36,645&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12.8%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;All five&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;882&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;201,384&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;163,131&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;133,220&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;33.8%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;18.3%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Token counts with &lt;code&gt;o200k_base&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Three patterns explain the spread:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Short values plus many fields means big wins (AliExpress, Bilibili, Douban: 40–43%).&lt;/strong&gt; Product listings, video comments and book or film entries have lots of short fields: IDs, prices, counts, timestamps, short titles. Structure is a large share of each row, so removing the repetition removes a large share of the tokens. Bilibili gets an extra boost from row count: the more rows, the bigger the saving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Mixed row shapes cut into the gain (Weibo: 25% vs pretty, under 5% vs minified).&lt;/strong&gt; A Weibo export mixes 22-key posts with 10-key comments. Rows of very different shapes share less structure, so there's less repetition to remove. If you filter to one row type, you'd recover most of the gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Long free text leaves little to remove (WeChat Articles: 13%).&lt;/strong&gt; WeChat rows are mostly article titles and summaries in Chinese, so the values already dominate the token count. Removing repetition still helps, but there's not much structure left to strip.&lt;/p&gt;

&lt;p&gt;Bytes tell the same story, with slightly larger gains: 40–46% fewer UTF-8 bytes for AliExpress, Bilibili and Douban against pretty JSON. That matters if you store or move exports at volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it saves in dollars
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4yugwfnqtixaaextuyft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4yugwfnqtixaaextuyft.png" alt="Grouped bar chart of monthly input cost for 300,000 rows: GPT-5.4 $171 pretty, $139 minified, $113 compact; GPT-5 $86, $69, $57; GPT-5 mini $17, $14, $11" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a worked example using the measured per-row averages: 228.3 tokens pretty, 185.0 minified and 151.0 compact.&lt;/p&gt;

&lt;p&gt;Say an agent ingests &lt;strong&gt;10,000 scraped rows a day&lt;/strong&gt; (about 300,000 a month) and reads each row once:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Pretty JSON&lt;/th&gt;
&lt;th&gt;Minified JSON&lt;/th&gt;
&lt;th&gt;Compact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input tokens / month&lt;/td&gt;
&lt;td&gt;68.5M&lt;/td&gt;
&lt;td&gt;55.5M&lt;/td&gt;
&lt;td&gt;45.3M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 at $2.50 / 1M&lt;/td&gt;
&lt;td&gt;$171.24&lt;/td&gt;
&lt;td&gt;$138.72&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$113.28&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5 at $1.25 / 1M&lt;/td&gt;
&lt;td&gt;$85.62&lt;/td&gt;
&lt;td&gt;$69.36&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$56.64&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5 mini at $0.25 / 1M&lt;/td&gt;
&lt;td&gt;$17.12&lt;/td&gt;
&lt;td&gt;$13.87&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$11.33&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On GPT-5.4, switching from pretty JSON saves &lt;strong&gt;about $58 a month (~$696 a year)&lt;/strong&gt;. Switching from minified saves about $25 a month. If the agent re-reads the data across several turns, multiply both by the number of reads. On a mini model the dollar savings are small, but you can fit about a third more rows into the same context.&lt;/p&gt;

&lt;p&gt;These are input costs only, at OpenAI list prices from October 2026, and they use the OpenAI tokenizer we measured. Claude uses a different tokenizer, so check your own counts before applying these percentages to Claude prices.&lt;/p&gt;

&lt;h2&gt;
  
  
  How this compares to TOON, CSV and lossy compressors
&lt;/h2&gt;

&lt;p&gt;Token-efficient formats are a crowded topic right now, so it's worth placing this one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TOON (Token-Oriented Object Notation)&lt;/strong&gt; is the best-known "JSON for LLMs" format. It uses a YAML-like layout with tabular arrays. &lt;a href="https://github.com/ErcinDedeoglu/toon-vs-json-benchmark" rel="noopener noreferrer"&gt;Independent benchmarks&lt;/a&gt; report about &lt;strong&gt;34% fewer tokens than minified JSON on uniform tabular data&lt;/strong&gt;, but &lt;strong&gt;14–17% *more&lt;/strong&gt;* on nested or semi-uniform data, and smaller savings on non-OpenAI tokenizers. The author also notes that the widely quoted "40–60%" figure is measured against &lt;em&gt;pretty&lt;/em&gt; JSON. Our numbers sit in the same range for the same reason. Tabular data compresses well, and mixed shapes don't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSV&lt;/strong&gt; is very compact for flat tables, but it has no types (is &lt;code&gt;"123"&lt;/code&gt; a string or a number?), no &lt;code&gt;null&lt;/code&gt;, and no way to say "this key was absent". The &lt;a href="https://www.mintlify.com/toon-format/toon/advanced/benchmarks" rel="noopener noreferrer"&gt;TOON project's own benchmarks&lt;/a&gt; exclude CSV from parts of their accuracy tests because it can't represent the non-flat datasets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lossy "AI compressors"&lt;/strong&gt; can post bigger headline numbers by summarizing or sampling. We tested one (headroom) on the same kind of files, and it dropped rows or fields on 7 of 8 sample datasets. That's fine for an agent's scratch memory, but not for data a customer is paying to receive intact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent-loop caveat.&lt;/strong&gt; A 2026 study of &lt;a href="https://arxiv.org/html/2605.29676v2" rel="noopener noreferrer"&gt;token-optimized formats in agentic systems&lt;/a&gt; found that formats which shrink tool &lt;em&gt;outputs&lt;/em&gt; the model must &lt;em&gt;write&lt;/em&gt; can increase total cost when parsing failures trigger extra turns. Compact output is an &lt;strong&gt;input&lt;/strong&gt; format: the model reads it and never has to produce it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We built compact output to be plain JSON that keeps types and &lt;code&gt;null&lt;/code&gt; and round-trips exactly, so it's safe for data a customer is paying for.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use it
&lt;/h2&gt;

&lt;p&gt;Compact output isn't always the right call. Skip it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You're loading a spreadsheet, BI tool or database.&lt;/strong&gt; Use the normal dataset export in CSV, Excel or JSON. The compact format exists to cut LLM tokens, not to replace ordinary exports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your rows are mostly long text.&lt;/strong&gt; As the WeChat result shows, savings drop toward 10%, and per-row objects can be easier to debug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're mixing very different row types in one table.&lt;/strong&gt; Weibo's posts plus comments showed this. Either filter to one row type, or accept the smaller gain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need row-level retrieval.&lt;/strong&gt; For RAG, you usually embed one row or chunk at a time. Each chunk is small, so the saving shrinks. Compact output pays off when you send &lt;em&gt;many rows together&lt;/em&gt; in one prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The model has to &lt;em&gt;produce&lt;/em&gt; this format.&lt;/strong&gt; Keep model outputs in ordinary JSON or structured outputs. Use compact for what the model reads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You already minify, and your volume is tiny.&lt;/strong&gt; At a few hundred rows a month, an 18% saving on minified JSON is worth less than your time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using it with LangChain and LLM pipelines
&lt;/h2&gt;

&lt;p&gt;Set &lt;code&gt;"outputFormat": "compact"&lt;/code&gt; on the run. The dataset is unchanged and so is the price. The actor also writes the compact copy to the run's key-value store under &lt;code&gt;OUTPUT_COMPACT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Fetch it with the Apify client&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_APIFY_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dheerajitbhu/aliexpress-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search&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;searchQueries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mechanical keyboard&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;maxResults&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outputFormat&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;compact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key_value_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultKeyValueStoreId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;get_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OUTPUT_COMPACT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# compact copy of the run's rows
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Field names in &lt;code&gt;run_input&lt;/code&gt; vary by actor. Check each actor's input tab.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Send it straight to the model&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Below are AliExpress product rows in compact JSON.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;+&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;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ensure_ascii&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;separators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Which five products have the best rating-to-price ratio?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&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;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Use it as an agent tool result in LangChain&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;latest_products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return current AliExpress listings for a query in compact JSON.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dheerajitbhu/aliexpress-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search&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;searchQueries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxResults&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outputFormat&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;compact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;rec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key_value_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultKeyValueStoreId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;get_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OUTPUT_COMPACT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;ensure_ascii&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;separators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because tool results are re-sent on every later turn of the agent loop, the savings repeat every time the agent reads that result again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Need regular dicts?&lt;/strong&gt; For pandas, LangChain &lt;code&gt;Document&lt;/code&gt;s or a vector store, read the normal dataset from the same run. It's always there, unchanged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_core.documents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&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="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;r&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;strong&gt;Is it really lossless?&lt;/strong&gt;&lt;br&gt;
Yes, within what JSON can represent. Every benchmark file round-tripped back to the exact original rows, including real &lt;code&gt;null&lt;/code&gt;s and keys absent from some rows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does compact output change what I pay for the actor?&lt;/strong&gt;&lt;br&gt;
No. The run pushes the same rows to the dataset at the same per-result price. &lt;code&gt;OUTPUT_COMPACT&lt;/code&gt; is an extra key-value store record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do LLMs understand the compact shape?&lt;/strong&gt;&lt;br&gt;
In our use, yes, It reads like a table. We haven't run a formal accuracy benchmark, so test your own task if accuracy is critical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not just use CSV?&lt;/strong&gt;&lt;br&gt;
CSV loses types and can't tell &lt;code&gt;null&lt;/code&gt; from an absent key. Compact output keeps both and still parses with &lt;code&gt;json.loads&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this work with Claude, Gemini or open models?&lt;/strong&gt;&lt;br&gt;
The format works with any model. The &lt;em&gt;percentages&lt;/em&gt; above come from OpenAI tokenizers, and other tokenizers will give different numbers. The structural saving, writing keys once instead of N times, applies everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why are your numbers smaller than some format headlines?&lt;/strong&gt;&lt;br&gt;
Big headline numbers usually come from comparing against pretty-printed JSON on perfectly uniform synthetic data. On 882 real, messy rows we measured 13–43% per actor against pretty JSON and 18% overall against minified. We'd rather quote the smaller, real number.&lt;/p&gt;

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

&lt;p&gt;Compact output is available on five Integration Yard actors on Apify. Add &lt;code&gt;"outputFormat": "compact"&lt;/code&gt; to any run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://apify.com/dheerajitbhu/aliexpress-scraper" rel="noopener noreferrer"&gt;AliExpress Scraper&lt;/a&gt;: 43% fewer tokens than pretty JSON in our benchmark&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apify.com/dheerajitbhu/bilibili-scraper" rel="noopener noreferrer"&gt;Bilibili Scraper&lt;/a&gt;: 42%&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apify.com/dheerajitbhu/douban-scraper" rel="noopener noreferrer"&gt;Douban Scraper&lt;/a&gt;: 40%&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apify.com/dheerajitbhu/weibo-scraper" rel="noopener noreferrer"&gt;Weibo Scraper&lt;/a&gt;: 25%&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://apify.com/dheerajitbhu/wechat-articles-scraper" rel="noopener noreferrer"&gt;WeChat Articles Scraper&lt;/a&gt;: 13%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apify's free plan includes monthly platform credit, so you can run it on your own query and count the tokens yourself. If your numbers differ from ours, email &lt;a href="mailto:apify@integrationyard.com"&gt;apify@integrationyard.com&lt;/a&gt;. We'll publish corrections.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Benchmark data: 882 rows, &lt;code&gt;tiktoken&lt;/code&gt; &lt;code&gt;o200k_base&lt;/code&gt; and &lt;code&gt;cl100k_base&lt;/code&gt;, October 2026. Prices are list prices checked October 20, 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>ai</category>
      <category>llm</category>
      <category>json</category>
    </item>
  </channel>
</rss>
