# Substack RSS Feed Extractor & Newsletter Monitor (`tugelbay/substack-rss-intelligence`) Actor

Extract structured newsletter posts from official public Substack RSS feeds without browser scraping. Users are responsible for lawful access and downstream use.

- **URL**: https://apify.com/tugelbay/substack-rss-intelligence.md
- **Developed by:** [Tugelbay Konabayev](https://apify.com/tugelbay) (community)
- **Categories:** Automation, News, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 substack 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 RSS feed extractor for public newsletters: submit authorized publication feeds and receive post URL, title, author, categories, summary, content, media metadata, status, and `publishedAt` as structured JSON for monitoring and research.

This Actor intentionally reads the RSS interface that Substack documents for public publications. It does not crawl publication pages, discover feeds, use a private API, access paywalled content, collect comments or Notes, or bypass access controls. You provide the feeds you are authorized to process.

### Why use it and features

- Accepts up to 50 official `https://publication.substack.com/feed` URLs per run.
- Parses RSS publication metadata and public post fields.
- Returns title, canonical URL, GUID, publication date, author, categories, summary, content text, image metadata, and podcast enclosure metadata when present.
- Deduplicates posts by canonical URL or GUID.
- Filters posts with an optional `publishedAfter` ISO 8601 date-time.
- Limits results per feed and caps large content fields.
- Processes feeds sequentially with configurable polite pacing.
- Retries rate limits and temporary server errors with bounded backoff.
- Stops after 3 redirect hops, 20 total retries, or 540 seconds per run.
- Produces visible `feedError` dataset rows for HTTP, network, or XML failures.
- Uses no browser and no proxy by default, keeping runs fast and inexpensive.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `feedUrls` | array | required | Official public Substack RSS URLs in request-list format. |
| `maxItemsPerFeed` | integer | `20` | Newest matching items returned per feed, from 1 to 100. |
| `publishedAfter` | string | empty | Optional ISO 8601 cutoff date-time. |
| `includeContentHtml` | boolean | `false` | Include the HTML supplied in the RSS item. |
| `maxContentChars` | integer | `5000` | Character cap for content text and optional HTML. |
| `requestDelaySecs` | number | `1` | Delay between sequential feed requests. |

Example input:

```json
{
  "feedUrls": [
    { "url": "https://thedatacollector.substack.com/feed" }
  ],
  "maxItemsPerFeed": 10,
  "publishedAfter": "2026-07-01T00:00:00Z",
  "includeContentHtml": false
}
````

### Output data fields

Each successful dataset row represents one public RSS post:

```json
{
  "recordType": "post",
  "feedUrl": "https://publication.substack.com/feed",
  "publicationTitle": "Publication name",
  "publicationUrl": "https://publication.substack.com",
  "postTitle": "Post title",
  "postUrl": "https://publication.substack.com/p/post-slug",
  "guid": "https://publication.substack.com/p/post-slug",
  "publishedAt": "2026-07-13T10:00:00Z",
  "author": "Author name",
  "categories": ["AI", "Data"],
  "summary": "Plain-text summary",
  "contentText": "Plain-text RSS content",
  "status": "ok"
}
```

If a feed is unavailable or malformed, the Actor stores a diagnostic-style row with `recordType: "feedError"`, the feed URL, and a concise error. Successful posts use the `substack-post` pay-per-event name; `feedError` records and Actor starts do not emit a billable event. The `OUTPUT` key-value-store record summarizes feeds, posts, errors, downloaded bytes, retries, 429 responses, billable event count, and runtime.

### Pricing

Billing deduplication is scoped to a single feed response in a single run. Re-running the same feed can emit and charge for the same posts again. The FREE-tier list price is **$2 per 1,000 successful posts** (`$0.002` per `substack-post` event). The hard maximum is 5,000 billable post events per run (`50 feeds × 100 posts`), so the maximum list-price result charge for one run is **$10**. Store tier discounts can only reduce that amount. Failed feeds and Actor starts do not emit a billable event.

### How to run and use the feed extractor

1. Start with one authorized public `publication.substack.com/feed` URL and a small item limit.
2. Inspect canonical post URLs, `publishedAt`, content fields, and any explicit `feedError` row.
3. Schedule only the validated feed and persist the last successful cutoff in your own workflow.

Use the Actor from Apify Console, API, schedules, webhooks, Make, Zapier, or any integration that consumes the default dataset. For monitoring, schedule periodic runs and set `publishedAfter` to the previous successful checkpoint in your own workflow. RSS feeds normally expose only a recent window, so this Actor is not a historical archive.

### Substack RSS comparison

| Route | Best for | Trade-off |
| --- | --- | --- |
| This Actor | Bounded multi-feed JSON in Apify datasets, schedules, webhooks, and integrations | Only the public RSS window and fields are available |
| Direct RSS client | One feed inside your own application | You maintain retries, XML normalization, storage, and run summaries |
| Page scraper/private API | Fields absent from RSS | Outside this Actor's safety boundary; paywalls and access controls must not be bypassed |

Use the direct feed when your application already owns the ingestion stack. Use this Actor when Apify orchestration and normalized error rows remove maintenance.

### FAQ

#### Does this read paid or subscriber-only posts?

No. It returns only content present in the public RSS response and does not access subscriber sessions or paywalls.

#### Can it discover a publication feed for me?

No. You provide direct authorized Substack publication feed URLs; unrestricted URL fetching is intentionally rejected.

#### Can the same post be billed again?

Yes. Deduplication is run-local. Re-running the same feed can return and bill the same public post again.

### Validation evidence and Substack terms (2026-07-14)

Validation on 2026-07-14 preserves the RSS-only boundary:

- Substack's current [Terms of Use](https://substack.com/terms) and [Privacy Policy](https://substack.com/privacy) remain authoritative.
- Results retain feed/post URLs, GUID, status, and `publishedAt`; unavailable or malformed feeds produce explicit non-billable `feedError` rows.
- Strict Actor QA validates URL restrictions, schemas, bounded retries, links, metadata, Docker configuration, and the `substack-post` PPE event before release.
- Only feeds you are authorized to process should be submitted; copyright, privacy, and republication obligations remain with the user.

This evidence does not guarantee feed availability, historical completeness, subscriber content, rankings, traffic, or AI citations.

### Limits and responsible use

Only direct Substack publication subdomains are accepted in this first release. Custom-domain feeds are intentionally rejected because an unrestricted URL fetcher would introduce server-side request forgery risk. The Actor cannot return content absent from the public RSS response, recover deleted posts, access subscriber-only pages, or guarantee that every publication exposes the same fields.

Respect publishers' rights, applicable law, Substack terms, and reasonable request frequency. Do not use the output for spam, unauthorized republication, personal-data enrichment, or attempts to evade access restrictions.

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Substack. Substack is a third-party service, so feed availability and behavior can change without notice. Only submit feeds you are authorized to access and process. RSS output can contain third-party copyrighted material; you are responsible for ensuring that storage, analysis, republication, and other downstream use is lawful and authorized.

The Actor stops a feed after bounded retries and reports 429 responses in `OUTPUT`. Operational policy: if 429 responses affect 20% or more of feed requests in monitored public runs, pause public traffic and review the integration rather than adding proxies or increasing retries. Sustained Substack blocking is a stop condition, not a signal to bypass controls.

### Support

When reporting an issue, include the public feed URL, sanitized Actor input, run ID, and the error message. Never send account credentials, cookies, or private publication data.

# Actor input Schema

## `feedUrls` (type: `array`):

Official public feeds in https://publication.substack.com/feed format. Up to 50 feeds per run.

## `maxItemsPerFeed` (type: `integer`):

Maximum number of newest matching posts returned and billed from each feed. A run can emit at most 5,000 successful post events (50 feeds × 100 posts). Re-running the same input emits and bills the posts again; deduplication applies only within one feed response in one run.

## `publishedAfter` (type: `string`):

Optional ISO 8601 date-time, for example 2026-06-01T00:00:00Z. Posts older than this value are skipped.

## `includeContentHtml` (type: `boolean`):

Include RSS-provided post HTML. Disabled by default for smaller, cleaner datasets.

## `maxContentChars` (type: `integer`):

Maximum characters retained in contentText and optional contentHtml per post.

## `requestDelaySecs` (type: `number`):

Polite delay in seconds between sequential feed requests.

## Actor input object example

```json
{
  "feedUrls": [
    {
      "url": "https://thedatacollector.substack.com/feed"
    }
  ],
  "maxItemsPerFeed": 20,
  "includeContentHtml": false,
  "maxContentChars": 5000,
  "requestDelaySecs": 1
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing structured Substack posts and feed error records.

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

Feed, post, and error counts for the run.

# 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 = {
    "feedUrls": [
        {
            "url": "https://thedatacollector.substack.com/feed"
        }
    ],
    "maxItemsPerFeed": 20,
    "includeContentHtml": false,
    "maxContentChars": 5000,
    "requestDelaySecs": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("tugelbay/substack-rss-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 = {
    "feedUrls": [{ "url": "https://thedatacollector.substack.com/feed" }],
    "maxItemsPerFeed": 20,
    "includeContentHtml": False,
    "maxContentChars": 5000,
    "requestDelaySecs": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("tugelbay/substack-rss-intelligence").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "feedUrls": [
    {
      "url": "https://thedatacollector.substack.com/feed"
    }
  ],
  "maxItemsPerFeed": 20,
  "includeContentHtml": false,
  "maxContentChars": 5000,
  "requestDelaySecs": 1
}' |
apify call tugelbay/substack-rss-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=tugelbay/substack-rss-intelligence",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Substack RSS Feed Extractor & Newsletter Monitor",
        "description": "Extract structured newsletter posts from official public Substack RSS feeds without browser scraping. Users are responsible for lawful access and downstream use.",
        "version": "0.2",
        "x-build-id": "sMjHJozgpkqu2of8d"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/tugelbay~substack-rss-intelligence/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-tugelbay-substack-rss-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/tugelbay~substack-rss-intelligence/runs": {
            "post": {
                "operationId": "runs-sync-tugelbay-substack-rss-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/tugelbay~substack-rss-intelligence/run-sync": {
            "post": {
                "operationId": "run-sync-tugelbay-substack-rss-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "feedUrls"
                ],
                "properties": {
                    "feedUrls": {
                        "title": "Substack RSS feed URLs",
                        "type": "array",
                        "description": "Official public feeds in https://publication.substack.com/feed format. Up to 50 feeds per run.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "maxItemsPerFeed": {
                        "title": "Maximum posts per feed",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Maximum number of newest matching posts returned and billed from each feed. A run can emit at most 5,000 successful post events (50 feeds × 100 posts). Re-running the same input emits and bills the posts again; deduplication applies only within one feed response in one run.",
                        "default": 20
                    },
                    "publishedAfter": {
                        "title": "Published after",
                        "type": "string",
                        "description": "Optional ISO 8601 date-time, for example 2026-06-01T00:00:00Z. Posts older than this value are skipped."
                    },
                    "includeContentHtml": {
                        "title": "Include content HTML",
                        "type": "boolean",
                        "description": "Include RSS-provided post HTML. Disabled by default for smaller, cleaner datasets.",
                        "default": false
                    },
                    "maxContentChars": {
                        "title": "Maximum content characters",
                        "minimum": 500,
                        "maximum": 50000,
                        "type": "integer",
                        "description": "Maximum characters retained in contentText and optional contentHtml per post.",
                        "default": 5000
                    },
                    "requestDelaySecs": {
                        "title": "Delay between feeds",
                        "minimum": 0,
                        "maximum": 30,
                        "type": "number",
                        "description": "Polite delay in seconds between sequential feed requests.",
                        "default": 1
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
