Discover related keywords for any seed keyword with Google Ads search volumes, CPC, competition, and 12-month monthly trends. 217 countries × 46 languages.
The run can no longer be killed by the key-value store. Under
LIMITED_PERMISSIONS — how Apify's automated QA and every API-triggered run
starts an Actor — opening the store is refused with HTTP 403
(KeyValueStoreCollectionClient.getOrCreate, path /v2/key-value-stores).
That call sat in a || fallback chain and was never inside a try/catch of
ours, so the throw ended the run with exit code 91 and a reported FAILED run
with zero items. Every store open now goes through a wrapper that returns a
no-op store instead of throwing, so the free-run counter and the run SUMMARY
degrade and the actual work proceeds.
The gate store's name-to-id lookup no longer depends on the store still being
on the first page. There is no GET-by-name endpoint, so the lookup pages
through /v2/key-value-stores; it used a fixed limit=50, which silently
stopped containing gate stores once the account passed 50 of them — and the
account creates a new default store on every run, so that list grows on its
own. The lookup now pages (100 per page, up to 20 pages).
[1.4] - 2026-10-08
Fixed
KV writes can no longer hang the run. Actor.setValue does not just fail
under LIMITED_PERMISSIONS — it can simply never resolve. Measured on a live
run of a sibling Actor: results were fetched successfully, then the following
setValue never returned and the run sat for 49 minutes before being aborted
with an empty dataset and a $0.08 bill, and not one error in the log.
try/catch cannot help with that — it catches a rejection, not a promise that
never settles, so the previous try { await Actor.setValue(...) } catch {...}
guard was not sufficient. SUMMARY now races a 15s timeout and reports the
failure, so a stuck store costs one summary field instead of the whole run.
makeLogger gained the missing warning level. @apify/log exposes
warning and leaves warn undefined, so every logger.warning(...) call
threw a TypeError — including inside the free-tier gate's own "I am degrading"
branch, which meant the run died while reporting that it was degraded.
validateInput is now exported, so test/expand-tasks.js can assert on it.
SUMMARY now carries free_tier_cap with enforced / degraded /
degraded_reason, so a cap that stopped being enforced is visible outside
the log.
[1.3.0] - 2026-07-18
Changed
Limited each run to exactly one seed keyword to control request costs.
Changed the keyword input from a multi-line textarea to a single text field.
Rejects multiple keywords before any paid request is sent.
[1.2.0] - 2026-07-18
Added
Added Date From and Date To input fields for monthly search-history selection.
Added defaults for every input field, including a rolling 12-month date window.
Added date-format and chronological-order validation.
[1.1.0] - 2026-07-18
Changed
Increased the free-user allowance to 5 runs per day.
Replaced free-text locations with a multi-select dropdown covering 39 major countries.
Replaced free-text language input with a Target Language dropdown covering 20 major languages.
Removed advanced and unnecessary settings from the public input form.
Removed internal codes, provider flags, and system metadata from Dataset rows.
Preserved safe defaults for empty Apify automated-test inputs.
Verified
All seven local test suites pass.
Free users can run five times; the sixth daily run is blocked.
Country and language selections propagate correctly to every exported result.
Structured monthly_searches and concepts arrays remain queryable.
[1.0.0] - 2026-07-18
Added
Initial keyword suggestion workflow with search volume, CPC, competition, bid estimates, monthly trends, and concepts.