
Congress Stock Trades Scraper
scrape.ly/store/querystone/congress-trades-scraperNewsBusiness
3 monthly users

Scrape Substack newsletters, posts and authors without login: titles, full text of free posts, publish dates, reactions, comments with replies, paid/free status, subscriber counts and author info. Search by keyword or paste newsletter, post or profile URLs.
Scrape any Substack newsletter, post, author profile or keyword search into a clean dataset: titles, full text of free posts, publish dates, reactions, restacks, comments with replies, paid/free status, subscriber counts and author details. No login, no browser, and fast: it reads Substack's own public JSON, so a newsletter's latest posts arrive in seconds.
*.substack.com newsletters, custom domains (like lennysnewsletter.com), bare subdomain names, single post links, substack.com/@handle profiles, open.substack.com share links and keyword search.| Field | What it does |
|---|---|
startUrls | Newsletters (https://name.substack.com, a custom domain or just name), post links (/p/slug), profiles (https://substack.com/@handle). |
searchQueries | Keywords searched across all public Substack posts. |
maxPostsPerNewsletter | Newest posts per newsletter or profile (default 10, 0 = all). |
maxSearchResults | Posts per search query (default 10). |
startDate, endDate | Publish date window: YYYY-MM-DD or relative like 30 days. |
contentType | all, newsletter, podcast, thread or video. |
audience | all, free or paid. |
minReactions | Skip posts with fewer reactions. |
includeContent | Full HTML and plain text of free posts (default on). |
includeComments, maxCommentsPerPost | Comment threads and how many comments (with replies) to keep per post. |
includePublicationInfo | Newsletter fields on every row (default on). |
{
"startUrls": ["https://www.lennysnewsletter.com", "https://www.noahpinion.blog"],
"searchQueries": ["climate policy"],
"maxPostsPerNewsletter": 10,
"maxSearchResults": 10,
"startDate": "2026-01-01",
"includeComments": true,
"maxCommentsPerPost": 20
}
One row per post.
| Field | Description |
|---|---|
postId, title, subtitle, slug, url | Post identity and canonical link |
publishedAt, updatedAt | Publish and last-edit time (ISO 8601) |
postType, audience, isPaid | newsletter / podcast / thread / video; everyone, only_paid, founding |
bodyHtml, bodyText, hasFullContent | Full content of free posts (HTML and plain text) |
previewHtml, truncatedBodyText | Public preview for paid posts and the short teaser for all posts |
wordcount, coverImage, description, tags, section | Post details |
reactionCount, reactions, commentCount, childCommentCount, restacks | Engagement |
podcastUrl, podcastDuration, hasVoiceover | Audio details |
authorName, authorHandle, authorId, authorBio, authorPhotoUrl, authorUrl, authors | Byline (all co-authors in authors) |
publicationName, publicationUrl, publicationSubdomain, publicationCustomDomain, publicationDescription, publicationLogoUrl, publicationLanguage | Newsletter |
subscriberCount, subscriberRange, paidSubscriberRange, paymentsEnabled | Newsletter size as Substack shows it |
comments, commentsScraped | Comment tree (body, date, name, handle, reactionCount, isAuthor, isPinned, replies) |
sourceUrl or searchQuery + searchRank, scrapedAt | Where the row came from |
Sample row (shortened; commenter names are fictional):
{
"type": "post",
"postId": 220058014,
"title": "A Nobel for New Keynesian macro, at last!",
"subtitle": "It’s about time.",
"url": "https://www.noahpinion.blog/p/a-nobel-for-new-keynesian-macro-at",
"publishedAt": "2026-10-13T05:28:43.757Z",
"postType": "newsletter",
"audience": "everyone",
"isPaid": false,
"wordcount": 2753,
"reactionCount": 389,
"commentCount": 19,
"restacks": 46,
"bodyText": "I have a Google Doc with a long list of posts I’ve been meaning to write…",
"hasFullContent": true,
"authorName": "Noah Smith",
"authorHandle": "noahpinion",
"publicationName": "Noahpinion",
"publicationUrl": "https://www.noahpinion.blog",
"subscriberCount": "460,000",
"subscriberRange": "Hundreds of thousands of subscribers",
"paidSubscriberRange": "Tens of thousands of paid subscribers",
"comments": [
{
"id": 359697984,
"body": "Great summary of why this prize matters.",
"date": "2026-10-13T05:47:38.273Z",
"name": "Jane Reader",
"handle": "janereader",
"reactionCount": 20,
"isAuthor": false,
"replies": [
{ "id": 359700567, "body": "Thanks!", "name": "Noah Smith", "isAuthor": true, "replies": [] }
]
}
],
"commentsScraped": 2,
"sourceUrl": "https://www.noahpinion.blog",
"scrapedAt": "2026-10-14T21:40:12.31Z"
}
Pay per result, no monthly fee:
Example: 1,000 free posts with full content ≈ $1.50; the same 1,000 posts as metadata only ≈ $0.80. Platform usage (a small amount of compute and datacenter proxy traffic) is billed separately and is usually a few cents per thousand posts.
Is it legal to scrape Substack? The actor reads only public data that Substack serves to any visitor without logging in. Respect authors' copyright and Substack's terms when you reuse the content, and handle personal data (like commenter names) according to the laws that apply to you.
Do I need a Substack account or a proxy? No account. Datacenter proxies are on by default. If Substack blocks a datacenter exit, the actor retries that request through a residential exit automatically, so a run doesn't lose results.
Can I get the text of paid posts? No. Paid posts return all metadata, engagement numbers, the teaser and the public preview Substack shows to non-subscribers, never the paywalled text.
How many posts can I get? Set maxPostsPerNewsletter to 0 for a newsletter's whole public archive. Search returns as many posts as Substack's search offers for a query (typically a few hundred).
Why is a field empty? Substack doesn't fill every field for every post: subscriber counts are only public when the writer shows them, podcast fields only exist on podcast episodes, and bodyHtml is empty for paid posts.
Can I schedule it or use the API? Yes. Schedule runs to track new posts, and read the dataset through the API or export it to JSON, CSV or Excel.
Every field below can be set in the run form, passed through the API, or saved as a task. Unset fields fall back to the defaults shown.
startUrlsarrayOptionalNewsletter, post or profile URLs
Substack newsletters (https://name.substack.com, a custom domain like https://www.lennysnewsletter.com, or just the subdomain name), single post URLs (/p/slug), or author profiles (https://substack.com/@handle). Archive and homepage URLs work too.
searchQueriesarrayOptionaldefault []Search queries
Keywords to search across all public Substack posts, e.g. artificial intelligence or climate policy. Results use the same post output as newsletter scraping.
maxPostsPerNewsletterintegerOptionaldefault 10Max posts per newsletter
Newest posts to save from each newsletter or profile. 0 = the whole archive.
maxSearchResultsintegerOptionaldefault 10Max posts per search query
Posts to save for each search query. 0 = as many as search returns (usually a few hundred).
startDatestringOptionalPublished after
Only posts published on or after this date: YYYY-MM-DD or a relative period such as 30 days or 6 months.
endDatestringOptionalPublished before
Only posts published on or before this date (YYYY-MM-DD or a relative period).
contentTypeenumOptionaldefault "all"Post type
Only posts of this type.
audienceenumOptionaldefault "all"Audience
Paid posts return metadata and the public preview, never the paywalled text.
minReactionsintegerOptionalMin reactions (likes)
Skip posts with fewer reactions.
includeContentbooleanOptionaldefault trueInclude full post content
Add the full HTML and plain text of each free post (one extra request per post). Turn off for fast, cheaper metadata-only results.
includeCommentsbooleanOptionaldefault falseInclude comments
Add each post's comment thread with nested replies.
maxCommentsPerPostintegerOptionaldefault 20Max comments per post
Comments (including replies) to keep per post. 0 = all.
includePublicationInfobooleanOptionaldefault trueInclude newsletter info
Add newsletter fields to every post: subscriber count, description, logo, language, author.
proxyConfigurationobjectOptionaldefault {"useScrapelyProxy":true,"scrapelyProxyGroups":["DATACENTER…Proxy configuration
Datacenter proxies are used by default and work for Substack's public API.
Every run writes its results to a dataset. Preview it in the dashboard, then export it or read it through the API.
| Field | Type | Description |
|---|---|---|
| postId | integer | Substack post ID |
| title | string | null | Post title |
| url | string | null | Canonical post URL |
| publishedAt | string | null | Publish date (ISO 8601) |
| audience | string | null | everyone, only_paid, founding or only_free |
| bodyHtml | string | null | Full HTML of free posts |
| comments | array | null | Comment tree when comments are requested |
You pay for the events the actor reports, such as each result or page it produces. Platform usage is included in the event prices.
| Event | Charged when | Price |
|---|---|---|
| Comment | One comment or reply saved when comments are on. | $0.0004 |
| Post (metadata) | One post saved without full content (content turned off, or a paid post with only the public preview). | $0.0008 |
| Post with full content | One free Substack post saved with its full HTML and text. | $0.0015 |
Run this actor from your own code. Swap in your API token and the examples work as-is.
import { ScrapelyClient } from 'scrapely-client'
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN })
// Start the actor and wait for the run to finish.
const run = await client.actor('echofield/substack-scraper').call({
"startUrls": [
"https://www.lennysnewsletter.com",
"https://www.noahpinion.blog"
],
"searchQueries": [],
"maxPostsPerNewsletter": 10,
"maxSearchResults": 10,
"proxyConfiguration": {
"useScrapelyProxy": true,
"scrapelyProxyGroups": [
"DATACENTER"
]
}
})
// Read the dataset the run produced.
const { items } = await client.dataset(run.defaultDatasetId).listItems()
console.log(items)Tokens live in your account settings. Keep them server-side: a token carries the full permissions of your account.
Connect the Scrape.ly MCP server once and your agent can run this actor as a tool. Pick your tool:
Fetch scrape.ly/agents.md and run echofield/substack-scraperPaste into Claude Code, Codex, Cursor or any AI agent. It signs you in once in the browser.
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp?tools=actors,runs,storage,docs&actors=echofield/substack-scraper"
}
}
}No key in the file: your client opens the browser to sign you in the first time it connects.
Inputs the developer prepared for common jobs. Open one to see its input, then copy it to your account to run it as-is or adjust it.
Latest newsletter posts with up to 5 comments each.
Newsletters matching a keyword that are free to read.
Post titles, dates and links without the full text.
Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes. The advantage lasts forever.