# BookTok Trend Intelligence & Goodreads Enrichment (`thescrapelab/booktok-trend-intelligence`) Actor

Analyze public BookTok videos and export matched book data, TikTok engagement metrics, trend scores, representative evidence, and Goodreads metadata for publishing, author marketing, and reader-demand research.

- **URL**: https://apify.com/thescrapelab/booktok-trend-intelligence.md
- **Developed by:** [Inus Grobler](https://apify.com/thescrapelab) (community)
- **Categories:** Social media, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## BookTok Trend Intelligence & Goodreads Enrichment

### Quick start

What it does: collects public BookTok signals, matches them to books, scores trends, and enriches results with Goodreads and Open Library metadata. Input accepts titles, authors, ISBNs, or discovery topics; output is a structured dataset with book trends and optional video evidence. Use cases include publishing, marketing, and research. Pricing and cost guidance, limitations, and troubleshooting for common no-signal, matching, runtime, and upstream-source cases are documented below.

Example input: use `watchlist` with a title, ISBN, or `Title | Author` pair. Output includes ranked book trends, evidence, confidence, and a run summary. Pay-per-event launch pricing is scheduled for August 3, 2026. Review [pricing and cost](#cost-and-runtime), [limitations](#limitations), and [troubleshooting](#troubleshooting) before increasing limits.

BookTok Trend Intelligence turns public TikTok book videos into ranked, analysis-ready book data. Track named titles, compare competing books, or discover books appearing in BookTok results, then combine TikTok mentions, creators, views, engagement, and recency with Goodreads ratings and book metadata.

Use this BookTok trend tracker for publishing research, author marketing, reader-demand analysis, campaign reporting, acquisition research, influencer discovery, and competitive book intelligence. Results are delivered as clean JSON dataset rows and can also be exported to CSV, Excel, XML, RSS, or HTML.

### What this BookTok analytics Actor does

- Tracks public TikTok videos for a list of book titles, authors, or ISBNs.
- Discovers book candidates from public BookTok keyword and hashtag results.
- Compares multiple books using the same bounded collection and scoring method.
- Matches videos to books using ISBN, title, author, hashtag, and source-query evidence.
- Calculates mentions, unique creators, views, engagements, engagement rate, recency, and a transparent trend score.
- Enriches confident matches with public Goodreads ratings, review counts, genres, covers, identifiers, and canonical URLs.
- Uses Open Library to resolve discovery candidates or fill basic metadata when Goodreads has no confident result.
- Preserves representative TikTok videos and optional evidence rows so analysts can audit every conclusion.
- Returns partial but useful results when one public source is temporarily unavailable.

### Who should use it?

- Publishers comparing reader attention across current and upcoming titles
- Authors and literary agencies measuring BookTok campaign reach
- Book marketers finding videos and creators driving discussion
- Editors and acquisition teams researching rising subjects or genres
- Bookshops, libraries, and recommendation products tracking reader demand
- Researchers building reproducible social-media and book metadata datasets

### Analysis modes

#### Watchlist

Provide one or more books. The Actor searches public TikTok results for every title, matches the collected videos, enriches each book, and returns one `book_trend` row per input.

#### Compare

Provide at least two books. Results are ranked by trend score and include each title's share of the views collected in that run.

#### Discover

Provide BookTok keywords or hashtags. The Actor extracts plausible title signals from captions, hashtags, and search context, resolves them through Open Library, then adds Goodreads enrichment when a confident match is available.

Discovery is deliberately conservative. Ambiguous phrases are left unresolved instead of being presented as books with false certainty.

### Input

Most users only need these five controls:

| Field | What to enter | Suggested first run |
| --- | --- | --- |
| `mode` | Track books, discover BookTok titles, or compare books | `watchlist` |
| `targets` | Books as `Title \| Author` or ISBN; discovery topics in Discover mode | `Dune \| Frank Herbert` |
| `searchDepth` | `quick`, `balanced`, or `deep` | `quick` |
| `enrichWithGoodreads` | Add Goodreads ratings and book details | `true` |
| `includeVideoEvidence` | Add separate rows for individual TikTok videos | `false` |

The search-depth preset sets sensible limits automatically:

| Preset | Named-book videos | Discovery videos per topic | Total video cap | Best for |
| --- | ---: | ---: | ---: | --- |
| `quick` | 1 | 5 | 25 | First runs and low-cost checks |
| `balanced` | 3 | 10 | 100 | Normal research |
| `deep` | 10 | 25 | 250 | Wider coverage and longer runs |

For ambiguous titles, use `Title | Author`. The Actor also accepts ISBN-10 and ISBN-13. The collapsible **More options** section contains only maximum books, the source spending cap, and unmatched-video diagnostics. Fine-grained limits remain supported through JSON/API input for existing advanced integrations.

### Example inputs

#### Track one book

```json
{
  "mode": "watchlist",
  "targets": ["Dune | Frank Herbert"],
  "searchDepth": "quick"
}
````

#### Compare books

```json
{
  "mode": "compare",
  "targets": [
    "Dune | Frank Herbert",
    "Kindred | Octavia E. Butler"
  ],
  "searchDepth": "balanced"
}
```

#### Discover fantasy BookTok titles

```json
{
  "mode": "discover",
  "targets": ["fantasy booktok"],
  "searchDepth": "quick"
}
```

### Output

The Output tab opens on **Results**, a compact book-level table with only the fields clients usually need first:

- rank, title, and author
- trend score and trend label
- matched video count, views, and engagement rate
- Goodreads rating and book URL

Use **Book Details** for additional metadata, **Individual Videos** when evidence rows were requested, and **Full Data (Advanced)** for every raw field. The **Run Summary** contains completion status, counts, runtime, warnings, and source statuses.

#### Example result

```json
{
  "rank": 1,
  "title": "Dune",
  "author": "Frank Herbert",
  "trendScore": 68.42,
  "trendLabel": "strong",
  "mentionCount": 12,
  "totalViews": 2500000,
  "engagementRate": 0.1088,
  "averageRating": 4.21,
  "goodreadsUrl": "https://www.goodreads.com/book/show/44767458-dune"
}
```

The full dataset still includes matching confidence, Goodreads metadata, engagement totals, representative videos, timestamps, warnings, and source provenance for advanced integrations.

### How the trend score works

The score ranges from 0 to 100 and combines:

- sample volume: number of confidently matched videos
- reach: logarithmically scaled total views
- engagement: likes, comments, shares, and saves divided by views
- recency: age of the newest matched public video

Labels are:

- `no_signal` — no collected video met the match threshold
- `emerging` — a limited or early sample
- `rising` — meaningful collected attention
- `strong` — high reach or engagement in the sample
- `breakaway` — exceptional combined sample signals

This is a reproducible ranking of the videos collected in one run. It is not an estimate of every BookTok video ever published and should not be presented as an official TikTok ranking.

### Matching and data quality

Every TikTok match carries:

- `matchConfidence`
- `matchMethod`
- `matchReasons`
- the source query
- representative video evidence

Goodreads enrichment has a separate `goodreadsMatchConfidence`. Low-confidence Goodreads candidates are rejected instead of silently replacing the requested book with a similarly named title.

If a title-only Goodreads lookup is ambiguous, the Actor can use a confidently matched Open Library ISBN for a second Goodreads lookup. Each upstream run remains visible in `UPSTREAM_RUNS` and `sourceRunIds`.

`dataCompleteness`, `sourceStatus`, and `warnings` make partial results explicit. If TikTok is temporarily blocked but Goodreads succeeds, the Actor still returns the book with `no_tiktok_signal` rather than producing an empty dataset.

Some public TikTok search results expose a video URL and caption without engagement counters. Those rows remain auditable, but the aggregate is marked `missing_tiktok_metrics` and its trend score uses only the signals actually available; missing counters are never presented as complete data.

### Cost and runtime

From **August 3, 2026 at 17:05 UTC**, the launch price is **$0.01 per completed `book_trend` result** ($10 per 1,000 results), plus the standard $0.00005 Actor start event. Apify requires advance notice when changing pricing models, so runs before that activation time remain on the existing pay-per-usage model. The introductory event rate is 50% of the planned standard $0.02 per book result. Optional `video_evidence`, `unmatched_video`, and `run_status` rows do not add another BookTok Trend Intelligence result charge.

This workflow calls public TikTok and Goodreads Actors under your Apify account. Their current event pricing can apply separately to those child runs. When TikTok collection requires multiple child runs, the Actor divides `maxUpstreamChargeUsd` across them so the configured pay-per-event ceiling remains a source-level budget. The parent Actor includes its own platform usage in the book-result price rather than adding a separate parent usage charge.

The Actor respects Apify's maximum total charge for the run. If the remaining budget cannot fund one book result, it exits before calling the data sources and returns a clear status row. If the budget allows fewer results than requested, work is capped and the run summary is marked partial instead of returning unpaid book records.

Control spend with:

- `searchDepth` for a Quick, Balanced, or Deep preset
- fewer entries in `targets`
- exact video and book limits in Advanced controls when needed
- `maxUpstreamChargeUsd` for pay-per-event upstream pricing

Start with one to three videos per book. Broad discovery searches and large comparison lists take longer because public TikTok collection is the dominant runtime. Larger query lists are processed with at most three TikTok child runs active at once, which reduces elapsed time without raising the result cap. Discovery topics run independently because each topic can return a full result page; shorter named-book searches are grouped into bounded batches.

### Python API example

```python
import os

from apify_client import ApifyClient

TOKEN = os.environ["APIFY_TOKEN"]
ACTOR_ID = "thescrapelab/booktok-trend-intelligence"

apify_client = ApifyClient(TOKEN)
actor_client = apify_client.actor(ACTOR_ID)

run_input = {
    "mode": "compare",
    "targets": [
        "Dune | Frank Herbert",
        "Kindred | Octavia E. Butler",
    ],
    "searchDepth": "quick",
}

call_result = actor_client.call(run_input=run_input)

if call_result is None:
    raise RuntimeError("Actor run failed")

dataset_client = apify_client.dataset(call_result["defaultDatasetId"])
items = dataset_client.list_items(view="overview", clean=True).items

for item in items:
    print(item)
```

### JavaScript API example

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('thescrapelab/booktok-trend-intelligence').call({
  mode: 'watchlist',
  targets: ['Dune | Frank Herbert'],
  searchDepth: 'quick',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems({
  view: 'overview',
  clean: true,
});
console.log(items);
```

### Scheduling and integrations

Schedule the Actor daily or weekly to create comparable snapshots. Send completed datasets to Google Sheets, Airtable, Make, Zapier, n8n, a database, a BI dashboard, or an LLM workflow through Apify integrations and webhooks.

For time-series reporting, retain each run's `scrapedAt`, source run IDs, trend score, and underlying engagement totals. Do not compare runs that used materially different searches or collection limits without accounting for that change.

### Limitations

- TikTok results are public search samples and may vary by availability, region, ranking, or anti-bot behavior.
- The Actor does not sign in, access private profiles, bypass access controls, or claim complete TikTok coverage.
- Captions do not always name a book clearly. Discovery therefore favors precision and can leave candidates unresolved.
- Metrics are point-in-time public values and can change after collection.
- Public Goodreads search can return similarly named editions or related works; confidence checks reduce but cannot eliminate ambiguity.
- Date filtering excludes videos that do not expose a usable public creation time.
- Open Library and Goodreads coverage varies by book and edition.
- Source layouts, APIs, pricing, and availability can change.

### Troubleshooting

#### I received a book row with zero TikTok mentions

Check `sourceStatus`, `dataCompleteness`, and `warnings`. The search may have returned no public videos, videos may have fallen outside the date range, or candidates may have stayed below `minimumMatchConfidence`.

#### A title matched the wrong edition

Use `Title | Author` or an ISBN instead of title-only input. Review `goodreadsMatchConfidence` and the canonical URLs before merging results into an authoritative catalog.

#### Discovery returned fewer books than expected

Try a more specific topic, move from Quick to Balanced search depth, and optionally include unmatched videos to inspect the evidence. Lowering the confidence threshold increases recall but can also create false matches.

#### The run is slow

Use Quick search depth, reduce the number of targets, and keep individual video rows disabled unless required. Public TikTok extraction normally accounts for most of the runtime.

#### An upstream source failed

The default resilient mode returns partial data with warnings. Enable `strictMode` only when your integration must reject any incomplete run.

### Responsible use

This Actor processes public content and public book metadata only. Use the results responsibly, respect applicable website terms and laws, avoid harassment or sensitive-person profiling, and review source policies for your specific commercial use case.

# Actor input Schema

## `mode` (type: `string`):

Track named books, discover titles from BookTok topics, or compare two or more named books.

## `targets` (type: `array`):

For Track or Compare, enter one book per line as Title | Author or ISBN. For Discover, enter topics such as fantasy booktok. Compare needs at least two books.

## `searchDepth` (type: `string`):

Quick requests up to 1 video per named book or 5 per discovery topic. Balanced requests up to 3 or 10. Deep requests up to 10 or 25 and can take much longer.

## `enrichWithGoodreads` (type: `boolean`):

Add the matched Goodreads rating, review counts, genres, cover, description, identifiers, and book URL.

## `includeVideoEvidence` (type: `boolean`):

Add one separate dataset row for every confidently matched TikTok video. Leave disabled for the simplest book-level output.

## `dateFrom` (type: `string`):

Optional start date. Older videos and videos without a usable public creation date are excluded.

## `dateTo` (type: `string`):

Optional end date. Videos after this date are excluded.

## `maxBooks` (type: `integer`):

Override the search-depth preset's maximum number of named or discovered books. Lower values reduce runtime and cost.

## `maxVideosPerBook` (type: `integer`):

Override the preset's public TikTok video limit for each named book in Track or Compare mode.

## `maxDiscoveryVideosPerQuery` (type: `integer`):

Override the preset's public TikTok video limit for each topic in Discover mode.

## `maxTotalVideos` (type: `integer`):

Override the preset's hard cap for TikTok dataset items read across the complete run.

## `maxUpstreamChargeUsd` (type: `number`):

Maximum total USD event charge allocated across child runs for each pay-per-event source. Item limits remain the main control for other pricing models.

## `minimumMatchConfidence` (type: `number`):

Confidence from 0 to 1 required to connect a TikTok video with a book. Higher values favor precision; lower values return broader matches.

## `useOpenLibraryFallback` (type: `boolean`):

Resolve discovery candidates or fill basic book identity when Goodreads has no confident match.

## `includeUnmatchedVideos` (type: `boolean`):

Add rows for collected videos that did not meet the book-match confidence threshold.

## `maxRepresentativeVideos` (type: `integer`):

Override the preset's number of high-signal videos embedded in each aggregate book result.

## `upstreamTimeoutSecs` (type: `integer`):

Override the preset's maximum seconds for each TikTok batch or Goodreads child run. A timeout returns partial output unless strict mode is enabled.

## `strictMode` (type: `boolean`):

Fail the complete run when an upstream Actor fails. Leave disabled to receive useful partial results with clear warnings.

## `books` (type: `array`):

Backward-compatible API field for named books. New integrations should use targets.

## `discoveryQueries` (type: `array`):

Backward-compatible API field for discovery keywords. New integrations should use targets.

## Actor input object example

```json
{
  "mode": "watchlist",
  "targets": [
    "Dune | Frank Herbert"
  ],
  "searchDepth": "quick",
  "enrichWithGoodreads": true,
  "includeVideoEvidence": false,
  "maxUpstreamChargeUsd": 1,
  "minimumMatchConfidence": 0.55,
  "useOpenLibraryFallback": true,
  "includeUnmatchedVideos": false,
  "strictMode": false
}
```

# Actor output Schema

## `bookTrends` (type: `string`):

The clearest book-level view: rank, title, trend score, video count, views, engagement, Goodreads rating, and book URL.

## `runSummary` (type: `string`):

Completion status, result counts, runtime, warnings, and source statuses.

## `videoEvidence` (type: `string`):

TikTok video rows when individual or unmatched video output was enabled in the input.

## `datasetItems` (type: `string`):

Every raw book, video, and status field for API integrations or detailed exports.

## `upstreamRuns` (type: `string`):

TikTok, Goodreads, and Open Library run provenance and status details.

## `unmatchedCandidates` (type: `string`):

Discovery phrases considered but not confidently resolved into book results.

## `runApi` (type: `string`):

Direct Apify API link for this Actor run.

# 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 = {
    "targets": [
        "Dune | Frank Herbert"
    ],
    "searchDepth": "quick"
};

// Run the Actor and wait for it to finish
const run = await client.actor("thescrapelab/booktok-trend-intelligence").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 = {
    "targets": ["Dune | Frank Herbert"],
    "searchDepth": "quick",
}

# Run the Actor and wait for it to finish
run = client.actor("thescrapelab/booktok-trend-intelligence").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 '{
  "targets": [
    "Dune | Frank Herbert"
  ],
  "searchDepth": "quick"
}' |
apify call thescrapelab/booktok-trend-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=thescrapelab/booktok-trend-intelligence",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "BookTok Trend Intelligence & Goodreads Enrichment",
        "description": "Analyze public BookTok videos and export matched book data, TikTok engagement metrics, trend scores, representative evidence, and Goodreads metadata for publishing, author marketing, and reader-demand research.",
        "version": "1.4",
        "x-build-id": "DfYwgu6wXEEILmcg6"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/thescrapelab~booktok-trend-intelligence/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-thescrapelab-booktok-trend-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/thescrapelab~booktok-trend-intelligence/runs": {
            "post": {
                "operationId": "runs-sync-thescrapelab-booktok-trend-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/thescrapelab~booktok-trend-intelligence/run-sync": {
            "post": {
                "operationId": "run-sync-thescrapelab-booktok-trend-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "mode": {
                        "title": "What do you want to do?",
                        "enum": [
                            "watchlist",
                            "discover",
                            "compare"
                        ],
                        "type": "string",
                        "description": "Track named books, discover titles from BookTok topics, or compare two or more named books.",
                        "default": "watchlist"
                    },
                    "targets": {
                        "title": "Books or discovery topics",
                        "maxItems": 50,
                        "type": "array",
                        "description": "For Track or Compare, enter one book per line as Title | Author or ISBN. For Discover, enter topics such as fantasy booktok. Compare needs at least two books.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "searchDepth": {
                        "title": "Search depth",
                        "enum": [
                            "quick",
                            "balanced",
                            "deep"
                        ],
                        "type": "string",
                        "description": "Quick requests up to 1 video per named book or 5 per discovery topic. Balanced requests up to 3 or 10. Deep requests up to 10 or 25 and can take much longer."
                    },
                    "enrichWithGoodreads": {
                        "title": "Add Goodreads details",
                        "type": "boolean",
                        "description": "Add the matched Goodreads rating, review counts, genres, cover, description, identifiers, and book URL.",
                        "default": true
                    },
                    "includeVideoEvidence": {
                        "title": "Include individual video rows",
                        "type": "boolean",
                        "description": "Add one separate dataset row for every confidently matched TikTok video. Leave disabled for the simplest book-level output.",
                        "default": false
                    },
                    "dateFrom": {
                        "title": "Videos from",
                        "type": "string",
                        "description": "Optional start date. Older videos and videos without a usable public creation date are excluded."
                    },
                    "dateTo": {
                        "title": "Videos to",
                        "type": "string",
                        "description": "Optional end date. Videos after this date are excluded."
                    },
                    "maxBooks": {
                        "title": "Maximum books",
                        "minimum": 1,
                        "maximum": 50,
                        "type": "integer",
                        "description": "Override the search-depth preset's maximum number of named or discovered books. Lower values reduce runtime and cost."
                    },
                    "maxVideosPerBook": {
                        "title": "Videos per named book",
                        "minimum": 1,
                        "maximum": 25,
                        "type": "integer",
                        "description": "Override the preset's public TikTok video limit for each named book in Track or Compare mode."
                    },
                    "maxDiscoveryVideosPerQuery": {
                        "title": "Videos per discovery topic",
                        "minimum": 1,
                        "maximum": 25,
                        "type": "integer",
                        "description": "Override the preset's public TikTok video limit for each topic in Discover mode."
                    },
                    "maxTotalVideos": {
                        "title": "Maximum total videos",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Override the preset's hard cap for TikTok dataset items read across the complete run."
                    },
                    "maxUpstreamChargeUsd": {
                        "title": "Maximum charge per source",
                        "minimum": 0.05,
                        "maximum": 20,
                        "type": "number",
                        "description": "Maximum total USD event charge allocated across child runs for each pay-per-event source. Item limits remain the main control for other pricing models.",
                        "default": 1
                    },
                    "minimumMatchConfidence": {
                        "title": "Book match confidence",
                        "minimum": 0.25,
                        "maximum": 1,
                        "type": "number",
                        "description": "Confidence from 0 to 1 required to connect a TikTok video with a book. Higher values favor precision; lower values return broader matches.",
                        "default": 0.55
                    },
                    "useOpenLibraryFallback": {
                        "title": "Use Open Library fallback",
                        "type": "boolean",
                        "description": "Resolve discovery candidates or fill basic book identity when Goodreads has no confident match.",
                        "default": true
                    },
                    "includeUnmatchedVideos": {
                        "title": "Include unmatched videos",
                        "type": "boolean",
                        "description": "Add rows for collected videos that did not meet the book-match confidence threshold.",
                        "default": false
                    },
                    "maxRepresentativeVideos": {
                        "title": "Preview videos per book",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Override the preset's number of high-signal videos embedded in each aggregate book result."
                    },
                    "upstreamTimeoutSecs": {
                        "title": "Source timeout",
                        "minimum": 60,
                        "maximum": 900,
                        "type": "integer",
                        "description": "Override the preset's maximum seconds for each TikTok batch or Goodreads child run. A timeout returns partial output unless strict mode is enabled."
                    },
                    "strictMode": {
                        "title": "Fail on incomplete source data",
                        "type": "boolean",
                        "description": "Fail the complete run when an upstream Actor fails. Leave disabled to receive useful partial results with clear warnings.",
                        "default": false
                    },
                    "books": {
                        "title": "Books (legacy API field)",
                        "maxItems": 50,
                        "type": "array",
                        "description": "Backward-compatible API field for named books. New integrations should use targets.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "discoveryQueries": {
                        "title": "Discovery topics (legacy API field)",
                        "maxItems": 50,
                        "type": "array",
                        "description": "Backward-compatible API field for discovery keywords. New integrations should use targets.",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
