# Amazon KDP Niche Analyzer (`steadyscrape/kdp-niche-analyzer`) Actor

Amazon KDP niche finder and research tool: the top books for each keyword with real Best Sellers Rank (BSR), reviews, price, publisher, indie or not, plus estimated monthly sales and an opportunity score (formulas stated). Paperback and Kindle. Export to CSV, JSON or API. No login.

- **URL**: https://apify.com/steadyscrape/kdp-niche-analyzer.md
- **Developed by:** [Steady Scrape](https://apify.com/steadyscrape) (community)
- **Categories:** E-commerce, For creators, SEO tools
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 book with details

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

## Amazon KDP Niche Analyzer — Best Sellers Rank, sales estimates and competition for book niches

Type the niches you are thinking of publishing in — `gratitude journal`, `coloring book for adults`, `password log book` —
and get, for each one, **the top books Amazon.com shows a buyer**, each with its **real Best Sellers Rank**, price, review
count, rating, publisher, whether it is **independently published (KDP)**, page count and publication date, plus a
**niche summary**: how many results the search has, median price and reviews, how many top books have under 50 reviews,
the median rank, an **estimated monthly sales** figure, the share of independent publishers, Amazon's own **search-box
suggestions**, and an **opportunity score** with the reasons behind it.

Works for print (Amazon's Books department: paperbacks, hardcovers, spiral-bound and low-content books) and for the
**Kindle Store** (with the share of Kindle Unlimited titles). No login, no Amazon account, no API key.

### Who it is for

- **KDP self-publishers** shortlisting niches before writing, designing or formatting anything.
- **Low-content publishers** (journals, planners, log books, coloring and activity books) checking which keywords still
  leave room for a newcomer.
- **Market researchers** benchmarking prices, page counts and review counts in a category.
- **Anyone scheduling a re-check** of a niche: run it weekly and compare the summaries.

### What you get

One dataset with two kinds of rows (the field `type` says which):

**A `book` row** for each top organic result: `position`, `page`, `asin`, `url`, `title`, `authors`, `format`, `price`,
`listPrice`, `rating`, `reviewCount`, `series`, `kindleUnlimited`, `soldBy` (Kindle), `sponsored`, `publicationDate`; and
with `includeDetails` (on by default) from the book's own page: `bestSellersRank` (in Books or in Kindle Store),
`categoryRanks`, **`estimatedMonthlySales`**, `publisher`, **`independentlyPublished`**, `pageCount`, `language`,
`dimensions`, `isbn13`.

**A `niche` row** per keyword and department: `totalResults` (as Amazon words it, e.g. "over 60,000"), `booksAnalyzed`,
`sponsoredSkipped`, `medianPrice`, `averagePrice`, `medianRating`, `medianReviews`, `averageReviews`,
`shareUnder50Reviews`, `shareKindleUnlimited`, `medianBestSellersRank`, `bestBestSellersRank`,
`estimatedMonthlySalesMedian`, `estimatedMonthlySalesTotal`, `shareIndependentlyPublished`, `medianPageCount`,
`medianAgeDays`, `newestPublicationDate`, **`opportunityScoreEstimate`** (0–100), **`verdictEstimate`** (promising /
mixed / crowded), `scoreReasons` and `suggestions`.

Example niche row (from a real run, 24 top results for "password log book", 2026-10-14):

```json
{
  "type": "niche", "keyword": "password log book", "store": "books", "status": "ok",
  "totalResults": 50000, "totalResultsText": "over 50,000", "booksAnalyzed": 24,
  "medianPrice": 7.41, "medianReviews": 184, "shareUnder50Reviews": 0.292,
  "medianBestSellersRank": 135765.5, "estimatedMonthlySalesMedian": 22.5, "shareIndependentlyPublished": 0.765,
  "opportunityScoreEstimate": 46, "verdictEstimate": "mixed",
  "scoreReasons": [
    "demand 0.55: the median book sells an estimated 23 copies a month",
    "competition 0.24: the median book has 184 reviews",
    "independents 0.76: 76 % of the books with a known publisher are independently published"
  ],
  "suggestions": ["password log book with lock"]
}
```

### The two estimates, and their formulas

Nothing Amazon publishes says how many copies a book sells or how hard a niche is. These two fields are **estimates**,
named so, and computed in the open so you can recompute or reweigh them:

- **`estimatedMonthlySales` = round(30 × min(5000, 100000 ÷ bestSellersRank))**. It fits the public BSR-to-sales tables for
  Amazon.com books (#10,000 ≈ 10 copies a day, #100,000 ≈ 1 a day) and caps the very top at 5,000 a day. Only the overall
  rank (in Books or in Kindle Store) is used; a rank in Office Products or a category is not comparable and gives `null`.
  A rank is a snapshot that moves every hour.
- **`opportunityScoreEstimate` = round(100 × (0.45 × demand + 0.40 × competition + 0.15 × shareIndependentlyPublished))**,
  where demand = min(1, log10(1 + median estimated monthly sales) ÷ log10(301)) — 300 copies a month or more counts as full
  demand — and competition = 1 − min(1, log10(1 + median review count) ÷ 3) — 1,000 reviews or more counts as fully
  crowded. Promising from 65, mixed from 40, crowded below. It needs at least 5 ranked books; otherwise it is `null` and
  `scoreReasons` says why.

`independentlyPublished` is true when a print book's publisher reads "Independently published", or when a Kindle book lists
no publisher (how Kindle books published through KDP read); false when a publisher is named.

### Input

```json
{
  "keywords": ["gratitude journal", "coloring book for adults"],
  "stores": ["books", "kindle"],
  "booksPerNiche": 16,
  "includeDetails": true,
  "includeSuggestions": true,
  "analyzeSuggestions": false
}
```

- `booksPerNiche` (1–100): top organic results analyzed per keyword and department (16 per results page).
- `analyzeSuggestions`: Amazon's suggestions for your keywords become niches of their own, up to `maxNiches`.
- `includeSponsored`: off by default, so niches are measured on organic results; sponsored ones are counted in
  `sponsoredSkipped`.

### Pricing

Pay per result, no start fee:

| event | price | when |
|---|---|---|
| `niche` | US$0.005 | a niche analyzed (status `ok`) |
| `book-with-details` | US$0.002 | a book read with its own page (rank, publisher…) |
| `book` | US$0.001 | a book with what the search shows (details off, or its page refused) |

A niche of 16 books with details costs US$0.037. Rows with status `invalid`, `no_results` or `blocked` are free. Your
spending limit is checked **before** each niche: the Actor never sends requests for books it could not charge, and stops
with a clear message when the limit is reached.

### Limits — read these

- **Amazon.com only.** Amazon.ca answers too, but many of its book pages show category ranks only, and the sales formula is
  calibrated on the US store.
- **Amazon limits how many pages one IP reads.** In our tests a run read about 115–135 pages (5 niches × 24 books with
  details) before Amazon started refusing its IPs, and the refusals lasted more than 4 minutes. The Actor then pauses
  and retries (three 60-second pauses), and whatever it still cannot read comes back as free `blocked` rows, or as books
  without details (charged at the `book` price). For wide research, split it across runs a few minutes apart, or turn
  `includeDetails` off for a first pass and open details only for the niches you keep.
- Bot checks are never solved: the Actor changes route or gives up and says so.
- Prices, ranks and review counts are what Amazon showed at that moment from a US IP.

### Is it legal?

It reads public pages anyone can open without logging in, at a human pace, and collects book data — titles, prices, ranks,
publishers — not personal data beyond the author names printed on the books. Use it in line with Amazon's terms and your
local law; you are responsible for how you use the data.

# Actor input Schema

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

One niche per line, as a buyer would type it in Amazon's search box: <code>gratitude journal</code>, <code>coloring book for adults</code>, <code>password log book</code>. Each keyword is searched on Amazon.com in every department you pick below.

## `stores` (type: `array`):

<code>books</code> = Amazon's Books department (paperbacks, hardcovers, spiral-bound and low-content books); <code>kindle</code> = the Kindle Store (e-books, with the share of Kindle Unlimited titles). Pick both to compare print and e-book for the same keyword.

## `booksPerNiche` (type: `integer`):

How many top organic results to analyze per keyword and department (16 per results page; up to 100). The niche summary is computed from these books.

## `includeDetails` (type: `boolean`):

Reads each book's own page for its Best Sellers Rank, category ranks, publisher, independently published or not, publication date, page count, dimensions and ISBN, which the sales estimate and the opportunity score need. Off: only what the search results show, at the lower <code>book</code> price.

## `includeSuggestions` (type: `boolean`):

Adds the phrases Amazon's search box suggests for each keyword (long-tail ideas) to its niche row. Free.

## `analyzeSuggestions` (type: `boolean`):

Each suggestion of your keywords becomes a niche of its own and is analyzed and charged like one, up to <b>Max niches</b>.

## `maxSuggestions` (type: `integer`):

How many of Amazon's suggestions to keep (and analyze, when that is on) per keyword.

## `maxNiches` (type: `integer`):

A hard cap on niches analyzed in the run, suggestions included. The run also stops before a niche your spending limit could not pay for, without sending its requests.

## `includeSponsored` (type: `boolean`):

Off (default): sponsored placements are skipped and counted, so the niche is measured on organic results. On: they are analyzed (and charged) like the others, flagged <code>sponsored</code>.

## Actor input object example

```json
{
  "keywords": [
    "gratitude journal"
  ],
  "stores": [
    "books"
  ],
  "booksPerNiche": 16,
  "includeDetails": true,
  "includeSuggestions": true,
  "analyzeSuggestions": false,
  "maxSuggestions": 5,
  "maxNiches": 50,
  "includeSponsored": false
}
```

# Actor output Schema

## `rows` (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": [
        "gratitude journal"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyscrape/kdp-niche-analyzer").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": ["gratitude journal"] }

# Run the Actor and wait for it to finish
run = client.actor("steadyscrape/kdp-niche-analyzer").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": [
    "gratitude journal"
  ]
}' |
apify call steadyscrape/kdp-niche-analyzer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadyscrape/kdp-niche-analyzer"
        }
    }
}
```

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/Hte01vLQxvZ63ywSe/builds/JiNG45RW6B04JrI4p/openapi.json
