Substack Posts API: Newsletter Posts, Likes, Comments avatar

Substack Posts API: Newsletter Posts, Likes, Comments

Pricing

from $1.00 / 1,000 post rows

Go to Apify Store
Substack Posts API: Newsletter Posts, Likes, Comments

Substack Posts API: Newsletter Posts, Likes, Comments

Get posts from any Substack newsletter (substack.com or custom domain): title, date, free or paid, likes, comments, word count, authors and optional full text of free posts. Public API, no login.

Pricing

from $1.00 / 1,000 post rows

Rating

0.0

(0)

Developer

Ailu Studio

Ailu Studio

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

15 hours ago

Last modified

Security

Limited permissions

Share

Substack Posts API: Newsletter Posts, Likes, Comments and Full Text

Get the posts of any Substack newsletter as clean JSON rows: title, subtitle, URL, publish time, free or paid, likes, comments, restacks, word count, authors, section, cover image and preview text, plus the optional full text of free posts. Works with name.substack.com publications and custom domains (for example newsletter.pragmaticengineer.com). Unlike the most used Substack Actor in the Store, full text of free posts costs nothing extra and there is no start fee; you can filter by free/paid and by date, and the price is $1.00 per 1,000 rows.

Use cases

  • Track what competitors, analysts or creators publish and how readers react (likes, comments, restacks).
  • Build a reading list or RAG corpus from the free posts of a set of newsletters.
  • Compare publishing cadence, free vs paid mix and post length across newsletters.
  • Schedule a daily run with sinceDays: 1 to collect new posts from many publications.

Input

FieldDefaultMeaning
publications["newsletter.pragmaticengineer.com", "astralcodexten.substack.com"]Subdomain (astralcodexten), *.substack.com address, custom domain or any post URL.
sinceDays0Only posts from the last N days. 0 = no date limit.
audienceallall, free (open to everyone) or paid (paying or founding members).
includeBodyfalseAlso fetch the full text of free posts into bodyText.
maxBodiesPerPublication20Cap on full-text requests per publication, newest first.
maxPostsPerPublication50Cap on posts per publication, newest first.
maxItems200Cap on rows for the whole run.

Output

One row per post, newest first per publication.

FieldMeaning
idStable key <publicationHost>:<postId>.
publication, publicationIdPublication host (from the canonical URL) and Substack ID.
title, subtitle, url, slugPost identity and canonical link.
publishedAtPublish time, ISO 8601 UTC.
postTypenewsletter, podcast, thread or video.
audience, isPaidSubstack audience value and a paid flag.
likes, comments, restacksEngagement counts at fetch time.
wordCountWord count of the full post (also for paid posts).
authors, authorHandlesByline names and Substack handles.
sectionName, coverImageUrl, description, previewText, podcastUrlExtra metadata.
bodyTextPlain-text body of free posts when includeBody is on, else null.
fetchedAtWhen the row was fetched.
{
"id": "newsletter.pragmaticengineer.com:223351496",
"postId": 223351496,
"publication": "newsletter.pragmaticengineer.com",
"publicationId": 458709,
"title": "How software engineering is changing: a tale of two eras",
"subtitle": "We invited readers to write about how building software changed, in an essay challenge. Many of you took part, and today we’re sharing the winning piece from a strong set of entries",
"url": "https://newsletter.pragmaticengineer.com/p/how-software-engineering-is-changing",
"slug": "how-software-engineering-is-changing",
"publishedAt": "2026-11-03T16:58:22.397Z",
"postType": "newsletter",
"audience": "everyone",
"isPaid": false,
"likes": 156,
"comments": 2,
"restacks": 11,
"wordCount": 5921,
"authors": ["Gergely Orosz", "Jessica Salmon", "Ivan Klaric"],
"authorHandles": ["pragmaticengineer", "thejessicasalmon", "ivanklaric182781"],
"sectionName": "Deepdives",
"coverImageUrl": "https://substackcdn.com/image/fetch/$s_!WYGs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25c874c2-9b02-4a24-9046-879cb1500023_1920x899.png",
"description": "We invited readers to write about how building software changed, in an essay challenge. Many of you took part, and today we’re sharing the winning piece from a strong set of entries",
"previewText": "Before we start: I’m in San Francisco this week and there are a few remaining spots for these live events (registration required):",
"podcastUrl": null,
"bodyText": null,
"fetchedAt": "2026-11-04T12:00:00.000Z"
}

How it works and limits

  • Reads each publication's archive listing (/api/v1/archive?sort=new, up to 50 posts per request) and, for full text, /api/v1/posts/<slug>. These are the public JSON endpoints the Substack website itself uses; no login or cookies are sent.
  • Requests to one publication are spaced at least 0.5 s apart with retries on 429/5xx. Substack rate-limits aggressive clients, so keep maxBodiesPerPublication moderate.
  • Paid posts are listed with full metadata, but their body is never fetched or returned (only Substack's short previewText).
  • Counts (likes, comments, restacks) are a snapshot at fetch time.
  • Not covered: Substack Notes, comments text, subscriber counts, profile pages (substack.com/@name), private or deleted posts.

Pricing

Pay per result: $1.00 per 1,000 rows (result event). Platform usage is billed separately by Apify. Removed/free rows are not charged.

Not affiliated with Substack Inc. Uses the public Substack publication JSON endpoints only. Data licence/terms: https://substack.com/tos. Post texts are copyrighted by their authors; respect their rights when you republish anything.

FAQ

Does it work with custom domains? Yes. Enter the domain (e.g. newsletter.pragmaticengineer.com); astralcodexten.substack.com style addresses are followed to their custom domain automatically.

Can I get the full text of paid posts? No. Only free posts include bodyText; paid posts return metadata and Substack's preview line.

How do I pull a whole archive? Set maxPostsPerPublication and maxItems high (e.g. 5000). The Actor pages through the archive newest to oldest.

Why is publication different from what I entered? It is taken from each post's canonical URL, so astralcodexten.substack.com becomes www.astralcodexten.com. This keeps id stable however you write the input.