# Beehiiv Newsletter Scraper (`maximedupre/beehiiv`) Actor

Collect public Beehiiv newsletter profiles and posts from submitted URLs. Return publication details, post metadata, available content in plain text, Markdown, or HTML, plus images, links, and sponsor signals in an Apify dataset. Public pages need no customer credentials.

- **URL**: https://apify.com/maximedupre/beehiiv.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** News, Social media, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.15 / 1,000 posts

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

### 🐝 Turn public Beehiiv pages into usable data

Researchers, newsletter teams, marketers, and developers can use this Actor to read public Beehiiv pages and save structured rows. Get newsletter profiles, post metadata, public content, sponsor details, and product page data in an Apify dataset, so you can review or reuse source data without copying it by hand.

The Actor reads public Beehiiv pages and does not bypass private or subscriber-only content.

**Try these workflows**

- Collect public publication profiles and posts with **[Beehiiv Newsletter](https://apify.com/maximedupre/beehiiv/examples/beehiiv-newsletter)**.
- Read public product page details for **[Beehiiv Pricing](https://apify.com/maximedupre/beehiiv/examples/beehiiv-pricing)**.
- Gather post text and metadata for **[Beehiiv Newsletter Examples](https://apify.com/maximedupre/beehiiv/examples/beehiiv-newsletter-examples)**.
- Collect public posts and previews for **[Beehiiv Reviews](https://apify.com/maximedupre/beehiiv/examples/beehiiv-reviews)**.
- Check public Beehiiv page data for **[Is Beehiiv Free](https://apify.com/maximedupre/beehiiv/examples/is-beehiiv-free)**.

#### 📦 Beehiiv records in three shapes

Each saved row has a `recordType` and a public `url`. The three shapes are `post`, `newsletterProfile`, and `productPage`. Optional fields appear when the public page provides them.

Post rows can include publication and author details, access state, preview text, content in plain text, Markdown, and HTML, reading signals, outbound links, and sponsor details with UTM values when found.

#### ▶️ Collect a focused Beehiiv result set

1. Choose one result type: Posts, Newsletter profiles, or Product pages.
2. Add the matching public Beehiiv URLs.
3. For Posts, optionally filter by keyword, date, access level, or reading time.
4. Set `maxItems` to a positive limit when you want to stop early. Leave it empty to return all available results until the source is exhausted.
5. Start the run and open the dataset link in the output.

#### ⚙️ Input

Choose one result type for each run. Fields for the other result types are ignored. The input form accepts public Beehiiv publication, post, or product page URLs.

**Input fields**

| Field | Type | What it does |
| --- | --- | --- |
| `resultType` | string | Required. Chooses `posts`, `newsletterProfiles`, or `productPages`. |
| `posts` | object | Post options. Use when `resultType` is `posts`. |
| `posts.urls` | array of strings | Adds public Beehiiv publication or post URLs. A publication URL finds its public posts. A post URL retrieves that post. |
| `posts.keywords` | array of strings | Optionally keeps posts that match one or more words or phrases. |
| `posts.dateFrom` | date | Keeps posts published on or after this UTC date in `YYYY-MM-DD` form. |
| `posts.dateTo` | date | Keeps posts published on or before this UTC date in `YYYY-MM-DD` form. |
| `posts.accessLevel` | string | Keeps posts with the selected public state: `all`, `free`, `premium`, `preview`, `metadataOnly`, or `unavailable`. |
| `posts.readingTimeMin` | integer | Keeps posts with at least this estimated reading time in minutes. |
| `posts.readingTimeMax` | integer | Keeps posts with no more than this estimated reading time in minutes. |
| `newsletterProfiles` | object | Newsletter profile options. Use when `resultType` is `newsletterProfiles`. |
| `newsletterProfiles.publicationUrls` | array of strings | Adds public Beehiiv publication URLs. |
| `productPages` | object | Product page options. Use when `resultType` is `productPages`. |
| `productPages.urls` | array of strings | Adds public Beehiiv product page URLs. |
| `maxItems` | integer | Optional positive work limit for the selected result type. Leave it empty to return all available results until the source is exhausted. |

**Default input**

This is the public input from a successful current-beta default-input run:

```json
{
  "resultType": "posts",
  "posts": {
    "urls": [
      "https://product.beehiiv.com/p/post-likes-comments-sharing"
    ]
  },
  "maxItems": 1
}
```

#### 🧾 Output

The run output contains a link to the default dataset. The dataset holds one row for each saved result.

**Run output**

| Field | Type | What it does |
| --- | --- | --- |
| `datasetUrl` | URL | Opens the collected Beehiiv results in the default dataset. |

**Post rows**

| Field | Type | What it does |
| --- | --- | --- |
| `recordType` | string | Always `post` for this shape. |
| `url` | URL | Public URL for the post. |
| `title` | string | Public post title. |
| `description` | string | Public post description or summary, when available. |
| `publishedAt` | date-time | Publication date and time from the public page. |
| `publication` | object | Public identity and links for the publication. |
| `publication.name` | string | Public publication name. |
| `publication.canonicalUrl` | URL | Canonical public URL of the publication, when available. |
| `publication.domain` | string | Public domain used by the publication, when available. |
| `publication.logoUrl` | URL | Public publication logo URL, when available. |
| `publication.socialLinks` | array of objects | Public social links listed by the publication, when available. |
| `publication.socialLinks[].platform` | string | Social platform named by the source. |
| `publication.socialLinks[].url` | URL | Public social profile URL. |
| `author` | object | Public author information for the post. |
| `author.name` | string | Public author name. |
| `author.url` | URL | Public author profile URL, when available. |
| `author.imageUrl` | URL | Public author image URL, when available. |
| `accessLevel` | string | Public post state: `free`, `premium`, `preview`, `metadataOnly`, or `unavailable`. |
| `previewText` | string | Public preview text for the post, when available. |
| `content` | object | Public post content in the formats that are available. |
| `content.plainText` | string | Public post content as plain text, when available. |
| `content.markdown` | string | Public post content as clean Markdown, when available. |
| `content.html` | string | Public post content as HTML, when available. |
| `readingTimeMinutes` | integer | Estimated reading time in minutes, when available. |
| `wordCount` | integer | Number of words in the public post, when available. |
| `coverImageUrl` | URL | Public post cover image URL, when available. |
| `outboundLinks` | array of URLs | Unique public links cited in the post. |
| `tags` | array of strings | Public post tags or topical categories, when available. |
| `sponsors` | array of objects | Sponsor placements found in the public post, when available. |
| `sponsors[].name` | string | Public sponsor name. |
| `sponsors[].markerPhrase` | string | Phrase that marked the sponsor placement, when available. |
| `sponsors[].destinationUrl` | URL | Public sponsor destination URL, when available. |
| `sponsors[].utm` | object | UTM attribution values on the sponsor link, when available. |
| `sponsors[].utm.source` | string | UTM source value. |
| `sponsors[].utm.medium` | string | UTM medium value. |
| `sponsors[].utm.campaign` | string | UTM campaign value. |
| `sponsors[].utm.term` | string | UTM term value. |
| `sponsors[].utm.content` | string | UTM content value. |

**Example post row**

This shortened row is from a successful current-beta run. Long content and the outbound link list use `"..."` as omission markers.

```json
{
  "recordType": "post",
  "url": "https://breakingandentering.beehiiv.com/p/liv-golf-lawsuit-and-emmy-nominated-director-presented-by-tatari",
  "title": "LIV Golf Lawsuit and Emmy Nominated Director | Presented by Tatari",
  "description": "Last show of the week!",
  "publishedAt": "2026-08-20T17:42:30.795Z",
  "publication": {
    "name": "what's good",
    "canonicalUrl": "https://breakingandentering.beehiiv.com/",
    "domain": "breakingandentering.beehiiv.com",
    "logoUrl": "https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/publication/logo/0948c743-516e-495f-ba1e-baf36b9b2d51/72435995-C3C7-49A5-82EF-6B29283A7FB9.png"
  },
  "accessLevel": "free",
  "previewText": "Last show of the week!",
  "content": {
    "plainText": "...",
    "markdown": "...",
    "html": "..."
  },
  "readingTimeMinutes": 1,
  "wordCount": 414,
  "coverImageUrl": "https://beehiiv-images-production.s3.amazonaws.com/uploads/publication/thumbnail/0948c743-516e-495f-ba1e-baf36b9b2d51/landscape_Untitled_design__4_.png",
  "outboundLinks": [
    "..."
  ],
  "sponsors": [
    {
      "name": "Tatari",
      "markerPhrase": "Presented by",
      "destinationUrl": "https://lp.tatari.tv/breaking-and-entering?utm_campaign=49261468-Breaking+%26+Entering&utm_source=Breaking+%26+Entering&utm_medium=podcast&utm_content=LP",
      "utm": {
        "source": "Breaking & Entering",
        "medium": "podcast",
        "campaign": "49261468-Breaking & Entering",
        "content": "LP"
      }
    }
  ],
  "author": {
    "name": "Jack Westerkamp",
    "imageUrl": "https://beehiiv-images-production.s3.amazonaws.com/static_assets/gradient_avatar_3.png"
  }
}
```

**Newsletter profile rows**

| Field | Type | What it does |
| --- | --- | --- |
| `recordType` | string | Always `newsletterProfile` for this shape. |
| `url` | URL | Public URL used for the newsletter profile. |
| `description` | string | Public newsletter description, when available. |
| `publication` | object | Public newsletter identity and links. |
| `publication.name` | string | Public publication name. |
| `publication.canonicalUrl` | URL | Canonical public URL of the publication, when available. |
| `publication.domain` | string | Public domain used by the publication, when available. |
| `publication.logoUrl` | URL | Public publication logo URL, when available. |
| `publication.socialLinks` | array of objects | Public social links listed by the publication, when available. |
| `publication.socialLinks[].platform` | string | Social platform named by the source. |
| `publication.socialLinks[].url` | URL | Public social profile URL. |
| `categories` | array of strings | Public newsletter categories, when available. |
| `avatarUrl` | URL | Public newsletter avatar URL, when available. |
| `publishedPostCount` | integer | Number of published posts shown by the public profile, when available. |

**Example newsletter profile row**

This complete row is from a successful current-beta run:

```json
{
  "recordType": "newsletterProfile",
  "url": "https://product.beehiiv.com/",
  "description": "The latest product drops on beehiiv.",
  "publication": {
    "name": "Product Updates",
    "canonicalUrl": "https://product.beehiiv.com/",
    "domain": "product.beehiiv.com",
    "logoUrl": "https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/publication/logo/a8e88f38-1bf6-4bad-8154-2c897fe51252/Social_Profile_pic.png",
    "socialLinks": [
      {
        "platform": "facebook",
        "url": "https://www.facebook.com/trybeehiiv"
      },
      {
        "platform": "instagram",
        "url": "https://www.instagram.com/beehiiv/"
      },
      {
        "platform": "linkedin",
        "url": "https://www.linkedin.com/company/beehiiv"
      },
      {
        "platform": "tiktok",
        "url": "https://www.tiktok.com/@beehiiv"
      },
      {
        "platform": "twitter",
        "url": "https://twitter.com/beehiiv"
      },
      {
        "platform": "youtube",
        "url": "https://www.youtube.com/@beehiiv"
      },
      {
        "platform": "bluesky",
        "url": "https://bsky.app/profile/beehiiv.com"
      }
    ]
  },
  "avatarUrl": "https://media.beehiiv.com/cdn-cgi/image/fit=scale-down,format=auto,onerror=redirect,quality=80/uploads/publication/logo/a8e88f38-1bf6-4bad-8154-2c897fe51252/Social_Profile_pic.png",
  "publishedPostCount": 150
}
```

**Product page rows**

| Field | Type | What it does |
| --- | --- | --- |
| `recordType` | string | Always `productPage` for this shape. |
| `url` | URL | Public URL used for the product page. |
| `title` | string | Public product title. |
| `publishedAt` | date-time | Publication date and time supplied by the public page. |
| `description` | string | Public product description or summary. |
| `content` | object | Public product page content in the formats that are available. |
| `content.plainText` | string | Public product content as plain text, when available. |
| `content.markdown` | string | Public product content as clean Markdown, when available. |
| `content.html` | string | Public product content as HTML, when available. |
| `media` | array of objects | Public media assets available on the product page. |
| `media[].url` | URL | Main public URL for the media asset. |
| `media[].type` | string | Media type supplied by the public page, when available. |
| `media[].altText` | string | Public alternative text for the media asset, when available. |

**Example product page row**

This complete row is from a successful current-beta run:

```json
{
  "recordType": "productPage",
  "url": "https://www.theunpanickedself.com/products/3-step-protocol-for-panic",
  "title": "3-Step Protocol For Panic",
  "publishedAt": "2026-03-06T19:23:21.312Z",
  "description": "A free, practical guide for anyone experiencing panic attacks. The 3 Step Protocol For Panic walks you through a simple, actionable framework to stop fighting panic — and start listening to it instead. No breathing exercises required. Just three steps grounded in real experience and the science of how panic actually works.",
  "content": {
    "plainText": "Most advice tells you to calm panic down. This guide takes a different approach — because fighting panic is exactly what makes it worse. \nThe 3 Step Protocol For Panic is built on one core insight: panic isn't the enemy. It's a signal. And the moment you stop trying to eliminate it, something shifts. Inside you'll find a clear, actionable framework to move through a panic attack without resistance — and guiding questions to make each step personal to your experience. Designed for the moment when nothing else is working.",
    "markdown": "Most advice tells you to calm panic down. This guide takes a different approach — because fighting panic is exactly what makes it worse. \n\nThe 3 Step Protocol For Panic is built on one core insight: **panic isn't the enemy.** It's a signal. And the moment you stop trying to eliminate it, something shifts. Inside you'll find a clear, actionable framework to move through a panic attack without resistance — and guiding questions to make each step personal to your experience. Designed for the moment when nothing else is working.",
    "html": "<p>Most advice tells you to calm panic down. This guide takes a different approach — because fighting panic is exactly what makes it worse. </p><p>The 3 Step Protocol For Panic is built on one core insight: <strong>panic isn't the enemy.</strong> It's a signal. And the moment you stop trying to eliminate it, something shifts. Inside you'll find a clear, actionable framework to move through a panic attack without resistance — and guiding questions to make each step personal to your experience. Designed for the moment when nothing else is working.</p>"
  },
  "media": [
    {
      "url": "https://beehiiv-images-production.s3.amazonaws.com/uploads/product_variant_asset/asset/650dd961-f098-4ca4-b858-a9e229519995/3-step-protocol-image.png"
    }
  ]
}
```

#### 💳 Pricing

**What is charged**

One successfully saved public post is one billable event. The event uses tiered pricing, so the amount depends on the Apify pricing tier on your account. A run with no saved post does not create this post event. Newsletter profile and product page rows are not charged by this event.

#### 🔌 Integrations

Use the Apify Console or API to start a run and read the `datasetUrl` in its output. The Actor reads public Beehiiv URLs and does not need customer credentials for those pages.

**Video guide**

https://www.youtube.com/watch?v=bNACk1\_S\_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### Can it read private or paid Beehiiv posts?

No. It does not promise private or subscriber-only full text. Use the public access state and preview fields when the source exposes them.

##### Should I submit a publication URL or a post URL?

Use a publication URL when you want to find its public posts. Use a direct post URL when you want that post. Both go in `posts.urls`.

##### What does `maxItems` do?

It is an optional positive work limit for the selected result type. Leave it empty to return all available results until the source is exhausted.

##### What content formats can a post row include?

When public content is available, a post row can include plain text, clean Markdown, and HTML. A restricted page may expose less content.

##### What does a newsletter profile row contain?

It can include the publication name, canonical URL or domain, logo, social links, description, avatar, categories, and published-post count when the public page shows them.

##### Can one run use Posts and Newsletter profiles together?

No. Choose one result type for a run, then add the matching URLs. Run the Actor again for another result type.

##### What does the access-level filter do?

It keeps posts with the public state you choose. It does not unlock premium or private content.

##### What does a product page row contain?

It can include the page title, date, description, available text formats, and public media links.

### 📝 Changelog

**v0.0** (22-09-2026)

- Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~beehiiv/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- **[Substack API Scraper: Posts, Authors & Newsletters](https://apify.com/maximedupre/substack-api)** reads public Substack posts, publications, and comments for cross-newsletter research.
- **[Beehiiv Scraper - Newsletters, Posts & Content](https://apify.com/scraper_guru/beehiiv-scraper)** offers a competing workflow for public Beehiiv newsletter and post data.
- **[Beehiiv Newsletter Discovery Scraper](https://apify.com/crawlerbros/beehiiv-newsletter-scraper)** focuses on finding public Beehiiv newsletters and profiles.
- **[Newsletter Sponsorship Intelligence — Substack, beehiiv & Ghost](https://apify.com/silentshadow55/newsletter-sponsors-actor)** helps inspect sponsor placements across public newsletter issues.
- **[Beehiiv Product Parser Spider](https://apify.com/getdataforme/beehiiv-product-parser-spider)** focuses on public Beehiiv product page details and media.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `resultType` (type: `string`):

Choose the kind of public Beehiiv data to return.

## `posts` (type: `object`):

Use these fields when Result type is Posts. A publication URL finds its public posts, and a post URL retrieves that post.

## `newsletterProfiles` (type: `object`):

Use these fields when Result type is Newsletter profiles. Add one or more public Beehiiv publication URLs.

## `productPages` (type: `object`):

Use these fields when Result type is Product pages.

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

Optional work limit for the selected result type. Omit it to collect all available results until the source is exhausted.

## Actor input object example

```json
{
  "resultType": "posts",
  "posts": {
    "urls": [
      "https://product.beehiiv.com/p/post-likes-comments-sharing"
    ]
  },
  "maxItems": 1
}
```

# Actor output Schema

## `datasetUrl` (type: `string`):

Open the collected Beehiiv results.

# 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 = {
    "resultType": "posts",
    "posts": {
        "urls": [
            "https://product.beehiiv.com/p/post-likes-comments-sharing"
        ]
    },
    "maxItems": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/beehiiv").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 = {
    "resultType": "posts",
    "posts": { "urls": ["https://product.beehiiv.com/p/post-likes-comments-sharing"] },
    "maxItems": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/beehiiv").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 '{
  "resultType": "posts",
  "posts": {
    "urls": [
      "https://product.beehiiv.com/p/post-likes-comments-sharing"
    ]
  },
  "maxItems": 1
}' |
apify call maximedupre/beehiiv --silent --output-dataset

```

## MCP server setup

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

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/O1zRJVGSK68gRyMPw/builds/DL6KtnyzBBYgQC8Gj/openapi.json
