# Amazon KDP Niche Analyzer & Finder: Book BSR & Niche Score (`tagadanar/kdp-niche-analyzer`) Actor

Amazon KDP niche research from keywords: every top book with Best Sellers Rank, price, rating, reviews, publication date, pages, publisher and KDP flag, plus a transparent niche score per keyword. Books or Kindle. $1 per 1,000 books + $0.003 per niche, usage included.

- **URL**: https://apify.com/tagadanar/kdp-niche-analyzer.md
- **Developed by:** [Tagada Data](https://apify.com/tagadanar) (community)
- **Categories:** E-commerce, SEO tools
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 book analyzeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

Type the book niches you are thinking about ("keto cookbook for seniors", "dog
mom journal") and get back, for each one, the books already ranking on
amazon.com with their **Best Sellers Rank**, price, rating, review count,
publication date and age, page count, publisher and whether they are
independently published (KDP), plus **one niche row per keyword** with a score
you can sort by. No API key, no proxy to set up, no browser.

**$1.00 per 1,000 books + $0.003 per niche report**, platform usage included.

### What you get

Two kinds of rows in the dataset, told apart by `type`.

#### `type: "book"`, one per book

| field | example | notes |
| --- | --- | --- |
| `keyword` / `store` | `keto cookbook for seniors` / `Books (all formats)` | |
| `rank` / `page` | `3` / `1` | organic rank on Amazon's results (ads skipped); `null` on an ad row |
| `asin`, `title`, `authors`, `url`, `image` | `B0HD8DD9BX`, `Keto Diet Cookbook for Seniors…`, `["Eleanor C. Hill"]` | |
| `bookFormat` | `Paperback`, `Kindle Edition`, `Hardcover` | |
| `isBook` | `true` | `false` for products Amazon shelves under Books without being books (spiral notebooks ranked in Office Products) |
| `price` / `currency` / `listPrice` | `2.99` / `USD` / `null` | what a US buyer pays; a Kindle Unlimited title shows its purchase price |
| `rating` / `reviewCount` | `4.9` / `49` | `reviewCount` 0 = nobody has rated it yet |
| `bsr` / `bsrStore` | `109513` / `Kindle Store` | Best Sellers Rank as printed on the book's page |
| `categoryRanks` | `[{"rank": 91, "category": "Low Carb Diets (Books)"}]` | the sub-category ranks, up to 5 |
| `publicationDate` / `ageDays` | `2026-08-06` / `82` | |
| `printLength` | `121` | pages |
| `publisher` / `independentlyPublished` | `Independently published` / `true` | the KDP paperback signal; `null` when the page names no publisher (common on Kindle e-books) |
| `language`, `isbn10`, `isbn13`, `dimensions`, `series` | `English`, …, `9798276518350` | where Amazon prints them |
| `kindleUnlimited`, `isBestSeller`, `sponsored` | `true`, `false`, `false` | |
| `detailStatus` | `ok` | see below |

`detailStatus` says whether the book's own page was read: `ok`; `not-requested`
(you switched book pages off); or, delivered **free**, `refused` (Amazon refused
that page on every route), `time` (the run's time limit), `not-found`,
`other-page` (Amazon answered with a different product) or `unreadable`.

#### `type: "niche"`, one per keyword

Examples: "keto cookbook for seniors" in Books, read 2026-10-27. The same day
"dog training book" scored 30, `saturated`: median BSR 15,900, but a median of
2,695 reviews among its top 10.

| field | example | notes |
| --- | --- | --- |
| `nicheScore` | `44` | 0 to 100, see below; `null` when it cannot be grounded |
| `verdict` / `verdictReason` | `mixed` / `demand 33/100, openness 58/100` | `promising`, `mixed`, `saturated`, `low-demand` |
| `demandScore` / `competitionOpennessScore` | `33` / `58` | the two halves of the score |
| `medianBsr`, `bestBsr`, `booksUnder100kBsr` | `163320`, `43022`, `3` | over the top 10 books |
| `medianReviews`, `booksUnder100Reviews` | `49`, `7` | |
| `medianPrice`, `averageRating` | `14.99`, `4.4` | |
| `independentlyPublishedShare`, `publishedLast365DaysShare`, `medianAgeDays` | `0.88`, `0.5`, `398` | shares of the top 10 (publisher share: of those naming one) |
| `kindleUnlimitedShare`, `nonBookResults` | `0.7`, `0` | |
| `totalResults`, `sponsoredOnPage1`, `cardsOnPage1` | `3769`, `0`, `16` | Amazon's own result count; ad pressure on page 1 |

### How the niche score is computed

It is computed from the **top 10 organic books** of the keyword (ads and
non-book products left out), from numbers Amazon shows publicly. Nothing is
estimated: there is no sales or royalty figure, because a sales estimate from
BSR is a guess and this actor does not sell guesses.

- **Demand (0-100)** from the median Best Sellers Rank of those books, on a log
  scale: median BSR 1,000 or better = 100, about 45,000 = 50, 2,000,000 or worse
  \= 0. Needs at least 3 books with a BSR, otherwise it is left empty.
- **Competition openness (0-100)** from their median review count, on a log
  scale: 0 reviews = 100, 100 reviews = 50, 10,000 or more = 0.
- **Niche score** = the geometric mean of the two, `round(sqrt(demand ×
  openness))`, so a niche needs both buyers and room: a zero on either side
  makes the whole score zero, which an average would hide.
- **Verdict**: `low-demand` when demand < 25, else `saturated` when openness <
  25, else `promising` when the score is 55 or more, else `mixed`.

The score compares keywords with each other, read on the same day; it is not a
forecast. The niche row also carries the raw medians, so you can apply your own
rule instead (for example "at least 5 books under BSR 100,000 and fewer than
100 reviews each").

### Input

| field | default | |
| --- | --- | --- |
| `keywords` | required | up to 50 niches; an amazon.com search link is read as its keyword (`k=`) |
| `format` | `books` | `books` = Amazon's Books store, every format; `kindle` = Kindle Store e-books |
| `booksPerKeyword` | 20 | 3 to 50 organic books per keyword, from Amazon's first 3 result pages |
| `includeDetails` | on | read each book's page for BSR, dates, pages, publisher. Off = search-card fields only and no demand score |
| `includeSponsored` | off | also deliver the ad slots (never scored) |

```json
{ "keywords": ["keto cookbook for seniors", "dog training book"], "booksPerKeyword": 10 }
```

### Pricing

| event | price |
| --- | --- |
| Book analyzed | **$1.00 per 1,000 books** ($0.90 Bronze, $0.80 Silver, $0.70 Gold) |
| Niche report | **$0.003 per keyword** ($0.0027 / $0.0024 / $0.0021) |
| Actor start | $0.001 per run |

Platform usage is included. A book row whose book page could not be read is
delivered free (its `detailStatus` says why), and a niche row with no score is
free too (with book pages switched off, its competition-openness score is the
score). Ten keywords at 20 books cost about $0.23.

### FAQ

**Why are there notebooks in my Books results?**
Amazon's Books search lists spiral notebooks and journals that are sold as
office products. They are what a shopper sees, so they are delivered, marked
`isBook: false` with their Office Products rank, and kept out of the score
(`nonBookResults` counts them). For low-content niches that is useful
competition data in itself.

**Which marketplace?**
amazon.com, read as a US shopper sees it, in US dollars. Other Amazon sites
answer the routes this actor uses with prices missing or converted, so they are
left out rather than sold half-empty.

**What happens when Amazon refuses?**
Each page gets two browser fingerprints on two free routes, and a fresh
cookie jar for Amazon's random checkpoint page, before the actor gives up. A
search Amazon refuses ends the run with a status starting `BLOCKED:`; it never
reports "no results" when it was turned away. A keyword Amazon genuinely has no
books for succeeds with Amazon's own count of 0 as proof.

**Is this legal?**
It reads pages Amazon shows to anyone without logging in and collects no
personal data. Check the terms that apply to your own use.

***

Amazon KDP niche research, KDP niche finder, Kindle niche analyzer, Amazon book
BSR scraper, Best Sellers Rank checker, low-content book niche research, self
publishing keyword research, Kindle Unlimited competition, book market research.

# Changelog

This Actor's version history is a separate document: https://apify.com/tagadanar/kdp-niche-analyzer/changelog.md

# Actor input Schema

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

One book niche per line, as a reader would search Amazon (e.g. "dog mom journal", "keto cookbook for seniors"). Each keyword is searched on amazon.com and scored on its own. Up to 50.

## `format` (type: `string`):

books = Amazon's Books store, every format (paperback, hardcover, Kindle, spiral notebooks listed as books). kindle = the Kindle Store, e-books only.

## `booksPerKeyword` (type: `integer`):

Organic (non-ad) books read per keyword, from the top of Amazon's results, at most 3 search pages. The niche score uses the top 10. 3 to 50.

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

On: every book's Amazon page is read for its Best Sellers Rank, category ranks, publication date, print length, publisher and ISBN, and the niche score uses the BSRs. Off: search-card fields only (price, rating, reviews, format, author) and no demand score.

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

Off: only organic results are delivered. On: ad slots are delivered too, with rank empty and sponsored = true. Ads never enter the niche score.

## Actor input object example

```json
{
  "keywords": [
    "keto cookbook for seniors",
    "dog training book",
    "dog mom journal"
  ],
  "format": "books",
  "booksPerKeyword": 10,
  "includeDetails": true,
  "includeSponsored": false
}
```

# Actor output Schema

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

Book rows (type = book) and one niche row per keyword (type = niche) in the default dataset.

# 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": [
        "keto cookbook for seniors",
        "dog training book"
    ],
    "booksPerKeyword": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("tagadanar/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": [
        "keto cookbook for seniors",
        "dog training book",
    ],
    "booksPerKeyword": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("tagadanar/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": [
    "keto cookbook for seniors",
    "dog training book"
  ],
  "booksPerKeyword": 10
}' |
apify call tagadanar/kdp-niche-analyzer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tagadanar/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/RmXzqKlngyUHwWTpD/builds/YSK2pNYiBmUKj73Al/openapi.json
