# Text Readability and Keyword Density Report (`firebrick_zamia/text-readability-keyword-report`) Actor

Readability scores (Flesch, Flesch-Kincaid, Gunning Fog, SMOG, Coleman-Liau, ARI), reading time, sentence statistics, top keywords and phrases, and target keyword density for text you provide. No network.

- **URL**: https://apify.com/firebrick_zamia/text-readability-keyword-report.md
- **Developed by:** [Aadam Ahmed](https://apify.com/firebrick_zamia) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

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

## Readability Score and Keyword Density Checker

**Get Flesch Reading Ease, Flesch-Kincaid, Gunning Fog, SMOG, Coleman-Liau and ARI scores, reading time, sentence statistics, top keywords and phrases and exact target keyword density for text you provide. Bulk, deterministic, no web calls, no AI.**

### What you get

One record per text with `readability` scores, a `flesch_label`, structure counts, `reading_time_minutes`, `top_keywords` and `target_keywords` with counts and density.

### Use cases

- Readability score check for blog posts, product pages and documentation before publishing.
- Keyword density report for SEO writers: count your target keywords exactly.
- Content QA at scale: flag texts with long sentences or a high grade level.

Analyse text you provide and get, in one record per text: readability scores, reading time, sentence statistics, the most frequent words and phrases, and the exact count and density of your target keywords. **No web calls, no AI model, deterministic.** Callable by developers and AI agents through Apify's MCP server (https://mcp.apify.com).

- **Readability** (English): Flesch Reading Ease, Flesch-Kincaid grade, Gunning Fog, SMOG, Coleman-Liau, Automated Readability Index, complex-word share.
- **Structure**: characters, words, unique words, sentences, paragraphs, average and longest sentence, number of sentences over your word limit.
- **Reading time** at 238 words per minute (Brysbaert 2019, silent reading of non-fiction: https://doi.org/10.1016/j.jml.2019.104047).
- **Keywords**: top words and 2-3 word phrases with counts and density (occurrences / total words x 100), optional English stopword filtering, plus your own **target keywords** counted as whole words (case-insensitive, Unicode aware, so it works for any space-separated script).

### Input

| Field | Meaning |
|---|---|
| `texts` | Texts to analyse (up to 2,000, each up to 500,000 characters) |
| `topKeywords`, `maxPhraseLength`, `removeStopwords` | keyword list options |
| `targetKeywords` | words or phrases to count exactly |
| `longSentenceWords` | threshold for "long sentence" (default 25) |
| `readability` | turn the formulas off if you only need keywords |

### Example input and output

Input (bundled `test-input.json`): one 84-word text, `topKeywords: 8`, `maxPhraseLength: 2`, `targetKeywords: ["actor", "AI agent"]`. Real output (abridged):

```json
{
  "words": 84, "sentences": 6, "paragraphs": 2, "avg_words_per_sentence": 14,
  "longest_sentence_words": 20, "reading_time_minutes": 0.35,
  "readability": { "applicable": true, "flesch_reading_ease": 60.69, "flesch_kincaid_grade": 8.27,
                   "gunning_fog": 9.89, "smog_reliable": false, "automated_readability_index": 7.44 },
  "flesch_label": "standard (8th-9th grade)",
  "top_keywords": [ { "phrase": "actor", "words": 1, "count": 3, "density_percent": 3.571 } ],
  "target_keywords": [ { "keyword": "actor", "count": 3, "density_percent": 3.571 },
                       { "keyword": "AI agent", "count": 1, "density_percent": 2.381 } ]
}
```

### Limitations (read before relying on it)

- **Readability formulas are for English** and are skipped (`applicable: false`) when fewer than 80% of words are Latin-script. Keyword counts work in other languages; there is no stemming, so `actor` and `actors` count separately, and the stopword list is English only.
- **Syllables are counted by a heuristic** with a small exception list, not a pronunciation dictionary. It is right for most common English words but can be off by one on some, so scores can differ by a few points from other tools. The formulas are the published ones (Flesch 1948; Kincaid et al. 1975; Gunning 1952; McLaughlin 1969; Coleman and Liau 1975; Senter and Smith 1967).
- The formulas are designed for passages of about 100+ words; shorter texts get a note. **SMOG needs 30+ sentences** (`smog_reliable`).
- **Sentence splitting is rule-based**: it protects decimals, initials and common abbreviations (Dr., Mr., U.S., etc.) but a sentence ending in an abbreviation such as "etc." is merged with the next one.
- **No keyword density is "right".** The Actor reports numbers; it does not claim a target percentage improves search ranking.
- Reading time is an average-reader estimate, not a measurement.

### Pricing (pay per result)

Pay-per-event with Apify's built-in dataset-item event: each text is one result. The live price is set in Apify Console and shown on the Store page (see Store). Planning figure in our notes: USD 2.00 per 1,000 texts. Competitor snapshot (search results, checked 22 Oct 2026): readability-only Actors list from USD 0.50 to USD 10 per 1,000, and one at USD 250 per 1,000 (see `apify/RESEARCH-3.md`).

### FAQ

**Does it fetch web pages?** No. Pass the text itself.

**Does it use AI?** No.

**Does it handle HTML?** No; strip markup first.

**Which readability score should I use?** Flesch Reading Ease is the most widely quoted (higher is easier); the grade-level formulas (Flesch-Kincaid, Fog, ARI) map to school years.

**Does it support Arabic?** Keyword counts do; readability formulas are English only.

# Actor input Schema

## `texts` (type: `array`):

Texts to analyse, one per line entry (up to 2,000, each up to 500,000 characters). Each text is one billed result. Use the JSON editor for multi-paragraph text.

## `topKeywords` (type: `integer`):

How many of the most frequent words and phrases to report per text. 0 turns the list off.

## `maxPhraseLength` (type: `integer`):

Longest phrase length in words to count (1 = single words, 3 = up to three-word phrases). Phrases must occur at least twice.

## `removeStopwords` (type: `boolean`):

Skip phrases that start or end with common English function words such as the, of, and.

## `targetKeywords` (type: `array`):

Words or phrases whose exact occurrences and density you want reported, one per line (up to 100). Matching is case-insensitive and whole-word.

## `longSentenceWords` (type: `integer`):

Sentences with more words than this are counted as long.

## `readability` (type: `boolean`):

Compute the readability formulas. They apply to English text only.

## Actor input object example

```json
{
  "texts": [
    "Short sentences help readers. Long, winding sentences that stack clause upon clause and rely on uncommon vocabulary tend to lose people before they reach the end. Write for the reader, then check the score."
  ],
  "topKeywords": 10,
  "maxPhraseLength": 2,
  "removeStopwords": true,
  "targetKeywords": [
    "readers",
    "readability"
  ],
  "longSentenceWords": 25,
  "readability": true
}
```

# Actor output Schema

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

All result records.

# 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 = {
    "texts": [
        "Short sentences help readers. Long, winding sentences that stack clause upon clause and rely on uncommon vocabulary tend to lose people before they reach the end. Write for the reader, then check the score."
    ],
    "targetKeywords": [
        "readers",
        "readability"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("firebrick_zamia/text-readability-keyword-report").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 = {
    "texts": ["Short sentences help readers. Long, winding sentences that stack clause upon clause and rely on uncommon vocabulary tend to lose people before they reach the end. Write for the reader, then check the score."],
    "targetKeywords": [
        "readers",
        "readability",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("firebrick_zamia/text-readability-keyword-report").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 '{
  "texts": [
    "Short sentences help readers. Long, winding sentences that stack clause upon clause and rely on uncommon vocabulary tend to lose people before they reach the end. Write for the reader, then check the score."
  ],
  "targetKeywords": [
    "readers",
    "readability"
  ]
}' |
apify call firebrick_zamia/text-readability-keyword-report --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,firebrick_zamia/text-readability-keyword-report"
        }
    }
}
```

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/C6ak7aqwU2Q3X37Qd/builds/uQ7F8H2bxCZcWEeoA/openapi.json
