# Keyword Suggest API - Google, YouTube, Bing, DDG Autocomplete (`kaz_kakyo/keyword-suggest-api`) Actor

Autocomplete keyword suggestions from Google, YouTube, Bing, and DuckDuckGo in one call. A-Z/0-9 and recursive expansion, locale targeting, parent-child keyword tree. No API key, no browser.

- **URL**: https://apify.com/kaz\_kakyo/keyword-suggest-api.md
- **Developed by:** [Heim AI](https://apify.com/kaz_kakyo) (community)
- **Categories:** SEO tools, Developer tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 keyword expansions

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Keyword Suggest API — Google, YouTube, Bing, DuckDuckGo Autocomplete

**Seed keywords in → autocomplete suggestions out.** Expand one or more keywords into normalized suggestion lists from **Google, YouTube, Bing, and DuckDuckGo** autocomplete APIs in a single run. Optional a–z / 0–9 suffix expansion and recursive depth-limited re-expansion with parent-child lineage. No API key, no browser.

| | |
|---|---|
| **Actor id** | `kaz_kakyo/keyword-suggest-api` |
| **Minimal input** | `{ "keywords": ["best crm"] }` |
| **Cost** | **$0.005** per run start + **$0.001** per keyword×source expansion that returns suggestions |
| **Output** | Dataset rows with `type: "expansion"` (plus free `error` / `notice` / `source_degraded` rows) |

### What it does

This actor is a **keyword suggestions / autocomplete API** wrapper: it calls the public suggest endpoints for Google, YouTube, Bing, and DuckDuckGo, normalizes the results, and writes one dataset row per (query × source) expansion. Use it for SEO keyword research, content ideation, PPC expansion, and agent-driven keyword discovery pipelines.

### Output

| `type` | Charged? | Meaning |
|---|---|---|
| `expansion` | Yes, if `suggestionCount > 0` | Successful autocomplete fetch |
| `error` | No | Bad input, fetch failure, or unknown source |
| `notice` | No | Cap or billing stop (`max_expansions_reached`, `keywords_capped`, `charge_limit_reached`, `billing_state_unknown`, `queue_limit_reached`, `run_interrupted`) |
| `source_degraded` | No | Source stopped after 5 consecutive hard failures |

Success shape:

```json
{
  "type": "expansion",
  "query": "best crm a",
  "seedKeyword": "best crm",
  "parentKeyword": "best crm",
  "variant": "a",
  "depth": 1,
  "source": "google",
  "language": "en",
  "country": "us",
  "suggestions": ["best crm apps", "best crm software"],
  "suggestionCount": 2,
  "fetchedAt": "2026-08-01T00:00:00.000Z"
}
```

Empty-result expansions (`suggestionCount: 0`), errors, notices, and degraded-source rows are **never billed**.

### Input

| Field | Default | Description |
|---|---|---|
| `keywords` | (required) | Seed keywords (`stringList`) |
| `sources` | all four | `google`, `youtube`, `bing`, `duckduckgo` |
| `language` | `en` | ISO 639-1 (2 letters) |
| `country` | `us` | ISO 3166-1 alpha-2 (2 letters) |
| `expandAlphabet` | `false` | Also fetch `{seed} a` … `{seed} z` |
| `expandNumbers` | `false` | Also fetch `{seed} 0` … `{seed} 9` |
| `maxDepth` | `1` | Recurse into suggestions on the same source (max 3) |
| `maxExpansions` | `200` | Global fetch cap (max 5000) |

**Two validation layers.** The input schema rejects malformed input **before a run starts** — HTTP 400 from the API, Console, a task or MCP, with no run created and nothing charged. That covers non-string `keywords` items, `sources` values outside the four names, and `language`/`country` values that are not exactly 2 letters; on the platform these never reach the actor, so they never appear as dataset rows. Input that passes the schema but is still unusable (empty `keywords`, keywords over 200 characters, more than 100 seeds) becomes uncharged `type: "error"` or `type: "notice"` rows and the run still **SUCCEEDS**. The runtime keeps its own copy of the schema checks purely as a defensive fallback for unvalidated local invocation (`node src/main.js`), where the same problems produce those uncharged rows instead of a 400.

### Pricing

| Event | Price |
|---|---|
| Run start (`apify-actor-start`) | **$0.005** |
| Expansion with ≥1 suggestion (`expansion`) | **$0.001** per keyword×source expansion that returns suggestions |

Worked examples (totals assume nonempty results):

- 1 seed × 4 sources → 4 expansions ≈ **$0.009** ($0.005 + 4×$0.001)
- 1 seed × Google only, a–z on → 27 expansions ≈ **$0.032** ($0.005 + 27×$0.001)
- Empty results, errors, notices, and degraded rows are **free**

Cap spend with `maxTotalChargeUsd` on the run. When the charge budget is exhausted (including a budget too small for the run-start fee), remaining work stops and a `charge_limit_reached` notice is written. If the actor cannot read its own billing state at run time, it stops instead of delivering unbilled data and writes a `billing_state_unknown` notice (fail-closed).

### Quick start (Console)

1. Open the actor in [Apify Console](https://console.apify.com).
2. Leave the prefill `keywords: ["best crm"]` (or add your seeds).
3. Click **Start**. Expect four `expansion` rows (one per source) with `suggestionCount > 0`.

### API

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/kaz_kakyo~keyword-suggest-api/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords":["best crm"],"sources":["google","bing"],"language":"en","country":"us"}'
```

Or with `apify-client`:

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('kaz_kakyo/keyword-suggest-api').call(
  { keywords: ['best crm'], maxDepth: 1 },
  { maxTotalChargeUsd: 1.0 },
);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const expansions = items.filter((i) => i.type === 'expansion');
```

### MCP / agents

Callable via the **Apify MCP server**. Pass `keywords` (and optional `sources`, locale, expansion flags). Filter dataset items on `type === "expansion"`. Input that violates the schema (unknown source, non-string keyword items, locale not exactly 2 letters) is rejected with HTTP 400 before a run is created — no dataset, no charge. Input that passes the schema but is unusable (empty keywords, oversize keywords) produces uncharged error rows without failing the run.

### Scheduling

Use **Apify Schedules** (or a saved Task + schedule) for recurring keyword monitoring — e.g. daily expansion of a seed list to detect new autocomplete phrases. Attach a webhook on `SUCCEEDED` and process only `expansion` rows.

### Locales

`language` and `country` are validated for **format only** (exactly 2 letters). Unassigned codes (e.g. `zz`) are passed through; endpoints fall back server-side (best-effort). Values are forwarded per source (`hl`/`gl` for Google/YouTube, `market` for Bing, `kl` for DuckDuckGo). DuckDuckGo region mapping: `kl` is `{country}-{language}` with `gb` remapped to `uk`.

### Limits (honest)

- Endpoints are **unofficial public autocomplete APIs** — they may change or rate-limit without notice.
- This actor does **not** return search-volume, CPC, or competition data — suggestions only.
- Suggestion lists **vary by locale and time**.
- Recursion re-expands on the **same source only** (a Google suggestion is not re-queried on Bing).
- Suffix expansion is **Latin a–z and digits 0–9** only.
- Typical response size is about **8–14 suggestions** per call.
- Queue is hard-bounded at **20,000 jobs**; seeds are capped at **100** per run (excess → `keywords_capped` notice).
- Default run timeout is **3600s**. `maxExpansions: 5000` on a single source can take ~35–40 minutes (per-source throttling ~150–350ms + network).
- The actor collects no personal data of its own: rows contain only your input keywords, query variants derived from them, and the public autocomplete strings the engines return. Output **echoes whatever you supply** as `keywords` (in `query`, `seedKeyword`, `parentKeyword`) — do not submit personal data (names, emails, phone numbers) as seed keywords if your dataset must stay PII-free. Your keywords are sent to the public suggest endpoints (Google, YouTube, Bing, DuckDuckGo) as queries.

# Actor input Schema

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

Required. Seed keywords to expand into autocomplete suggestions. Trimmed, empty entries dropped, case-insensitive deduped; max 100 seeds per run (excess recorded as a notice). Keywords longer than 200 characters become error rows and are skipped.

## `sources` (type: `array`):

Which autocomplete endpoints to query. Default: all four. Values outside the list are rejected by platform validation before the run starts (HTTP 400 via API/Console/task). On direct SDK/local invocation that bypasses schema validation, unknown values become uncharged error rows and known sources still run. Each (keyword × source) expansion is one billed event when suggestions are returned.

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

ISO 639-1 two-letter language code (e.g. en, de, fr). Format validated only (exactly 2 letters); unassigned codes (e.g. zz) are passed through and endpoints fall back server-side (best-effort). Values that are not exactly 2 letters are rejected by platform validation before the run starts (HTTP 400); on direct SDK/local invocation the same check produces one uncharged error row and the run still succeeds.

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

ISO 3166-1 alpha-2 country code (e.g. us, gb, de). Format validated only (exactly 2 letters); unassigned codes (e.g. zz) are passed through and endpoints fall back server-side (best-effort). Passed as gl/market region; for DuckDuckGo, gb is mapped to uk in the kl parameter. Values that are not exactly 2 letters are rejected by platform validation before the run starts (HTTP 400); on direct SDK/local invocation the same check produces one uncharged error row and the run still succeeds.

## `expandAlphabet` (type: `boolean`):

When true, for each seed and source also fetch "{seed} a" … "{seed} z" (26 extra queries per seed×source). Useful for discovering long-tail keyword variants. Counts toward maxExpansions.

## `expandNumbers` (type: `boolean`):

When true, for each seed and source also fetch "{seed} 0" … "{seed} 9" (10 extra queries per seed×source). Counts toward maxExpansions.

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

How deep to re-expand discovered suggestions on the same source. 1 = seeds (and optional suffixes) only. 2–3 = each suggestion becomes a new query on the source it came from. Parent-child lineage is recorded in parentKeyword.

## `maxExpansions` (type: `integer`):

Global cap on attempted endpoint fetches across all sources (billing safety). When hit, remaining jobs are skipped and one notice row (max\_expansions\_reached) is written. Default 200; max 5000.

## Actor input object example

```json
{
  "keywords": [
    "best crm"
  ],
  "sources": [
    "google",
    "youtube",
    "bing",
    "duckduckgo"
  ],
  "language": "en",
  "country": "us",
  "expandAlphabet": false,
  "expandNumbers": false,
  "maxDepth": 1,
  "maxExpansions": 200
}
```

# Actor output Schema

## `suggestions_flat` (type: `string`):

One row per keyword suggestion, with the query and source engine that produced it — the flat shape to feed straight into a sheet, a database or an agent.

## `overview` (type: `string`):

One row per expansion: the seed query, the engine, the depth reached and every suggestion it returned, grouped together.

# 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": [
        "best crm"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kaz_kakyo/keyword-suggest-api").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": ["best crm"] }

# Run the Actor and wait for it to finish
run = client.actor("kaz_kakyo/keyword-suggest-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "best crm"
  ]
}' |
apify call kaz_kakyo/keyword-suggest-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=kaz_kakyo/keyword-suggest-api",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HQzEObe5hUHiHfPDo/builds/4eQhDiMJydM6Nwg1t/openapi.json
