# Freebooksy Scraper (`crawlerbros/freebooksy-scraper`) Actor

Scrape free and discounted Kindle ebook deals from Freebooksy - the leading free-ebooks deal site. Daily deals, genre archives, tag pages, full-text search, and direct post/URL lookup with cover images, retailer links (Kindle/Apple Books/Kobo/Nook/Google Play), series data, and deal expiry dates.

- **URL**: https://apify.com/crawlerbros/freebooksy-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** E-commerce, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

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

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

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

# README

## Freebooksy Scraper

Scrape **Freebooksy** — the leading free-ebooks deal site for Amazon Kindle, Apple Books, Kobo, Nook, and Google Play. Pull today's **Deals of the Day**, browse **32 genre archives**, follow **tag pages**, run **full-text keyword searches**, or fetch specific deal posts by URL. Every deal comes with the book title, author, blurb, price, deal expiry date, genres, cover image, Amazon ASIN, and direct retailer links. Plain HTTP scraping of the public website — no login, no cookies, no proxy required.

### What this actor does

- **Five modes:** `deals` (homepage Deals of the Day), `byGenre` (genre archive browse), `byTag` (tag archive browse), `search` (keyword search), `byUrl` (direct deal-post URLs)
- **32 genres** as a dropdown — browse Romance, Fantasy, Mystery, Cozy Mystery, Science Fiction, Young Adult, and more
- **Retailer links** — Kindle, Apple Books, Kobo, Nook, and Google Play buy links per deal
- **Series data** — "other books in the series" with cover, URL, and Kindle price
- **Filters:** price range, free-only, deal expiry date window, keyword, genre
- **Empty fields are omitted** — no `null` values in the dataset

### Output per deal

- `asin` — Amazon ASIN (e.g. `B0C6HK79FV`)
- `bookTitle`, `author`, `description` — the book's blurb
- `price` — USD price (e.g. `0.99`), `priceLabel` — raw label (e.g. `$0.99`)
- `isFree` — `true` when the deal is completely free
- `dealExpiresOn` — the date the free/promotional price ends (ISO `YYYY-MM-DD`)
- `coverUrl` — book cover image (Amazon media CDN)
- `amazonUrl` — Amazon Kindle deal link
- `appleBooksUrl`, `koboUrl`, `nookUrl`, `googlePlayUrl` — retailer buy links where available
- `retailers[]` — full list of `{retailer, url}` buy buttons
- `genres[]` — genre slugs the deal's post is filed under
- `tags[]` — post tags (e.g. `kindle-unlimited`, `cozy-mystery`)
- `isSeries`, `seriesBooks[]` — `{title, coverUrl, url, price, asin}` for other books in the series
- `postTitle`, `postUrl`, `postPublishedAt` — the Freebooksy deal post this deal appeared in
- `sourceUrl` — canonical page the deal was found on
- `recordType: "deal"`, `scrapedAt` — UTC timestamp

Homepage Deals of the Day cards additionally include `genreLabel` (the display genre name). If a requested URL cannot be fetched, the actor emits a `recordType: "error"` record with `sourceUrl` and `error`.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `deals` | `deals` / `byGenre` / `byTag` / `search` / `byUrl` |
| `genre` | string | `romance` | Genre archive to browse (mode=byGenre) — 32 options |
| `genreFilter` | string | – | Only emit deals whose post is tagged with this genre |
| `tagSlug` | string | `kindle-unlimited` | Freebooksy tag slug (mode=byTag) |
| `searchQuery` | string | `romance` | Free-text search (mode=search) |
| `startUrls` | array | – | Deal-post URLs to fetch (mode=byUrl) |
| `keywords` | string | – | Only emit deals whose title/author/description contains this text |
| `minPrice` / `maxPrice` | number | – | Price range in USD |
| `freeBooksOnly` | bool | `false` | Only emit completely free deals |
| `dateFrom` / `dateTo` | string | – | Deal expiry-date window (`YYYY-MM-DD`) |
| `includeSeriesBooks` | bool | `true` | Attach series info to each deal |
| `maxPages` | int | `3` | Archive pages to walk (1–100) |
| `maxItems` | int | `50` | Hard cap on emitted records (1–1000) |
| `proxyConfiguration` | object | AUTO | Optional; uses the free Apify AUTO proxy only as a fallback |

#### Example: today's deals of the day

```json
{
  "mode": "deals",
  "maxItems": 20
}
```

#### Example: browse the romance archive, free books only, 2 pages

```json
{
  "mode": "byGenre",
  "genre": "romance",
  "freeBooksOnly": true,
  "maxPages": 2,
  "maxItems": 100
}
```

#### Example: search with filters

```json
{
  "mode": "search",
  "searchQuery": "cozy mystery",
  "keywords": "baker",
  "genreFilter": "cozy-mystery",
  "dateFrom": "2026-08-01"
}
```

#### Example: specific deal posts

```json
{
  "mode": "byUrl",
  "startUrls": [
    { "url": "https://www.freebooksy.com/2026/08/03/heatwave-whodunits-cozy-mystery-series/" }
  ]
}
```

### Use cases

- **Deal aggregators** — feed today's free and discounted Kindle titles into a daily deals site or newsletter
- **Deal tracking & price alerts** — monitor which books are promoted, at what price, and when the deal expires
- **Book marketing research** — study which genres and books Freebooksy promotes for author/publisher outreach
- **Recommendation engines** — consume genre-tagged ebook deals with covers and retailer links
- **Library & reading apps** — surface free books with direct retailer links to users
- **Backlist promotion analysis** — follow tag archives to see which authors/books recur in promotions

