# Google Autocomplete Scraper | Keyword Trees & Evidence (`peerless_columbine/google-autocomplete-keyword-discovery`) Actor

Expand seed keywords into Google search suggestions with language, country, recursive queries, alphabet and question patterns. Export query provenance with explicit request limits.

- **URL**: https://apify.com/peerless_columbine/google-autocomplete-keyword-discovery.md
- **Developed by:** [tingyou333 zhuang](https://apify.com/peerless_columbine) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 successful queries

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Autocomplete — keyword trees with query evidence

Independently authored Python Actor for collecting Google's public autocomplete suggestions. Supply one or more seed phrases, choose a language and country parameter, and optionally expand through three levels, alphabet suffixes, question prefixes and numeric prefixes. Each dataset row retains its original seed, exact query, source position and response hash.

Use the query evidence to audit keyword research, compare locale responses and build SEO content plans. Suggestions come from the live public Google endpoint; their number and wording can change between runs.

### Input

```json
{
  "keywords": ["coffee grinder"],
  "language": "en",
  "country": "us",
  "maxDepth": 1,
  "maxSuggestionsPerKeyword": 10,
  "appendAlphabet": false,
  "expansionPatterns": [],
  "maxRequestRetries": 3
}
```

| Input | Default | Behavior |
| --- | --- | --- |
| `keywords` | Required | Nonempty array of nonblank strings. Whitespace is trimmed; repeated seeds are processed once. |
| `language` | `en` | Google `hl` parameter; accepts a two/three-letter code and optional language subtag. |
| `country` | `us` | Google `gl` parameter; two letters, normalized to lowercase. |
| `maxDepth` | `1` | 1–3 collection levels: output depth is respectively 0, 0–1 or 0–2. |
| `maxSuggestionsPerKeyword` | `10` | 1–10 unique suggestions retained per query, in original response order. |
| `appendAlphabet` | `false` | Add `seed a` through `seed z` for each original seed. |
| `expansionPatterns` | `[]` | `questionPrefixes` and/or `numbers`; unknown patterns fail validation. |
| `maxRequestRetries` | `3` | Retries after the initial attempt; maximum four attempts with the default. |
| `maxRequests` | `0` | Optional global HTTP-attempt cap, including failed attempts and retries. Zero means no explicit cap. |
| `maxResults` | `0` | Optional global dataset-row cap. Zero means no explicit cap. |
| `requestDelayMillis` | `200` | Delay between source attempts; nonnegative integer. |

The final three fields are additional controls. Defaults impose no hidden request, result or elapsed-time cutoff. Actor platform timeouts and spending limits still apply. Invalid types, unknown inputs and out-of-range numbers fail before source requests or custom query charges. The native input schema provides the UI; the engine also validates values, including the expansion-pattern enum that the installed native schema validator does not accept under `stringList.items`.

### Expansion and provenance

Every seed first produces its direct query. Alphabet expansion adds 26 suffix queries. Question expansion adds ten prefixes in this order: `who`, `what`, `when`, `where`, `why`, `how`, `can`, `is`, `are`, `should`. Numbers add ten **prefix** queries, `0 seed` through `9 seed`. Enabling all modes therefore schedules 47 root queries per seed.

Patterns apply only to original seeds. Recursive suggestions become plain queries; alphabet/question/number expansion is not reapplied. A breadth-first queue visits each `(original seed, exact query)` once to avoid cycles. Separate seeds retain separate attribution even when they discover the same query. Within each response, suggestions are deduplicated while preserving their first original zero-based position. Exact matches to the query remain valid rows. A configured per-query selection cap also bounds which suggestions recurse.

`keyword` always identifies the original seed. `query` is the actual Google query. `depth` is 0, 1 or 2. `parentKeyword` is null at depth 0 and equals that row's actual recursive query at greater depths, following the documented output convention. It does not identify the previous queue node. `scrapedAt` is a UTC ISO 8601 timestamp. `sourceUrl` and `sourceSha256` are additional evidence fields.

Country and language are request parameters, not measurements of a network exit. Suggestions reflect Google's endpoint behavior and can change with time or location. There is no country-pinned proxy, search-volume estimate, CPC, relevance score or verified ranking.

### Persistence, errors and billing

Rows are pushed individually to the default dataset as they are produced. `SOURCE_DIAGNOSTICS` records every attempted query, status, response hash, byte count, retries and successful-query persistence/billing state. `OUTPUT` records counts, pending work, errors and coverage. Both records are checkpointed at the start of output for each successfully validated query (before emitting or charging), and at query end after output and charging. Source failures and terminal request/result/billing limits have explicit critical-state checkpoints. Dataset rows remain individually durable; there are no per-row KV snapshots or duplicate run-final snapshots. Intermediate snapshots use `status: running`; final status is `succeeded`, `succeeded_empty`, `partial` or `failed`.

HTTP 200 is accepted only with valid JSON, the exact query echo and an array of nonblank strings. Invalid JSON, shape mismatches, transient HTTP errors including 429/5xx, and transport failures use the retry allowance. Permanent 400/401/403/404/410 responses stop that query immediately. The production adapter uses `AsyncClient.stream` with raw chunk iteration, retains at most 1 MiB of body data, and closes immediately on the first chunk crossing that limit without consuming subsequent chunks. An oversized declared Content-Length is rejected before body consumption; the streamed byte count also enforces the cap when the header is absent or false. `SOURCE_TOO_LARGE` is terminal for that query and is not retried or charged. TLS verification is explicit and redirects are disabled per request. Requests specify identity encoding; an unexpected compressed response is rejected before reading/decompressing it. The crossing transport chunk and the bounded final bytes copy are transient allocations; this is a body-retention limit, not a whole-process memory guarantee. Source retries use exponential backoff: 200ms, 400ms, 800ms, 1.6s, 3.2s, 6.4s, 12.8s, 25.6s, then at most 30s of backoff per retry. The actual wait is the greater of this backoff and `requestDelayMillis`; a configured ordinary delay above 30s is preserved. `requestDelayMillis: 0` disables ordinary cross-query delay, not retry backoff. The retry index resets for each query. Request caps are checked before waiting or attempting another source request. The bounded exponent calculation cannot overflow for large retry counts. Exhausted source failures remain explicit errors; they are never converted to successful empty results. A valid empty array is a successful empty query. Redirects are not followed.

Partial source failure preserves successful query rows and permits other queries to continue. Global caps and spending limits stop further queries. Reaching a cap exactly as all requested work finishes reports `EXPANSION_COMPLETE`, with `hasMore: false`. A deliberate per-query selection limit sets `suggestionsTruncated: true` without falsely asserting that requested work remains. `hasMore` describes incomplete/error coverage, not a Google pagination cursor.

Storage or billing callback failures terminate collection; already stored rows remain. The Actor raises for terminal storage/billing failure and all-source failure. A key-value storage outage can also prevent saving the latest summary; the last successful checkpoint and dataset remain the available evidence.

The custom charge event is **`keyword-expanded`**. Individual suggestions have no additional row fee: the synthetic **`apify-default-dataset-item`** event may be omitted in cloud SDK mode, or explicitly configured at zero. Local PPE mode requires an explicit zero-price synthetic event. The adapter requires a finite positive query price and rejects unknown pricing models/events, invalid prices and nonzero per-row pricing. It checks affordability before starting each query, persists the initial validated query receipt and selected query rows, and then requests exactly one custom event for that successfully parsed query. A valid empty response also incurs one event after its empty-query receipt is saved. Failed source requests/retries incur no custom query events. A successful query cut short by the global result cap still incurs one query event for the observed and persisted query output. Storage failure before completing that output incurs no custom query event.

The last affordable event is accepted when `charged_count == 1`, even if `event_charge_limit_reached` is true afterward. The next query is blocked. A refused or uncertain write or charge is terminal. The input, Dataset, diagnostic storage and charging paths share one SDK client with zero automatic HTTP retries and use only the existing run-default stores. Each logical SDK HTTP operation has one native transport attempt; this does not prove platform exactly-once delivery. Google source requests retain their independent `maxRequestRetries` setting. Local FREE runs and cloud runs with verified unpriced SDK state skip custom charging; platform compute and storage usage can still cost money.

The current configured pricing is **$0.001 per successful query**, plus the platform's automatic **`apify-actor-start`** event at **$0.001 per GB, minimum one event**. The supported 128–512 MiB memory range therefore incurs one $0.001 startup event. A query can deliver up to ten unique suggestions at that same query price. For example, one successful query costs $0.002 including startup; 47 successful root-pattern queries cost $0.048 including startup. A valid empty response still counts as one successful query. Failed source attempts and retries do not incur query events; the startup fee still applies. There is no separate per-suggestion fee. The owned private Actor has this effective two-event configuration. An authenticated Console observation on 2026-10-09 displays “User pays platform usage costs: No”; the API omits that flag, so this UI observation is separate configuration evidence. Post-run storage interactions are not an unlimited free-storage/export promise. Owned private PPE checks confirmed startup/query counts and no synthetic row event; these are not paid-customer revenue. The [PPE documentation](https://docs.apify.com/actors/publishing/monetize/pay-per-event) explains platform events and spending limits.

Dataset writes, query-event charges and diagnostic writes are separate operations. A process kill between them can leave persisted rows with pending/uncertain billing. This candidate does not automatically replay or resume such queries; reconciliation is required before rerunning. Dataset progress remains durable row by row. Diagnostic/OUTPUT progress is best-effort per query and can lag the Dataset during a query. If the final KV checkpoint fails after durable rows and billing, the query may already have been charged; the exception propagates rather than reporting success. Exactly-once or atomic abort/restart recovery is not claimed.

### Larger jobs and memory

All output rows, diagnostics, queued queries and deduplication sets remain in memory during a run. The growing diagnostics record is rewritten at query boundaries. The 1 MiB response-body limit does not bound the entire process or the accumulated output. Three levels combined with multiple seeds or all root patterns can produce substantially more work than a single query.

Use `maxRequests`, `maxResults` and the platform's spending/time limits to bound a job. Inspect `OUTPUT` for incomplete work before treating a capped run as an exhaustive result. No maximum-scale throughput or whole-process memory guarantee is claimed.

### Results and workflow

`ROW_SCHEMA.json` validates data rows. `.actor/output_schema.json` links the default dataset and summary. Use Apify's dataset export for JSON/CSV/Excel, or retrieve the default dataset through its API. Scheduling, webhooks and downstream Sheets/Make/Zapier connections use platform integrations; no external destinations are contacted by this implementation.

`examples/observed-*-rows.json` contains actual local-source output, alongside the exact input and summary from the same acceptance run. Default: 10 rows/1 request; depth 3 with two suggestions per query: 6 rows/3 requests; all root patterns: 94 rows/47 requests; Spanish/Mexico: 10 rows/1 request; verified empty query: 0 rows/1 successful request. Counts are dated observations, not promised future results. No example row is synthesized. Earlier `evidence/basic.*`, `tree.*`, `alphabet.*`, `spanish.*` and `live-validation.json` predate the fixes and are superseded by `evidence/acceptance/`.

### Development and verification

The Python runtime and dependency artifacts are hash-locked in `requirements.lock`; the Docker base is pinned by manifest digest. Native input/output/dataset schemas and boundary tests are included in the project. Runtime verification covers malformed responses, access errors, retries, empty results, deduplication, caps, streaming limits and storage/billing interruptions.

The initial owned Apify cloud sample returned ten real suggestions from one query in 3.19 seconds, with 51.2 MB peak process memory. This bounded source test used FREE pricing; it is not a paid-customer or large-workload benchmark. Dated samples describe observed output, not guaranteed future suggestions or response time.

Run `python -m pytest tests -q` and `apify validate-schema` from the project environment. The optional live-source validation script issues real Google requests; offline replay does not. Public competitor documentation informs the feature contract; the implementation and vector icon are independently authored. Country-pinned proxies, search-volume metrics and secondary competitors' metadata/ranking features are outside this Actor's claims.

### Runtime revision

Source revision 0.1.3 adds the shared single-attempt SDK adapter and strict query billing validation. The input, Google source retry policy, recursive expansion, query-local deduplication, attribution and row fields are unchanged. Earlier cloud examples bind earlier builds. The previous complete39 package was built successfully as dfUHIoTNA7ur9pFvO / 0.1.4 and accepted on real source and selected PPE cases; those receipts bind that previous package.

Source revision 0.1.4 fixes initialization for owned cloud runs whose effective pricing is absent: SDK 3.4.1 represents that state as `None`, with no event prices or event charges. Unsupported pricing models and failed pricing lookups still stop the run. The failed 0.1.3 cloud run stopped before Google collection and remains historical. Repaired 0.1.4 build dfUHIoTNA7ur9pFvO succeeded; run 1CBdbd3UbZWH8kQF8 returned ten real rows from one query with required cached source evidence complete. Its optional RUN-REPORT read was unknown and its readback hold remains retained. The 175 passing offline tests include the actual pinned SDK lifecycle with simulated HTTP/event transport and do not establish cloud or PPE acceptance.

### Dated owned-cloud verification, 2026-10-09

The current 0.1.4 runtime produced 389 real rows from all 47 root queries using Spanish/Mexico parameters (R20FnqWVv5NHcX9FH), six rows spanning depths 0–2 with per-query selection two (4UcG5d3E3zhXisd83), and two rows from one query with an explicit REQUEST_LIMIT partial result (WAehkPkzp2lfDm4Jh). These are observed counts, not promised future source results.

Three private PPE checks on that build were accepted: r3HmgXN1zPsHYJQ5U delivered ten rows and one query event plus one startup, then stopped with BILLING_LIMIT and one pending query; Xw70NdkzqP2boX2la returned a valid empty response with one query event plus startup; 5DXMxgPPZV7b1wN8V failed with INVALID_INPUT, zero source requests/rows/query events and one startup. The last is a successful negative billing test, not a successful collection. Dataset synthetic charges were absent. No source result or billing event was fabricated.

The exponential-backoff revision repairs a documented primary behavior missing from the earlier 0.1.4 engine. It preserves every input/default, retry count, queue/cap check, source validation, output and billing boundary. Targeted author verification passed 47 offline tests, including the 12 original engine tests unchanged, and replayed five saved real-source cases (53 responses/120 rows). At preparation of this revision, independent delta approval, its final exact source build/default paid smoke and publication gates remain pending. The dated 0.1.4 cloud/PPE receipts above remain historical and do not claim to be runs of the changed engine.

# Actor input Schema

## `keywords` (type: `array`):

One or more nonblank seed phrases.

## `language` (type: `string`):

Google hl parameter; does not control proxy exit.

## `country` (type: `string`):

Google gl parameter; does not verify physical location.

## `maxDepth` (type: `integer`):

1 collects direct suggestions; 2 or 3 adds recursive levels.

## `maxSuggestionsPerKeyword` (type: `integer`):

Keep at most this many unique suggestions per source query.

## `appendAlphabet` (type: `boolean`):

Root seeds only: query seed a through seed z; recurse returned suggestions without adding patterns again.

## `expansionPatterns` (type: `array`):

Root seeds only: ten question prefixes and/or 0–9 numeric prefixes before each seed.

## `maxRequests` (type: `integer`):

Includes failed attempts; limits expansion and retries.

## `maxResults` (type: `integer`):

0 disables the result cap; request cap still applies.

## `maxRequestRetries` (type: `integer`):

Retries after the first failed request, including transient HTTP errors and invalid payloads. Permanent 400/401/403/404/410 stop that query.

## `requestDelayMillis` (type: `integer`):

Minimum delay between attempted requests.

## Actor input object example

```json
{
  "keywords": [
    "coffee grinder"
  ],
  "language": "en",
  "country": "us",
  "maxDepth": 1,
  "maxSuggestionsPerKeyword": 10,
  "appendAlphabet": false,
  "expansionPatterns": [],
  "maxRequests": 0,
  "maxResults": 0,
  "maxRequestRetries": 3,
  "requestDelayMillis": 200
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "coffee grinder"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("peerless_columbine/google-autocomplete-keyword-discovery").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "keywords": ["coffee grinder"] }

# Run the Actor and wait for it to finish
run = client.actor("peerless_columbine/google-autocomplete-keyword-discovery").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "coffee grinder"
  ]
}' |
apify call peerless_columbine/google-autocomplete-keyword-discovery --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,peerless_columbine/google-autocomplete-keyword-discovery"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hsBvIyH7T038ImzxX/builds/pMs2Kh534Is9R4DbQ/openapi.json
