# Newsletter Lead Finder: Substack, Ghost & Beehiiv Leads (`chaptersoft/newsletter-lead-finder`) Actor

Find newsletter creators for sponsorships, outreach and partnerships. Search Substack and Ghost by keyword or category, or look up any newsletter URL. Subscribers, paid tier, cadence, socials, public emails and lead score. No login.

- **URL**: https://apify.com/chaptersoft/newsletter-lead-finder.md
- **Developed by:** [Jeremy Lam](https://apify.com/chaptersoft) (community)
- **Categories:** Lead generation, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 newsletter leads

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

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Newsletter Lead Finder: Substack, Ghost & Beehiiv leads

Find newsletter creators to **sponsor, pitch, partner with or recruit**. Search Substack and Ghost by keyword or category leaderboard, or bulk-enrich any newsletter URL (Substack, Ghost, Beehiiv, Kit, Buttondown, WordPress…). Every result is **one clean lead row per newsletter**: subscribers, paid tier and prices, posting cadence, last post date, author, every public social profile, publicly listed contact email, recommendation graph and a 0–100 lead score with reasons.

No login, no API key, no proxy needed. **$0.90 per 1,000 leads, no start fee**, and newsletters you already received are never charged again.

### Why this one

| | Newsletter Lead Finder | Typical Substack scrapers |
|---|---|---|
| Platforms | Substack + Ghost directories, plus **any** newsletter URL (Beehiiv, Kit, Buttondown, WordPress, custom domains) in the same row format | Substack only |
| Discovery | Keyword search, Substack category leaderboards (top / paid / trending, up to 525 each), Ghost Explore sections (Top, Top Revenue, Trending, 30+ topics), bulk URLs & @handles | usually one mode |
| Repeat runs | **Since-last-run memory — never pay twice** for the same newsletter | re-charged every run |
| Filters before you pay | subscribers min/max, paid / free, active within N days, language, must have email/socials, exclude words, min score | few |
| Lead quality | Cadence (posts/month, last post, days since), lead score with plain-English reasons, contributors, recommendations | raw fields |
| Price | **$0.0009 → $0.0006 per lead, no start fee** | $0.001–$0.015 + start fees up to $0.10 |

### Quick start

```json
{ "keywords": ["fintech"], "maxResults": 20, "activeWithinDays": 90 }
```

More examples:

- Top paid Technology newsletters with a public email: `{"categories": ["Technology"], "leaderboard": "paid", "requireContact": "email"}`
- Affordable micro-newsletters for sponsorships: `{"keywords": ["running", "marathon"], "minSubscribers": 1000, "maxSubscribers": 20000, "activeWithinDays": 30}`
- Ghost newsletters earning money: `{"categories": ["ghost:Top Revenue"]}`
- Enrich your own list: `{"urls": ["https://www.lennysnewsletter.com", "www.404media.co", "https://www.therundown.ai", "@noahpinion"]}`
- Snowball a niche: add `"includeRecommendations": true` and feed the recommended URLs into the next run.

### Input

| Field | What it does |
|---|---|
| `keywords` | Topics or names. Substack: Substack's own search (~100 per keyword). Ghost: matched against the Ghost Explore "Top" directory (Ghost has no search). With `categories`, keywords narrow the category results. `crypto*` = prefix. |
| `categories` | Substack categories (Technology, Business, Finance, Culture, Crypto, Sports, Health & Wellness, …) and Ghost sections (Top, Top Revenue, Most Popular, Trending, New, Programming, …). Loose matching; prefix `substack:` or `ghost:` to target one. Unknown names fail fast with the full list. |
| `urls` | Up to 1,000 publication URLs, bare domains or Substack `@handles`. Discovery filters are not applied to URLs you list (contact and score filters are). |
| `platforms` | Which directories keywords/categories search (Substack, Ghost). |
| `leaderboard` | Substack ranking: `all` (top by subscribers), `paid` (bestsellers) or `trending`. |
| `minSubscribers` / `maxSubscribers` | Public subscriber count bounds. Hidden counts are excluded when a minimum is set. |
| `monetization` | `any`, `paid`, `free`. |
| `activeWithinDays` | Latest public post must be this recent. |
| `languages` | e.g. `["en"]`. Unknown language is kept. |
| `requireContact` | `none`, `social`, `email`, `socialOrEmail`. |
| `excludeKeywords`, `minLeadScore` | Drop unwanted leads before you pay. |
| `includeRecentPosts`, `recentPostsLimit` | Latest post titles/links/dates (default on, 5). |
| `includeContactEmails` | Read the publication's own About/Contact page for public emails and socials (default on). |
| `includeRecommendations` | Newsletters each lead publicly recommends (default off). |
| `maxResults` | New leads per run (default 50, max 1,000). |
| `sinceLastRun` | Skip newsletters already delivered for the same settings (default on). `stateKey` shares memory across searches. |
| `notifyWebhookUrl` | https URL (Slack/Discord/Zapier/Make/your API) that receives a digest when a run finds new leads. |

#### Categories you can use

**Substack:** Culture, Technology, Business, U.S. Politics, Finance, Food & Drink, Podcasts, Sports, Art & Illustration, World Politics, Health Politics, News, Fashion & Beauty, Music, Faith & Spirituality, Climate & Environment, Science, Literature, Fiction, Health & Wellness, Design, Travel, Parenting, Philosophy, Comics, International, Crypto, History, Humor, Education, Film & TV, Home & Garden, Games.

**Ghost Explore:** Top, Top Revenue, Most Popular, Trending, New, Social Web, Personal, Technology, Business, Programming, News, Finance, Culture, Travel, Education, Art, Faith & Spirituality, Health & wellness, Literature, Sport, Entertainment, Productivity, Design, Food & Drink, Music, Crypto, Science, Fiction, Gaming, Nature & Outdoors, House & Home, Fashion & Beauty, Podcasts, Gear & Gadgets, Parenting, History, Climate, YouTubers.

A plain name (e.g. `Technology`) searches every platform that has it; `substack:Finance` or `ghost:Top Revenue` targets one. Matching ignores case and punctuation.

### Output

One row per newsletter (`type: "newsletter"`, charged) with: `name`, `url`, `domain`, `platform`, `description`, `category`, `leaderboardRank`, `language`, `authorName`, `authorHandle`, `authorBio`, `authorProfileUrl`, `contributors[]`, `subscriberCount`, `subscriberCountText`, `audienceTier`, `paidSubscriberTier`, `bestsellerTier`, `isPaid`, `paidPlans[]`, `monthlyPrice`, `annualPrice`, `currency`, `hasPodcast`, `createdAt`, `firstPostDate`, `lastPostDate`, `daysSinceLastPost`, `postsLast30Days`, `postsLast90Days`, `postsPerMonth`, `cadence`, `recentPosts[]`, `socialLinks` (x, linkedin, instagram, youtube, tiktok, facebook, threads, bluesky, mastodon, website, other\[]), `socialLinksCount`, `publicContactEmails[]`, `aboutUrl`, `subscribeUrl`, `rssUrl`, `recommendationCount`, `recommendations[]`, `leadScore`, `scoreReasons[]`, `matchedBy`, `retrievedAt`.

Free rows: `error` (one URL couldn't be read), `already-delivered` (a URL you listed was delivered in an earlier run — set `sinceLastRun: false` to refresh), `no-match` (explains which filter removed what). The run summary (OUTPUT record) lists per-source counts, skip reasons, charges and notes. Dataset views: **Leads** and **Contacts**.

Example row (trimmed):

```json
{"type": "newsletter", "platform": "substack", "name": "SemiAnalysis", "url": "https://newsletter.semianalysis.com", "authorName": "Dylan Patel", "subscriberCount": 325000, "isPaid": true, "monthlyPrice": 50, "cadence": "several per week", "lastPostDate": "2026-10-23", "postsPerMonth": 9.43, "publicContactEmails": ["sales@semianalysis.com"], "leadScore": 95, "scoreReasons": ["+30 audience 325K+", "+20 posted 6d ago", "+10 9.43 posts/month", "+15 public contact email", "+5 2 social profiles", "+8 runs a paid tier", "+5 bestseller tier 10000+", "+2 recommends other newsletters"], "socialLinks": {"x": "https://x.com/dylan522p", "website": "https://www.semianalysis.com"}}
```

### Pricing

Pay per event `newsletter-lead`: **$0.0009** (Free plan), **$0.0008** (Starter), **$0.0007** (Scale), **$0.0006** (Business) per new lead. No start fee. Filtered-out, already-delivered, no-match and error rows are free. Set **Maximum cost per run** and the Actor stops cleanly at your limit (and tells you so); since-last-run memory means re-running picks up where it left off.

### Data sources & compliance

Only public, no-login pages and endpoints: Substack's public search, category leaderboards, publication About pages and public archives/profiles; Ghost Explore (explore.ghost.org) directory pages and each site's public RSS and `/.well-known/recommendations.json`; any site's homepage, RSS/Atom feed, sitemap and About/Contact page. robots.txt is respected on every non-Substack site. No paywalled content is read. **Emails are only those the publisher prints publicly** on its own site (mailto links or visible text) — nothing guessed, no search-engine dorking, no private data. Requests are rate-limited per host. You are responsible for using leads in line with anti-spam law (CAN-SPAM, GDPR/PECR): personalise, identify yourself and honour opt-outs.

### Limits & tips

- Substack shows a rounded public lower bound for subscribers ("Over 19,000"); Ghost shows member counts only when the site opts in. Beehiiv/other sites don't publish counts (`subscriberCount: null`).
- Ghost and other sites rarely expose paid status, so `monetization: "paid"` keeps only confirmed paid ones (Substack, Ghost Top Revenue, Ghost/Beehiiv upgrade links).
- Beehiiv has no public directory — add Beehiiv newsletters via `urls`. If a Beehiiv site disables RSS, recent posts come from its public sitemap.
- Substack writers who moved to another platform are followed to their current site automatically.
- Substack search returns at most ~100 profiles per keyword — use several synonyms (e.g. `fintech`, `payments`, `banking`) or categories for bigger lists. The run tells you when every source was exhausted.
- Substack rate-limits busy clients. The Actor stays polite and retries; anything still rate-limited is skipped free (not marked as delivered) and picked up by your next run.

### Changelog

- 0.1 — first release: Substack search + leaderboards (top/paid/trending), Ghost Explore, bulk URL enrichment (Beehiiv/Kit/Buttondown/WordPress), since-last-run, lead score, recommendations, webhook.

# Actor input Schema

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

Topics, niches or names to search (e.g. fintech, AI, running, real estate). Substack: uses Substack's own writer/publication search (up to ~100 results per keyword). Ghost: matched against the names, descriptions and topics of the Ghost Explore directory. If you also pick categories, keywords narrow the category results instead. End a word with \* for a prefix ("crypto\*").

## `categories` (type: `array`):

Substack leaderboard categories (Technology, Business, Finance, Culture, U.S. Politics, Health & Wellness, Sports, Crypto, Education, Food & Drink, Science, …) and/or Ghost Explore sections (Top, Top Revenue, Most Popular, Trending, New, Technology, Business, Finance, Programming, …). Names are matched loosely. Prefix with substack: or ghost: to target one platform ("ghost:Top Revenue"). Up to 525 publications per Substack category, ranked.

## `urls` (type: `array`):

Enrich a list of newsletters you already have: https://name.substack.com, custom domains (www.example.com), Ghost, Beehiiv, Kit, Buttondown or WordPress newsletter sites, or Substack writer handles (@handle / substack.com/@handle). Up to 1,000 per run. Filters below (except contact and score) are not applied to URLs you list.

## `platforms` (type: `array`):

Which public directories keywords and categories search. Beehiiv has no public directory — add Beehiiv sites under URLs.

## `leaderboard` (type: `string`):

Which Substack category ranking to read (up to 525 per category). Ghost sections use their own order.

## `minSubscribers` (type: `integer`):

Only publications with at least this many public subscribers (Substack shows a public lower bound such as "Over 19,000"; Ghost shows member counts when the site allows). Publications that hide their count are excluded when this is set.

## `maxSubscribers` (type: `integer`):

Skip publications bigger than this — handy for finding affordable micro-newsletters for sponsorships.

## `monetization` (type: `string`):

Substack paid status is exact. Ghost/other sites rarely expose it, so "paid" keeps only confirmed paid ones (e.g. Ghost Top Revenue).

## `activeWithinDays` (type: `integer`):

Only publications whose latest public post is this recent (e.g. 30). Dormant newsletters are skipped for free.

## `languages` (type: `array`):

Two-letter language codes (en, es, de, pt…). Publications with unknown language are kept.

## `requireContact` (type: `string`):

Only keep leads you can actually reach. Emails come only from the publisher's own About/Contact page or homepage (never guessed).

## `excludeKeywords` (type: `array`):

Skip publications whose name, description or author bio mention any of these.

## `minLeadScore` (type: `integer`):

Only keep leads scoring at least this (0–100; audience, recent activity, cadence, reachability, paid tier). Every row explains its score.

## `includeRecentPosts` (type: `boolean`):

Add the latest post titles, links and dates to each row. Cadence and last post date are always included.

## `recentPostsLimit` (type: `integer`):

How many recent posts to list.

## `includeContactEmails` (type: `boolean`):

Read the publication's own About page for a publicly listed contact email and extra social links. No login, no guessing.

## `includeRecommendations` (type: `boolean`):

Add the newsletters each publication publicly recommends (Substack recommendations; Ghost recommendations). Great for snowballing a niche. One extra request per lead.

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

Stop after this many new leads. You also never pay more than the run's Maximum cost per run.

## `sinceLastRun` (type: `boolean`):

Remember what you already received with the same settings and skip it next time — re-runs and schedules never charge twice for the same newsletter. Turn off to refresh known leads.

## `stateKey` (type: `string`):

Name for the since-last-run memory. Leave empty to derive it from your settings; set one to share memory across different searches (e.g. one campaign).

## `notifyWebhookUrl` (type: `string`):

Optional https:// URL (Slack/Discord incoming webhook, Zapier, Make, your API). Receives a short message + JSON with the new leads when a run finds any.

## `includeNoMatchRows` (type: `boolean`):

Add a free row explaining why nothing matched (and which filter removed the most).

## Actor input object example

```json
{
  "keywords": [
    "fintech",
    "personal finance"
  ],
  "categories": [
    "Technology",
    "ghost:Top Revenue"
  ],
  "urls": [
    "https://www.lennysnewsletter.com",
    "www.404media.co",
    "@noahpinion"
  ],
  "platforms": [
    "substack",
    "ghost"
  ],
  "leaderboard": "all",
  "monetization": "any",
  "activeWithinDays": 90,
  "languages": [
    "en"
  ],
  "requireContact": "none",
  "includeRecentPosts": true,
  "recentPostsLimit": 5,
  "includeContactEmails": true,
  "includeRecommendations": false,
  "maxResults": 20,
  "sinceLastRun": true,
  "includeNoMatchRows": true
}
```

# Actor output Schema

## `leads` (type: `string`):

Overview: name, platform, subscribers, paid, cadence, last post, author, socials, email, score, link.

## `contacts` (type: `string`):

Outreach view: author, email, every social profile.

## `fullJson` (type: `string`):

Every field incl. recent posts, plans, contributors and recommendations.

## `summary` (type: `string`):

Per-source counts, skipped reasons, charged rows, notes.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "fintech"
    ],
    "activeWithinDays": 90,
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("chaptersoft/newsletter-lead-finder").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keywords": ["fintech"],
    "activeWithinDays": 90,
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("chaptersoft/newsletter-lead-finder").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "fintech"
  ],
  "activeWithinDays": 90,
  "maxResults": 20
}' |
apify call chaptersoft/newsletter-lead-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,chaptersoft/newsletter-lead-finder"
        }
    }
}
```

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/qvNzCy0yvIhbfaazz/builds/AVnbUXBDk8cflJR1l/openapi.json
