# Amazon Keywords Discovery Tool (`w3crawler/amazon-keywords-discovery-tool`) Actor

Discover source-backed public Amazon autocomplete suggestions for seed keywords with marketplace, locale, filtering, serialized pacing, and provenance controls.

- **URL**: https://apify.com/w3crawler/amazon-keywords-discovery-tool.md
- **Developed by:** [w3crawler](https://apify.com/w3crawler) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 keyword discoveries

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Amazon Keyword Discovery Scraper

### What does Amazon Keyword Discovery Scraper do?

Amazon Keyword Discovery Scraper discovers public Amazon autocomplete phrases and enriches each keyword with data from its public Amazon search page. Each output row keeps the autocomplete provenance and can also include result-count metadata, related searches, pagination information, and a bounded list of product cards.

The structured autocomplete response is the primary source. The search-page layer is a public HTML/DOM-style fallback enrichment step based on the same keyword URL that a user would open in Amazon. It does not log in, submit orders, access private pages, or attempt to bypass CAPTCHA, paywalls, regional restrictions, or other access controls.

### Why use Amazon Keyword Discovery Scraper?

- Discover keywords from one seed or a bounded list of seeds.
- Expand seeds with A-Z and 0-9 suffix queries.
- Apply include and exclude keyword filters before records are written.
- Sort keywords by source order, alphabetically, or normalized length.
- Get a rich record for each keyword rather than only a phrase string.
- Capture public result counts, related searches, next-page URLs, and top product details.
- Choose the Amazon marketplace, product sort, price bounds, page limit, product limit, and enrichment request cap.
- Use bounded concurrency, pacing, retries, timeouts, and dataset batching.

### What data can Amazon Keyword Discovery Scraper collect?

Each record includes the autocomplete context and stable derived keyword metrics. When search enrichment is enabled and the public page is available, the same record also contains search-page and product-card fields. Optional values are omitted when Amazon does not expose them; the Actor never substitutes fabricated values.

| Field | Type | Description |
| --- | --- | --- |
| id | string | Stable identifier made from the marketplace and normalized keyword. |
| keyword | string | Suggestion text returned by Amazon autocomplete. |
| normalizedKeyword | string | Locale-normalized value used for deduplication and sorting. |
| keywordLength | integer | Unicode character count of the keyword. |
| keywordWordCount | integer | Whitespace-delimited word count. |
| position | integer | One-based position in the final sorted dataset. |
| seedKeyword | string | Seed phrase that produced the autocomplete query. |
| seedIndex | integer | One-based seed index. |
| queriedPhrase | string | Exact autocomplete phrase submitted to Amazon. |
| queryIndex | integer | One-based expansion query index for the seed. |
| queryType | enum | seed or append_character. |
| expansionCharacter | string | A-Z or 0-9 suffix used by an expansion query, when applicable. |
| sourceRank | integer | One-based rank in the autocomplete response. |
| marketplace | string | Amazon host selected for the run. |
| marketplaceId | string | Amazon public marketplace identifier. |
| locale | string | Language and normalization locale. |
| searchUrl | URL | Public Amazon search URL, including configured sort and price bounds. |
| source | string | Stable provenance value: Amazon public autocomplete. |
| searchSortBy | enum | Product ordering requested for search-page enrichment. |
| searchMinPrice | number | Optional lower product-price bound. |
| searchMaxPrice | number | Optional upper product-price bound. |
| searchEnrichmentStatus | enum | enriched, partial, not_requested, unavailable, or blocked. |
| searchPagesScraped | integer | Number of public result pages successfully parsed. |
| searchHasNextPage | boolean | Whether the last parsed page advertises another page. |
| searchPageTitle | string | HTML title from the public result page, when available. |
| searchResultCount | integer | Approximate result count displayed by Amazon. |
| searchResultCountText | string | Result-count text displayed by Amazon. |
| searchHasNoResults | boolean | Whether Amazon explicitly reports that the query matched no products. |
| searchPageStatusCode | integer | Validated HTTP status for a parsed result page. |
| searchNextPageUrl | URL | Public URL advertised by the last parsed result page. |
| relatedQueries | string array | Related-search phrases exposed on the result page. |
| topProducts | object array | Bounded product-card data from the result page. |
| searchEnrichmentScrapedAt | date-time | Time at which page enrichment completed. |
| searchEnrichmentFailureCategory | string | Safe category explaining an unavailable enrichment request. |
| scrapedAt | date-time | Time at which the autocomplete record was normalized. |

Each topProducts object can contain:

| Field | Type | Description |
| --- | --- | --- |
| position | integer | Position within the combined product list. |
| pageNumber | integer | Amazon result-page number. |
| asin | string | Product ASIN from the public result card. |
| title | string | Product title. |
| url | URL | Public Amazon product URL. |
| imageUrl | URL | Product image URL when exposed. |
| price | number | Parsed numeric price when exposed. |
| currency | string | Currency marker or code when exposed. |
| priceText | string | Displayed price text. |
| rating | number | Rating on the 0-5 scale. |
| reviewCount | integer | Parsed review count. |
| isSponsored | boolean | Whether the card is marked sponsored. |
| badge | string | Amazon badge such as Amazon's Choice or Best Seller. |
| boughtInPastMonth | string | Public bought-in-past-month text. |
| offerCountText | string | Public offer-count text. |
| availability | string | Public availability or delivery text. |

The [live sample dataset record](samples/sample-record.json) comes from a bounded local Actor run on 2026-09-26. It contains 32 populated fields, a result count, and five product cards from Amazon's public response. Chrome may show additional cards or related searches that are not present in the Actor's HTTP response; the Actor does not infer values that its response does not expose.

### How to scrape Amazon

The Actor first requests Amazon's public completion endpoint and validates status code, final origin, JSON content type, response size, challenge signals, JSON syntax, and payload shape. The `marketplace` input selects both the public marketplace ID (`mid`) and that marketplace's own completion host (`completion.amazon.com`, `completion.amazon.co.uk`, and so on); Amazon answers a foreign marketplace's `mid` on another marketplace's host with HTTP 200 and an empty `suggestions` array, so the host is part of the marketplace selection. It then optionally requests the public search page for each final keyword and validates HTTPS marketplace origin, HTML content type, response size, challenge signals, and recognizable search-result evidence (a result count, product card, or explicit no-results message) before marking the page enriched.

The search parser reads the public result-card structure observed in Amazon's search UI, including ASIN cards, h2 product links, price spans, ratings, review counts, sponsored labels, badges, offer text, delivery/availability text, related searches, and the s-pagination-next link. It stores mapped fields only; raw HTML, headers, cookies, authorization data, signed URLs, and tokens are not written to the dataset.

Autocomplete expansion is the Actor's bounded query pagination model: every seed/query is processed at most once, and maxQueriesPerSeed plus maxTotalQueries cap the plan. Search-page pagination is independently bounded by maxSearchPagesPerKeyword and maxEnrichmentRequests. maxItems is global across all unique keywords. Dataset records are pushed in batches using datasetBatchSize.

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Input

#### Minimal rich input

```json
{ "seedKeyword": "wireless earbuds" }
```

#### Multiple seeds, filters, sorting, and developer options

```json
{
  "seedKeywords": ["wireless earbuds", "bluetooth headphones"],
  "marketplace": "amazon.com",
  "locale": "en-US",
  "expansionMode": "seed",
  "suggestionLimit": 10,
  "maxQueriesPerSeed": 1,
  "maxTotalQueries": 2,
  "maxItems": 12,
  "includeKeywords": ["wireless"],
  "excludeKeywords": ["wired"],
  "sortBy": "alphabetical",
  "includeSearchMetadata": true,
  "maxProductsPerKeyword": 3,
  "maxSearchPagesPerKeyword": 1,
  "maxEnrichmentRequests": 12,
  "searchSortBy": "rating",
  "requestDelayMs": 300,
  "maxConcurrency": 2,
  "maxRequestRetries": 2,
  "requestTimeoutSecs": 12,
  "datasetBatchSize": 5,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

#### Page metadata without product arrays

```json
{
  "seedKeyword": "camera",
  "expansionMode": "seed",
  "suggestionLimit": 8,
  "maxItems": 8,
  "includeSearchMetadata": true,
  "maxProductsPerKeyword": 0,
  "maxSearchPagesPerKeyword": 2,
  "maxEnrichmentRequests": 10,
  "searchSortBy": "priceAsc",
  "searchMinPrice": 10,
  "searchMaxPrice": 200,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

#### Input fields

| Field | Type and default | Notes |
| --- | --- | --- |
| seedKeyword | string | One seed phrase. |
| seedKeywords | string array | Up to 100 seeds; takes precedence over seedKeyword. |
| marketplace | enum, amazon.com | One of the 12 supported Amazon marketplaces. Each marketplace is queried on its own completion host with its own market ID. |
| locale | enum, auto | Auto follows the selected marketplace. |
| expansionMode | enum, lettersAndNumbers | seed, letters, or lettersAndNumbers. |
| suggestionLimit | integer, 12 | 1-20 suggestions per autocomplete response. |
| maxQueriesPerSeed | integer, 37 | 1-37 expansion queries per seed. |
| maxTotalQueries | integer, 1000 | Global autocomplete-query cap, 1-5000. |
| maxItems | integer, 500 | Global unique keyword-record cap, 1-5000. |
| includeKeywords | string array | Keep a suggestion when it contains one of these substrings. |
| excludeKeywords | string array | Discard a suggestion when it contains one of these substrings. |
| sortBy | enum, sourceOrder | sourceOrder, alphabetical, lengthAsc, or lengthDesc. |
| includeSearchMetadata | boolean, true | Enable public search-page and product-card enrichment. |
| maxProductsPerKeyword | integer, 5 | 0-20 product cards per keyword. |
| maxSearchPagesPerKeyword | integer, 1 | 1-3 public search pages per keyword. |
| maxEnrichmentRequests | integer, 50 | Global page-request cap, 0-200. |
| searchSortBy | enum, featured | featured, priceAsc, priceDesc, rating, newest, or bestSellers. |
| searchMinPrice | number | Optional public search lower price bound. |
| searchMaxPrice | number | Optional public search upper price bound; cannot be below searchMinPrice. |
| requestDelayMs | integer, 300 | Delay before each request, 0-15000 ms. |
| maxConcurrency | integer, 2 | Concurrent requests, 1-8. |
| maxRequestRetries | integer, 2 | Retries, 0-5. |
| requestTimeoutSecs | integer, 12 | Per-request timeout, 5-120 seconds. |
| datasetBatchSize | integer, 50 | Records per dataset push, 1-100. |
| proxyConfiguration | object | Authorized Apify Proxy or custom HTTP(S) proxy options. |

The compatibility aliases alphabetExpansion, maxKeywords, minDelayMs, maxRetries, requestTimeoutMs, enrichSearchResults, useApifyProxy, proxyUrls, proxyGroups, and proxyCountryCode remain accepted. Prefer the modern sectioned fields; when both a modern field and its alias are supplied, the modern field wins.

The authoritative input types, defaults, enum values, and bounds are in [`.actor/input_schema.json`](.actor/input_schema.json).

### Output

The default dataset contains one rich record per unique normalized keyword. OUTPUT is a key-value summary with status, record/request/candidate/filter/duplicate counts, query-plan counts, sort settings, enrichment request counts, dataset-batch count, marketplace, connection mode, failure categories, boundary status, and completion time.

Dataset rows follow [`.actor/dataset_schema.json`](.actor/dataset_schema.json). The required and optional row fields are listed here:

<details>
<summary>Dataset fields and types</summary>

| Field | Type | Required |
| --- | --- | --- |
| `id` | string | Yes |
| `keyword` | string | Yes |
| `normalizedKeyword` | string | Yes |
| `keywordLength` | integer | Yes |
| `keywordWordCount` | integer | Yes |
| `position` | integer | Yes |
| `seedKeyword` | string | Yes |
| `seedIndex` | integer | Yes |
| `queriedPhrase` | string | Yes |
| `queryIndex` | integer | Yes |
| `queryType` | string | Yes |
| `expansionCharacter` | string | No |
| `sourceRank` | integer | Yes |
| `marketplace` | string | Yes |
| `marketplaceId` | string | Yes |
| `locale` | string | Yes |
| `searchUrl` | string | Yes |
| `suggestionType` | string | No |
| `candidateSource` | string | No |
| `source` | string | Yes |
| `searchSortBy` | string | Yes |
| `searchMinPrice` | number | No |
| `searchMaxPrice` | number | No |
| `searchEnrichmentStatus` | string | Yes |
| `searchPagesScraped` | integer | Yes |
| `searchHasNextPage` | boolean | Yes |
| `searchPageTitle` | string | No |
| `searchResultCount` | integer | No |
| `searchResultCountText` | string | No |
| `searchHasNoResults` | boolean | No |
| `searchPageStatusCode` | integer | No |
| `searchNextPageUrl` | string | No |
| `relatedQueries` | array of strings | Yes |
| `topProducts` | array of objects | Yes |
| `searchEnrichmentScrapedAt` | string | No |
| `searchEnrichmentFailureCategory` | string | No |
| `scrapedAt` | string | Yes |

</details>

Example OUTPUT summary:

```json
{
  "status": "completed",
  "records": 12,
  "requestsCompleted": 2,
  "requestsFailed": 0,
  "candidates": 20,
  "filtered": 0,
  "duplicates": 0,
  "failureCategories": [],
  "stoppedByBoundary": false,
  "marketplace": "amazon.com",
  "connectionMode": "direct",
  "sortBy": "alphabetical",
  "searchSortBy": "featured",
  "seedCount": 2,
  "queriesPlanned": 2,
  "queriesProcessed": 2,
  "maxConcurrency": 2,
  "datasetBatchesPushed": 3,
  "includeSearchMetadata": true,
  "enrichmentRequestsCompleted": 12,
  "enrichmentRequestsFailed": 0,
  "maxEnrichmentRequests": 50,
  "completedAt": "2026-09-05T12:00:02.000Z"
}
```

If any autocomplete or public search-page request fails, the Actor reports a failed run even when it has already saved valid keyword records from other requests. Such records retain their truthful searchEnrichmentStatus (partial, unavailable, or blocked) and safe failure category. A page that lacks recognizable search-result evidence is retried within the configured limit and then reported as unavailable. Explicit no-results pages are accepted and marked with searchHasNoResults. No-results autocomplete inputs complete with an empty dataset. The Actor never pushes placeholder rows.

### Tips and advanced options

- Start with seed-only expansion and a small maxItems while checking a marketplace.
- Set maxEnrichmentRequests to roughly maxItems for one page per keyword; increase it only when additional pages are needed.
- Set maxProductsPerKeyword to 0 when result counts, related searches, and pagination are enough.
- Use searchSortBy and price bounds to make the product-card slice more useful for a specific analysis.
- Keep maxConcurrency modest and requestDelayMs nonzero for responsible public-service request volume.
- Use an authorized proxy only when your Actor account and target-side terms allow it. Proxy credentials are never logged or returned.
- Amazon may show localized prices, delivery text, sponsored cards, or fewer fields depending on marketplace, locale, and session state.

### FAQ, support, and responsible use

#### Does the Actor access private Amazon data?

No. It uses public autocomplete and public search-page content only. It does not use accounts, cookies, checkout flows, private APIs, or access-control bypasses.

#### Does it handle multiple datasets and pagination?

Multiple seeds and multiple bounded autocomplete queries are combined into one default dataset with seed/query provenance. Public search-page pagination is followed only when the page advertises a next-page link, and only within maxSearchPagesPerKeyword and maxEnrichmentRequests. Each keyword record includes searchPagesScraped, searchHasNextPage, and searchNextPageUrl when available.

#### Is this an official Amazon product?

No. This is an independent Actor and is not affiliated with or endorsed by Amazon. Use it in accordance with Amazon's terms, applicable laws, and your own authorization. Do not use it to bypass restrictions or collect data you are not allowed to access.

#### Where can I get help?

For reproducible support, include the input, marketplace, OUTPUT summary, and safe failure category. Do not include credentials, cookies, authorization headers, proxy URLs containing secrets, or raw response bodies.

When a card has separate brand and product headings, extraction retains the most complete observed h2 label/full title within that product card. Explicit refusal responses stop without retry; an enrichment refusal skips later queued enrichment. A run with failed enrichment is partial. The root INPUT.json uses the bounded, paced enrichment fixture.

# Changelog

This Actor's version history is a separate document: https://apify.com/w3crawler/amazon-keywords-discovery-tool/changelog.md

# Actor input Schema

## `seedKeyword` (type: `string`):

Single phrase to enter in Amazon autocomplete. Use seedKeywords for multiple independent seeds.

## `seedKeywords` (type: `array`):

Optional list of phrases. When supplied, this list takes precedence over seedKeyword.

## `marketplace` (type: `string`):

Marketplace used for autocomplete market ID, search URLs, and public result pages.

## `locale` (type: `string`):

Accept-Language and keyword-normalization locale. Auto follows the selected marketplace.

## `expansionMode` (type: `string`):

Query the seed only, append A-Z, or append A-Z and 0-9. Expansion is bounded by per-seed and global query limits.

## `suggestionLimit` (type: `integer`):

Maximum suggestions accepted from one structured autocomplete response.

## `maxQueriesPerSeed` (type: `integer`):

Maximum autocomplete queries for each seed, including the base query.

## `maxTotalQueries` (type: `integer`):

Global safety cap across every seed and suffix expansion.

## `maxItems` (type: `integer`):

Global maximum number of unique normalized keyword records written to the dataset.

## `includeKeywords` (type: `array`):

Keep suggestions containing at least one case-insensitive substring.

## `excludeKeywords` (type: `array`):

Discard suggestions containing any case-insensitive substring.

## `sortBy` (type: `string`):

Ordering applied after cross-query deduplication.

## `includeSearchMetadata` (type: `boolean`):

Fetch each keyword's public Amazon search page and add page metadata, related queries, pagination, and top products.

## `maxProductsPerKeyword` (type: `integer`):

Maximum product cards stored inside each keyword record. Set to 0 to collect page metadata without products.

## `maxSearchPagesPerKeyword` (type: `integer`):

Maximum public Amazon result pages parsed for each keyword.

## `maxEnrichmentRequests` (type: `integer`):

Global cap on public Amazon search-page requests across all output keywords.

## `searchSortBy` (type: `string`):

Sort used on public Amazon search pages during enrichment.

## `searchMinPrice` (type: `number`):

Optional lower price bound for public Amazon search-page enrichment.

## `searchMaxPrice` (type: `number`):

Optional upper price bound for public Amazon search-page enrichment.

## `requestDelayMs` (type: `integer`):

Polite delay before each autocomplete or search-page request.

## `maxConcurrency` (type: `integer`):

Maximum number of bounded requests running in parallel.

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

Retries for temporary network, rate-limit, malformed, or server failures.

## `requestTimeoutSecs` (type: `integer`):

Maximum time allowed for one bounded request.

## `datasetBatchSize` (type: `integer`):

Number of rich records written in each Apify dataset push.

## `proxyConfiguration` (type: `object`):

Optional authorized Apify Proxy or custom HTTP(S) proxy configuration. Credentials are never logged.

## `enrichSearchResults` (type: `boolean`):

Deprecated alias for includeSearchMetadata.

## `alphabetExpansion` (type: `boolean`):

Deprecated compatibility flag. false maps to seed-only; true or omission preserves the default expansion mode.

## `maxKeywords` (type: `integer`):

Deprecated alias for maxItems.

## `minDelayMs` (type: `integer`):

Deprecated alias for requestDelayMs.

## `maxRetries` (type: `integer`):

Deprecated alias for maxRequestRetries.

## `requestTimeoutMs` (type: `integer`):

Deprecated millisecond alias for requestTimeoutSecs.

## `useApifyProxy` (type: `boolean`):

Deprecated flat alias for proxyConfiguration.useApifyProxy.

## `proxyUrls` (type: `array`):

Deprecated flat alias for proxyConfiguration.proxyUrls.

## `proxyGroups` (type: `array`):

Deprecated flat alias for proxyConfiguration.apifyProxyGroups.

## `proxyCountryCode` (type: `string`):

Deprecated flat alias for proxyConfiguration.apifyProxyCountry.

## Actor input object example

```json
{
  "seedKeyword": "wireless earbuds",
  "marketplace": "amazon.com",
  "locale": "auto",
  "expansionMode": "lettersAndNumbers",
  "suggestionLimit": 12,
  "maxQueriesPerSeed": 37,
  "maxTotalQueries": 1000,
  "maxItems": 500,
  "sortBy": "sourceOrder",
  "includeSearchMetadata": true,
  "maxProductsPerKeyword": 5,
  "maxSearchPagesPerKeyword": 1,
  "maxEnrichmentRequests": 50,
  "searchSortBy": "featured",
  "requestDelayMs": 300,
  "maxConcurrency": 2,
  "maxRequestRetries": 2,
  "requestTimeoutSecs": 12,
  "datasetBatchSize": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("w3crawler/amazon-keywords-discovery-tool").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("w3crawler/amazon-keywords-discovery-tool").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 '{}' |
apify call w3crawler/amazon-keywords-discovery-tool --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,w3crawler/amazon-keywords-discovery-tool"
        }
    }
}
```

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/0s3kLKrsqMuaXPVin/builds/2OLqzxcCH8SWletbo/openapi.json
