- A keyword with too little search volume no longer stops the rest of your run. Google answers a long-tail term below its volume floor with a complete, empty answer. The run used to read that as upstream trouble, retry it on three routes, and — after a few such terms in a row — stop early saying Google was rate-limiting broadly, leaving the rest of your list unattempted. It is now reported as a keyword with no data, never charged, and the run works through your whole list. A real rate limit, a blocked route and a torn answer are unchanged: still retried, still able to stop a run early.
- A trending-searches feed that answers with nothing published is reported as that, not as upstream trouble.
- The run status line names the keywords Google had no data for, and a run whose only outcome is that answer no longer asks you to open an issue about it.
- An unexpected error while collecting trending searches no longer ends the whole run. It is reported as that one unit's miss, and everything the run had already delivered stays delivered and charged as it was.
- A run refused for an input mistake now tells us which field was refused — the field's name only, never the value you typed. A check that is too strict now reaches us as one thing to fix instead of looking like many unrelated typos.
- A region or category Google does not recognise is now told to you as such. When Google refuses the request outright, the run used to retry it on three different routes and then report it as temporary upstream trouble with "please re-run shortly" — for an input that would have been refused again every time. The row now says the request was refused, names the region and category fields to check, and the run still costs nothing. A genuine rate limit, an empty answer and a server error are unchanged.
- A run that stops before it starts now reports its outcome too — a run refused for its memory setting, and a run given an input it cannot act on, now reach us the same way every other run does: counts and reason codes only, never your input or your rows.
- The zero-network sample run and the ledger-blocked exit now report their outcome too — the run record reaches us on those paths as well.
- Every run now reports its own outcome to us — counts and reason codes only, never your input or your rows — so a run that goes wrong reaches us even when nobody shares it.
- A mistyped input field no longer pushes the run's own counts off the page.
- Run status lines fit the run page again; sample-run wording shortened.
A run that resumes after a platform restart now recognises every row it already delivered, so nothing is delivered or charged twice.
Apify occasionally moves a running actor to another server. When that happens, the run re-reads its own dataset to remember what it already delivered. Until now it trusted the dataset's row count, which can lag for a moment after a restart; a lagging count could make the run start over and charge again for rows you already had, stop before the end, or stop the run outright as a precaution. The run now checks for real rows instead of trusting the count, and reads to the end whatever the count says. Rows, prices, charges and the status line on a normal run are exactly as before.
- A run that ends with a problem now says where to reach us. A miss, an input error, an early stop or a failed run closes by pointing at the Issues tab and naming the reply time; a fully delivered run is left alone.
- One support promise across this page — issues are answered in a couple of hours, always within a day.
The two screenshots on this page now load from Apify's own storage instead of an outside website, and the opening line names Google Trends in plain text rather than linking to it. Same pictures, same words, same page. Nothing about what this actor delivers or charges changed.
The comparison table on this page no longer links out to another vendor's website. The row still names the product and quotes its listed price, read on the date shown, exactly as before. Nothing about what this actor delivers or charges changed.
The suite blocks at the bottom of this page now state the three delivery-conditional fees that start 16 September 2026 on sibling actors — keyword volume's fresh lookup, profile posts' profile lookup, and Google Jobs' search fee. This page also now says "nothing charged for starting a run" wherever it used to say "no start fee" — the same promise, in the words the whole shelf uses. Nothing changes on this actor: same price, same events, same rows.
This page now opens with what you get and what it costs, shows the input form and a real result table, and compares this actor with the alternatives on public numbers. Nothing about what this actor delivers or charges changed.
- What you get, then what it costs, then the guarantee. The first screen used to lead with the no-charge-on-miss promise; it now leads with the data — the surfaces, the row shape, today's price — and keeps the promise where it belongs, right after.
- Two real screenshots. The input form, and the dataset table from a real run (
bitcoin and ethereum, three surfaces, US, past 12 months) — so you can see the output before you run it.
- How it compares. A table of the alternatives — Apify's own Google Trends scraper, the most-used third-party one, SerpApi and pytrends — on listed price, what one unit is, whether platform usage is billed on top, start fees and public success rates, all read on the date shown.
- The trending-now row shape, stated exactly. Keyword rows carry the full eleven-field envelope; trending-now rows carry five (
schemaVersion, surface, geo, fetchedAt, data) because a trending feed has no keyword or time range. This page used to say every row carried the same envelope; it now says which rows carry which.
- Suite links carry the current names of every steadyfetch actor, and the MCP snippet uses the current
tools= form of the server URL.
Sending null for a setting you do not want now means "use the default", instead of stopping the run before it starts.
- An optional setting sent as
null now takes its default. Agents, n8n templates and MCP callers routinely fill every field in a template and send null for the ones they have no value for. Until now Apify refused those runs before the container even started — you got a validation error, no run and no rows, and the fix was to know that you had to leave the key out entirely. Every setting on this actor now accepts null and reads it as "use the default", which is exactly what omitting it does.
searchTerms sent as null returns the sample rows. That is what leaving the field out has always done, and the two now behave identically. An explicitly empty list still asks you for terms — sending [] is a choice, sending null is not.
- The Search property field now also accepts a value typed straight in. It is still the same dropdown with the same five properties, but it no longer refuses anything else outright — which is what let it accept
null. A value that is not one of them is still refused, uncharged, and the message now names the ones that work; before, Apify refused it with a generic validation error. Nothing is ever quietly measured on the wrong property.
The linked example dataset is re-shot from a run of the current build. Nothing about what this actor delivers or charges changed.
- The example dataset now shows exactly what a paid run returns today — the three
bitcoin surfaces worldwide (each row reading "geo": "worldwide") plus the US trending-now feed, 13 rows, unedited. The output table on this page quotes that run.
Worldwide rows now say so, and the run's own summary row is in place for the day it can ship free of charge. Nothing about what this actor charges changed.
- A row from a run with no location set now reads
"geo": "worldwide" instead of an empty string. A blank in that column could not tell you whether the run was worldwide or the field had failed; the word can. Your input is unchanged — leave geo empty for worldwide, exactly as before.
- The uncharged run-summary row, held until it can be free. Every steadyfetch actor ends its dataset with one uncharged
_summary row — how many results were delivered, exactly what was charged, and why the run stopped — that reconciles against the rows above it. On this listing's current billing every row written to the dataset is a charged result, so that row is deliberately not written yet rather than charged to you. It will appear, uncharged and last, as soon as the listing's billing can carry a free row; nothing in today's datasets changes.
Related topics now tells you the one thing worth knowing when it comes back empty, and no failure message describes machinery instead of your result. Nothing about what this actor delivers or charges changed.
- A related-topics result that does not arrive now says what to do about it. Google meters its topics feed and serves it to a limited number of lookups at a time, so this one surface can come back empty on a busy moment. The report used to describe the refusal in our own terms and offer generic advice — narrowing an input, which recovers nothing on a single-keyword topics run. It now says plainly that related topics is a live surface that normally delivers, that nothing was charged, and that running the same input again a minute or two later normally works. This actor's own runs bear that out: the surface delivered real topic entities the same day.
- The related-topics caveat is now stated on this page, before you buy. The listing sold the surface without mentioning that a lookup can come back empty. It is the only surface here with that caveat, and it is now written into the table, the surface's description in the input form, and the FAQ — along with the fact that an empty topics lookup is never charged and never shipped as an empty row.
- Failure reports describe your result, not our retry machinery. The report attached to a run said how many fetches "failed after retries", described "empty payloads" and "degraded answers", and labelled every entry with an internal word. It now names what did not arrive, whether running again is worth your time, and where the detail is — using the same three-word vocabulary the rest of this suite uses.
This page's wording refreshed — what happens on a blocked or empty fetch is now described more plainly. Nothing about what this actor delivers or charges changed.
Clearer release notes — this page's notes now read more plainly. Nothing about what this actor delivers or charges changed.
Suite links now point at the full live shelf — every actor named in this README is a live
store link. Nothing about what this actor delivers or charges changed.
Review-fix build: what you are charged and what your dataset shows now agree in every failure the platform can produce.
- A result that fails to save no longer leaves its billing record behind. When results were fetched but the dataset save failed, the run's own books still marked that keyword as delivered and billed — so when another surface later delivered the same keyword, its rows could ship with an incomplete billing record and the run's accounting disagreed with the dataset. The books are now written only after the save lands: a failed save is still reported exactly as before, nothing is marked done, and every row's billing record matches what actually reached your dataset.
- A resumed run that cannot trust its own delivery record now stops rather than charging again. Right after a run is moved or resurrected, the dataset read-back can momentarily lag behind what has already been charged. A run that trusted such a read would start the work over — fetching, delivering and charging a second time for results you had already paid for. It now notices that its charges exceed what the record shows, stops cleanly without charging anything more, and says so. Re-running once the record has settled carries on normally.
- A pricing record that momentarily lists no billable event can no longer be spent against. While a pricing change rolls out there can be an instant where nothing on the listing is billable at all. Such a run used to read its budget as unlimited and could work through your whole input; it now stops before spending anything, says the pricing record needs fixing, and never stamps a row as charged. The two normal in-between states of a pricing rollout are unaffected and behave exactly as before.
An answer with nothing in it is no longer a row, and a run that stops early now tells you exactly what is left.
- An empty related-queries or related-topics answer is no longer delivered or charged. Google sometimes answers a related request with a well-formed reply that carries no queries and no topics at all. That reply used to become a row in your dataset — an empty
top and an empty rising — and it was charged like any other result. It now delivers nothing and costs nothing. Under the current pricing that simply means the row does not appear; the keyword's other surfaces are unaffected and still deliver normally.
- A run stopped by your cost cap during Trending now no longer says "0 results left". When your maximum cost per run cut the trending feed short, the status line reported nothing left to fetch — telling you a raised cap would buy you nothing. It now reports the exact number of trending results the cap left behind, so "raise Maximum cost per run to fetch everything" means what it says.
- An input field name this actor does not recognise is now named back to you, even when the run still has work to do. Sending a typo like
searchTerm alongside Trending now, or a misspelled setting beside real search terms, used to be silently dropped: the run did the part it could read and never mentioned the part it could not. The run still does that work, and the status line now names every field it did not recognise so you can see what was ignored.
- Related topics will be billed as its own kind of report. Related topics costs us considerably more to fetch than the other surfaces, so it is being separated from the general trend report onto its own event rather than being averaged into everyone's price. Nothing on your bill changes until the actor's pricing record lists that event, and Apify notifies every pricing change in advance — until then, related-topics rows are delivered without a separate charge.
Related topics is now a real surface — delivered rows, never empty ones.
- New opt-in surface:
relatedTopics. Add it to surfaces to get the related topics for a keyword — the top and rising topic entities, each with its knowledge-graph id (mid), title, type, score, and explore link, in the same schema-stable row envelope as every other surface. It is opt-in and stays out of the default surfaces, so existing runs and their costs are unchanged. In compare mode it is per-keyword (no shared scale) and is left out, exactly like related queries.
- Why it was not offered before, and what holds now. Google withholds the topics feed from most automated sessions — the reason this actor previously declined to sell the surface, and the reason tools that do sell it typically ship empty topics lists. This release fetches topics in a way Google actually answers. When Google still withholds or rate-limits a topics fetch, it is retried on a fresh connection and, if it cannot be delivered, it is reported in
ERRORS and never charged — an empty answer never becomes a row in your dataset.
An empty answer we could not confirm is now something to re-run, never a verdict on your keyword.
- An empty reply that survives every retry is no longer reported as "no data for this keyword". Google sometimes serves a valid-looking but empty reply when it is struggling, and from the outside that reply is indistinguishable from a keyword that truly has no data. A keyword whose every fresh attempt came back empty used to be given a definitive "Google Trends returned no data in the selected time range and region" plus advice to change your input — a temporary problem described as a permanent one. It is now reported as a temporary, uncharged miss that asks you to re-run shortly, and only suggests broadening your input if it keeps happening.
- A broad wave of empty answers now stops the run early with re-run guidance. When several keywords in a row come back empty and nothing has been delivered, the run stops and says so — the same early stop a broad rate-limit wave already gets — instead of working the whole list and blaming every keyword. The stop message and the nothing-delivered message now name empty answers alongside rate limits, so the status always describes what actually happened.
- A preparation step that answers incompletely is retried instead of surfacing an unclear failure. Each surface needs a small preparation step before it can fetch data. When that step comes back well-formed but incomplete, it is now recognised as the same temporary degradation as an empty data reply and retried on a fresh connection; previously it could surface as an unclear error, and a run that delivered nothing because of it could read as failed.
- A typo in an input field name now gets a helpful pointer instead of sample rows. Apify ignores any field an actor does not declare, so an input like
{"keywords": ["bitcoin"], "geo": "GB"} used to look exactly like a run with no input at all and came back with the frozen sample rows — reading as if the typo had worked. Such a run now stops immediately, uncharged, with a message naming the field it did not recognise and naming searchTerms as the field you meant. Sending only settings — a location, a time range — with no search terms gets the same pointer. A run with no input at all still returns the sample rows exactly as before, and a run that does carry search terms is unchanged, unknown field beside it or not.
- A bad value is now always reported, even when no search terms came with it. An unusable
timeRange or an unknown entry in surfaces sent without search terms used to be answered with sample rows and never mentioned; that run now stops with the message explaining the value, as it already did whenever search terms were present.
- The run status speaks one vocabulary. A run that stops early — at your cost cap, at the timeout, or during a broad Google rate-limit wave — now tells you what is left in the same terms the rest of the status and the pricing use: results, one keyword × one surface. Previously the same message mixed "results delivered" with "units left". The count is exact: anything already delivered, including by an earlier server before a migration, is never counted as left, and a not-yet-fetched Trending now feed is named rather than estimated as a number.
- Fixed: retries of rate-limited requests work again. The fresh connection used to retry a request Google had rate-limited could be rejected by an internal naming check before it ever reached Google, so that retry failed instantly instead of fetching your data. Affected fetches were reported as failed and were never charged; they now retry as designed.
- Runs now stop cleanly at your time limit instead of being cut off. When the time left in a run is no longer enough to safely finish the next fetch — including its retries and cool-downs — the run ends on its own with an honest partial status ("stopped before the run timeout with N unit(s) left") instead of being killed mid-fetch by the platform timer. Everything already delivered stays in your dataset, and nothing undelivered is charged.
- The sample run no longer depends on Google's mood. Running the actor with no search terms now returns a small frozen sample — real rows from a "bitcoin" capture, one per surface — that shows the exact output shape without contacting Google at all. Put your own keywords in
searchTerms to fetch live data. A trending-now-only run no longer also fetches the sample keyword.
- Interest by region is never delivered — or charged — as an empty answer. Google sometimes replies to a by-region request with a valid but empty result. That reply used to be accepted at face value: the run delivered a row whose region list was empty, and charged for it. It is now recognised for what it is, retried on a fresh connection, and if Google still will not answer, the keyword is reported as an uncharged miss instead. The other surfaces already worked this way; by-region was the last one that did not.
- A run no longer ends on an unclear error when Google rate-limits the retry itself. The fallback used to set up its retry outside the normal retry path, so a rate-limit hit during that step escaped as an unexplained failure rather than being retried like every other rate-limited request.
- Faster runs, same price. Requests now go out on the run's own connection first and only fall back to a fresh identity to retry something Google rate-limited. In our own measurements every rate-limited request retried that way came back with data on the next try. Typical runs finish noticeably quicker; what you pay per result is unchanged.
- An interrupted run no longer repeats itself. If Apify moves your run to another server mid-way — or you resurrect a finished run — it now recognises the results already sitting in your dataset. Nothing is fetched twice, no duplicate rows appear, and nothing is charged twice. If a charge was interrupted after a result was delivered, the run settles that one charge and only that one.
- A run moved between servers keeps its original time budget instead of starting a fresh one, so a long job cannot quietly run twice as long.
- A "Maximum cost per run" that affords exactly one result now delivers that one result, instead of stopping with nothing and asking you to raise a cap that was already enough.
- The Proxy country field now describes what it actually does: it applies only to the connection used to retry a rate-limited request. Most runs never need it.
- The suite directory now links the sibling actors that have gone live.
- A run no longer stops dead if saving results or recording a charge fails part-way through. It now finishes with a clear status, the rows already delivered stay in your dataset, and nothing undelivered is ever charged — the details land in
ERRORS.
- Delivery and billing problems on our side are now reported separately from failed fetches, so a run that did deliver your rows never reads as "the fetch failed". A "no data from Google" notice row is no longer written when the problem was ours.
- Keywords that Google genuinely answers with no data no longer count toward the "Google is rate-limiting broadly" early stop, so a list that starts with a few empty keywords is now worked all the way through. A real rate-limit wave still stops early exactly as before.
- README: added the unofficial / not-affiliated-with-Google note, and refreshed the directory of the other steadyfetch actors.
- Fixed: a compare run started from the form's default surface selection no longer fails. Compare now returns the surfaces that share a 0–100 scale — interest over time and interest by region — and skips related queries, which is per-keyword and has no shared scale. Related queries stay available in a normal (non-compare) run.
- The README now opens with an Output section — a table of real rows from the live example run, the compare screenshot, and the full JSON envelope — so you can see exactly what a result looks like before spending anything.
- Added a copy-and-paste block for AI agents and LLM clients: the actor id, a complete input example with every option explained, the output fields, and the event price.
- Clearer compare-mode guidance: related queries is a per-keyword surface with no shared scale, so leave it out of a compare run and fetch it in a separate run.
- New directory of the other steadyfetch actors — Facebook, Google Ads, TikTok, LinkedIn and Instagram Reel transcripts — with their free n8n templates.
- Billing accuracy improvement for runs with a Maximum cost per run: capped runs now deliver every result the cap affords — a rounding quirk could previously stop one result early.
- Documentation: pricing examples updated to the current paid-plan tier prices.
- Runs started with memory outside the tuned range (256 MB–2 GB) now exit immediately with clear guidance — nothing charged. Normal runs are unaffected; the input form already uses the right range.
- The default run memory is now 256 MB (was 512) — validated side-by-side with identical results. Pricing is per-result and unchanged.
- When Google is rate-limiting broadly, zero-result runs now stop early with clear retry guidance instead of slowly working through the whole keyword list. You're charged nothing either way — this just saves time.
- The status message for zero-result runs now reflects all-inclusive pricing correctly: such runs cost you nothing at all.
- Every run now finishes within a bounded time window, regardless of custom timeout settings — no more runs that linger.
- Search terms are capped at 300 per run (documented in the input form); split larger lists across runs.
- Quieter run logs: transient retry chatter moved to debug level.
- Runs with a tight Maximum cost per run now keep a little more headroom near the cap, removing rare cases where the platform could abort a capped run right at its ceiling instead of the run stopping cleanly with a "raise your cap" message. Nothing changes about what you're charged.
- Pricing docs updated: the transitional notes from the July 19 all-inclusive change-over are gone — one flat price per result is simply how it works now.
- The default run timeout is now 10 minutes (was 60). Typical runs finish in well under two; large batches can raise the timeout in run options as always.
- Pricing becomes all-inclusive on July 19, 2026 (announced to all users): platform usage will be included in the event price — one flat, predictable price per result, no separate usage line, and retries for failed fetches cost you nothing at all.
- The run-budget logic now follows the actor's active pricing model automatically: under the new pricing, runs with a Maximum cost per run deliver the full number of results the cap affords (the old model's usage headroom no longer applies once usage stops being billed separately).
- README pricing section updated for the transition.
- A run that returns no results only because Google rate-limited or blocked every request now finishes as a successful run (no result fee charged) with a clear "please retry shortly" message — instead of failing. You never pay a result fee for a run that delivered nothing, and genuine errors still fail loudly so you notice them.
- Runs that reach your "Maximum cost per run" now always stop cleanly with a "raise your cap to fetch everything" message instead of being aborted mid-run.
- Input mistakes no longer fail the run. A cleared keyword, an invalid
timeRange, a wrong compare-term count, or any other input-validation error now produces a SUCCEEDED run that charges nothing and writes a clear INPUT_GUIDANCE record to the key-value store telling you exactly what to fix — instead of a FAILED run. Genuine internal errors still fail loudly; nothing is ever charged on an input-error run.
- Zero-input runs (platform automated health checks, bare API calls) now run the bitcoin demo instead of failing:
searchTerms and surfaces gained schema default values — prefill alone is form-only and is not submitted on empty input.
- Listing screenshots (input form, multi-keyword compare output).
- Second live sample dataset: 4-keyword compare (chatgpt / claude / gemini / copilot) on one shared scale.
Initial release.
- All working Google Trends surfaces in one schema-stable JSON: interest over time, multi-keyword compare (2–5 on a shared scale), related queries (top + rising), interest by region, trending now (with traffic estimates and news links).
- Reliability engineering: rotating sessions, fail-fast timeouts, bounded retries with cooldowns, proactive session rotation.
- Detects Google's valid-but-empty degraded replies and retries instead of delivering empty rows; failed fetches are reported in
ERRORS and never charged.
- Budget-aware: stops cleanly at your max cost per run and before the run timeout, always reporting exactly what was delivered and what remains.
- Related topics intentionally not offered while Google's topics feed returns empty data platform-wide.