# Substack Newsletter Intelligence (`humin93/substack-intelligence`) Actor

Substack leaderboards, category rankings, subscriber-scale signals, paid-tier pricing, posting cadence and recommendation networks. Intelligence, not archive scraping. Public metadata only - no post bodies, no personal data.

- **URL**: https://apify.com/humin93/substack-intelligence.md
- **Developed by:** [hyeonsu kim](https://apify.com/humin93) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 publication analyzeds

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?

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

## Substack Newsletter Intelligence

A **Substack scraper** built for market intelligence, not archives. It extracts every **newsletter leaderboard**, category-level **Substack rankings**, published **subscriber count** signals, paid-tier pricing, posting cadence and recommendation networks — the **newsletter intelligence** layer that archive scrapers skip. Use it to answer questions like: who are the top paid newsletters in Finance? How many subscribers does a publication actually display? What does it charge, how often does it post, and who does it recommend?

Most Substack scrapers pull post archives. This actor collects the data around the publications instead:

- **Leaderboards & rankings** — top publications per category, ranked by paid or total audience (32 leaderboard-enabled categories, sweepable in one run).
- **Audience scale** — published subscriber counts ("Over 387,000 subscribers"), subscriber badges, and bestseller tiers (thousands / tens of thousands / hundreds of thousands of paid subscribers).
- **Monetization** — is payment enabled, all plans ($/month, $/year, founding tiers), cheapest monthly price, free vs. paid benefits.
- **Activity** — posts in the last 30 days, posts/week, average likes, comments and restacks, paid-post share, median post length.
- **Recommendation network** — each publication's public outbound recommendations, the growth engine of Substack.

### What it does NOT do

- It does **not** collect post bodies or full text — only titles, links, dates and public counts. Copyright stays with the authors.
- It does **not** touch anything behind a login and collects **no personal data**: no emails, no subscriber identities.
- It is **not** an archive scraper. If you need full post archives, other actors already do that.

### Modes

#### 1. `leaderboard` — ranked top of a category

```json
{
  "mode": "leaderboard",
  "category": "technology",
  "leaderboardType": "paid",
  "maxResults": 25
}
```

Use `"category": "all"` to sweep every leaderboard-enabled category in one run. `leaderboardType` switches between the paid-subscriber and all-subscriber rankings.

#### 2. `category` — long-tail discovery

Same as leaderboard, but paginates deep past the top 25:

```json
{
  "mode": "category",
  "category": "finance",
  "maxResults": 200
}
```

#### 3. `publication` — deep analysis of specific newsletters

```json
{
  "mode": "publication",
  "publicationUrls": [
    "https://www.astralcodexten.com",
    "https://blog.bytebytego.com",
    "https://stratechery.substack.com"
  ]
}
```

Works with `*.substack.com` subdomains and custom domains. Each publication gets archive-derived activity stats and its outbound recommendation network. Set `"enrichPublications": true` in leaderboard/category modes to get the same deep stats for every ranked publication.

### Sample output

One dataset item per publication. This is a real (shortened) record from a `leaderboard` run on the Finance category with enrichment on:

```json
{
  "mode": "leaderboard",
  "categoryName": "Finance",
  "leaderboardType": "paid",
  "rank": 3,
  "name": "Doomberg",
  "url": "https://newsletter.doomberg.com",
  "subdomain": "doomberg",
  "customDomain": "newsletter.doomberg.com",
  "description": "A lateral-thinking approach to energy, finance, and geopolitics...",
  "language": "en",
  "author": { "name": "Doomberg", "handle": "doomberg", "twitter": "DoombergT" },
  "audience": {
    "freeSubscriberCount": 387000,
    "subscriberBadge": "387K+",
    "subscriberCountDisplay": "Over 387,000 subscribers",
    "rankingDetail": "Tens of thousands of paid subscribers",
    "paidSubscribersOrderOfMagnitude": 10000,
    "totalSubscribersOrderOfMagnitude": 100000,
    "bestsellerTier": 10000
  },
  "monetization": {
    "paymentsEnabled": true,
    "plans": [
      { "amountCents": 4000, "currency": "usd", "interval": "month" },
      { "amountCents": 40000, "currency": "usd", "interval": "year" },
      { "amountCents": 120000, "currency": "usd", "interval": "year" }
    ],
    "cheapestMonthlyUsd": 40,
    "paidBenefits": ["Access to all full-length published articles", "..."]
  },
  "activity": {
    "postsLast30Days": 8,
    "postsPerWeek": 1.87,
    "paidPostShareInWindow": 0.88,
    "avgReactionsRecent": 695.4,
    "avgCommentsRecent": 188.9,
    "medianWordcountRecent": 1273,
    "lastPostDate": "2026-09-01T09:01:37.798Z",
    "latestPosts": [
      {
        "title": "With American Characteristics",
        "url": "https://newsletter.doomberg.com/p/with-american-characteristics",
        "date": "2026-09-01T09:01:37.798Z",
        "audience": "only_paid",
        "reactions": 551,
        "comments": 154,
        "wordcount": 1375
      }
    ]
  },
  "recommendations": { "outboundCount": 12, "outbound": [ { "name": "...", "url": "https://..." } ] },
  "timeline": { "createdAt": "2021-04-21T18:58:46.449Z", "firstPostDate": "2021-05-03T13:31:20.521Z" },
  "flags": { "podcastEnabled": false, "communityEnabled": true, "hasRecommendations": true }
}
```

#### Field guide

| Field | Meaning |
|---|---|
| `rank`, `leaderboardType` | Position on the category leaderboard, and which ranking it came from (`paid` or `all`) |
| `audience.freeSubscriberCount` | Subscriber count as published by the publication itself (when displayed) |
| `audience.subscriberBadge` / `subscriberCountDisplay` | The badge/text shown on the publication's page ("387K+", "Over 387,000 subscribers") |
| `audience.rankingDetail` | Substack's own scale wording on the leaderboard ("Tens of thousands of paid subscribers") |
| `audience.paidSubscribersOrderOfMagnitude` | That wording converted to a number you can sort on (10000 = tens of thousands) |
| `audience.bestsellerTier` | Bestseller badge tier: 1000 / 10000 / 100000 paid subscribers |
| `monetization.plans` | Every paid plan with amount (cents), currency and interval, incl. founding tiers |
| `monetization.cheapestMonthlyUsd` | Cheapest way in, normalized to USD/month for comparisons |
| `activity.*` | Computed from the recent public archive: cadence, engagement averages, paid share, median length |
| `recommendations.outbound` | Publications this newsletter publicly recommends (name, URL, blurb) |
| `timeline.createdAt` | When the publication was created — spot fast risers vs. veterans |
| `flags` | Podcast/community enabled, invite-only, has recommendations, etc. |

`activity` and `recommendations` are present in `publication` mode and whenever `enrichPublications` is on.

### Use cases

- **Newsletter market research** — map a category end to end: who ranks where, at what audience scale, at what price point, posting how often. Export to a spreadsheet or feed a dashboard directly from the dataset.
- **Competitive analysis** — track competing newsletters' cadence, engagement averages, paid-post share and pricing changes over time by re-running `publication` mode on a fixed URL list.
- **Sponsorship & advertising prospecting** — filter by category, subscriber order of magnitude and posting cadence to build a target list of newsletters worth sponsoring, with author handles for outreach via public channels.
- **Creator-economy analytics** — pricing distributions per category, bestseller-tier composition, engagement-per-subscriber-scale comparisons across hundreds of publications.
- **Recommendation-graph mapping** — crawl outbound recommendations from a seed list to discover adjacent newsletters and quantify who feeds audience to whom.

### Pricing (pay-per-event)

You pay only for what a run actually delivers:

| Event | Charged when |
|---|---|
| `actor-start` | Once per run (small flat fee) |
| `leaderboard-page` | Per ranked leaderboard/category page fetched (25 publications each) |
| `publication-analyzed` | Per publication deeply analyzed (activity stats + recommendation network) |

If a page or publication can't be fetched, that event is simply not charged — no data, no charge. A maximum-cost limit set on the run is respected: the actor stops gracefully and keeps the partial results already collected.

### FAQ

**Is this legal?** The actor reads only public, login-free pages and endpoints — the same data any visitor sees. Substack's `robots.txt` permits every path it touches (login, publishing and embed paths are excluded and never accessed). No post bodies are stored, and no personal data is collected: no emails, no subscriber identities, no tracking identifiers.

**Am I charged when something fails?** No. Events are charged only when the corresponding data is delivered to the dataset. A failed fetch produces no event. The only fixed cost is the small `actor-start` fee per run.

**How fast / how polite is it?** Requests run at low concurrency with a configurable delay (default 500 ms) and exponential backoff. This is deliberate — a polite scraper is a reliable scraper.

**Where do I get help?** Open an issue on the actor's **Issues tab** in Apify Console, and it will be looked at promptly. Feature requests (new fields, new modes) are welcome.

# Actor input Schema

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

What to collect. <b>leaderboard</b>: ranked top publications of one category (or all categories). <b>category</b>: deep enumeration of a category's publications beyond the top 25 (discovery/long tail). <b>publication</b>: deep intelligence on specific publications you list (subscriber signals, pricing, posting cadence, engagement, recommendation network).

## `category` (type: `string`):

Category slug for leaderboard/category modes, e.g. <code>technology</code>, <code>business</code>, <code>finance</code>, <code>culture</code>, <code>politics</code>. Use <code>all</code> to sweep every leaderboard-enabled category (leaderboard mode only). Full list of slugs is emitted in the run log at startup.

## `leaderboardType` (type: `string`):

Rank by paid subscriptions or by overall (free + paid) audience.

## `publicationUrls` (type: `array`):

Publication home URLs for publication mode. Both substack.com subdomains and custom domains work, e.g. <code>https://www.astralcodexten.com</code> or <code>https://stratechery.substack.com</code>.

## `maxResults` (type: `integer`):

Maximum number of publications to output (per category when sweeping all categories).

## `sortBy` (type: `string`):

Order of dataset items. <b>rank</b> keeps native leaderboard order; <b>subscribers</b> sorts by published subscriber count (publications hiding their count sort last); <b>price</b> sorts by cheapest monthly paid plan.

## `enrichPublications` (type: `boolean`):

In leaderboard/category modes, additionally fetch each publication's archive metadata (posting cadence, engagement averages) and recommendation network. Slower and charged per publication analyzed (pay-per-event).

## `archiveLookbackDays` (type: `integer`):

Window for posting-cadence and engagement statistics computed from archive metadata.

## `requestDelayMs` (type: `integer`):

Polite delay between consecutive HTTP requests. Keep at 500ms or higher.

## `maxRetries` (type: `integer`):

Retries with exponential backoff on 429/5xx/network errors.

## Actor input object example

```json
{
  "mode": "leaderboard",
  "category": "technology",
  "leaderboardType": "all",
  "publicationUrls": [
    "https://www.astralcodexten.com",
    "https://blog.bytebytego.com"
  ],
  "maxResults": 25,
  "sortBy": "rank",
  "enrichPublications": false,
  "archiveLookbackDays": 30,
  "requestDelayMs": 500,
  "maxRetries": 3
}
```

# Actor output Schema

## `publications` (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 = {
    "category": "technology",
    "publicationUrls": [
        "https://www.astralcodexten.com",
        "https://blog.bytebytego.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("humin93/substack-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 = {
    "category": "technology",
    "publicationUrls": [
        "https://www.astralcodexten.com",
        "https://blog.bytebytego.com",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("humin93/substack-intelligence").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 '{
  "category": "technology",
  "publicationUrls": [
    "https://www.astralcodexten.com",
    "https://blog.bytebytego.com"
  ]
}' |
apify call humin93/substack-intelligence --silent --output-dataset

```

## MCP server setup

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

```

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/OiZdArMhvHYPfzFQP/builds/87M9vUPovbas1KhLM/openapi.json