### FAQ

**What is the data source?**
The public freebooksy.com website — its homepage Deals of the Day widget, genre archives at `/read/genre/<slug>/`, tag archives at `/tag/<slug>/`, and WordPress search at `/?s=<query>`. All data is server-rendered HTML; no API key or account is needed.

**Why does the "Data Source" say Freebooksy and not BookBub?**
This actor replaces an earlier BookBub slot. BookBub's deal data could not be scraped reliably from Apify cloud: its API returns `403/406` to datacenter egress (and `406` to TLS-impersonating clients), and its web pages render deals entirely via JavaScript (zero deal titles in the raw HTML). Freebooksy is the leading free-ebook-deals site in the same category and serves complete server-rendered deal data that works from plain datacenter egress. Folder and slug are named for the actual platform being scraped.

**Are the deals free, or are some paid?**
Freebooksy is primarily a free-ebooks site, but its Deals of the Day widget also promotes discounted titles ($0.99–$1.99). Set `freeBooksOnly: true` to keep only free deals.

**Why do some records lack a `dealExpiresOn` date?**
Homepage Deals of the Day cards don't display an expiry date — only deal-post book cards do. Omitted fields are simply not included in the record.

**How fresh is the data?**
Genre archives and posts are updated daily; the homepage Deals of the Day reflects the current day's promotions. Run the actor on a schedule (e.g. daily) to track changes.

**Do I need a proxy?**
No. Freebooksy is accessible directly from datacenter IPs. An optional `proxyConfiguration` field (free Apify AUTO group) is available as a fallback if you hit rate limits.

**Are there rate limits?**
The site doesn't publish rate limits. The actor walks pages politely with small delays and respects `maxPages` / `maxItems` caps.

**What are genre slugs?**
Slugs are the URL-safe form used in archive URLs (e.g. `science-fiction`, `cozy-mystery`, `young-adult`). The `genre` and `genreFilter` inputs are dropdowns, so you never need to type them.

**Why are there sometimes fewer records than `maxItems`?**
Deduplication — the same book promoted across multiple posts is emitted once per run. Filters (price, date window, keywords) can also reduce the final count, and archive pages may simply contain fewer deals.

**Is this actor affiliated with Freebooksy?**
No. This is a third-party scraper using the publicly accessible freebooksy.com website.

# Actor input Schema

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

What to fetch.

## `genre` (type: `string`):

Genre archive to browse (mode=byGenre).

## `genreFilter` (type: `string`):

Only emit deals whose post is tagged with this genre. Applies to all modes.

## `tagSlug` (type: `string`):

Freebooksy tag slug, e.g. `mystery`, `kindle-unlimited`, `contemporary-romance`.

## `searchQuery` (type: `string`):

Free-text search across Freebooksy deal posts.

## `startUrls` (type: `array`):

Optional Freebooksy deal post URLs to fetch directly.

## `keywords` (type: `string`):

Only emit deals whose title, author, or description contains this text (case-insensitive).

## `minPrice` (type: `number`):

Only emit deals priced at or above this value. Applies to homepage deals and series-book prices.

## `maxPrice` (type: `number`):

Only emit deals priced at or below this value.

## `freeBooksOnly` (type: `boolean`):

Only emit deals that are completely free (drops paid promotions).

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

Only emit deals expiring on or after this date (YYYY-MM-DD).

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

Only emit deals expiring on or before this date (YYYY-MM-DD).

## `includeSeriesBooks` (type: `boolean`):

Attach other books in the series (cover, URL, price) to each deal record.

## `maxPages` (type: `integer`):

Maximum archive pages to walk (genre / tag / search modes). ~7 deals per post, 10 posts per page.

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

Hard cap on emitted records.

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

Optional. Uses the free Apify AUTO proxy group as a fallback if freebooksy.com rate-limits the datacenter IP.

## Actor input object example

```json
{
  "mode": "deals",
  "genre": "romance",
  "tagSlug": "kindle-unlimited",
  "searchQuery": "romance",
  "startUrls": [],
  "freeBooksOnly": false,
  "includeSeriesBooks": true,
  "maxPages": 3,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `deals` (type: `string`):

Dataset containing all scraped Freebooksy ebook deals.

# 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 = {
    "mode": "deals",
    "genre": "romance",
    "tagSlug": "kindle-unlimited",
    "searchQuery": "romance",
    "startUrls": [],
    "freeBooksOnly": false,
    "includeSeriesBooks": true,
    "maxPages": 3,
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/freebooksy-scraper").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 = {
    "mode": "deals",
    "genre": "romance",
    "tagSlug": "kindle-unlimited",
    "searchQuery": "romance",
    "startUrls": [],
    "freeBooksOnly": False,
    "includeSeriesBooks": True,
    "maxPages": 3,
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/freebooksy-scraper").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 '{
  "mode": "deals",
  "genre": "romance",
  "tagSlug": "kindle-unlimited",
  "searchQuery": "romance",
  "startUrls": [],
  "freeBooksOnly": false,
  "includeSeriesBooks": true,
  "maxPages": 3,
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call crawlerbros/freebooksy-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/freebooksy-scraper"
        }
    }
}

```

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/CmlVe7IT5uelrDFx4/builds/tR5OWwmNtScd76ed6/openapi.json
