New: Earn 20% as an AgentAlley affiliate. Share your link and earn on every sale you refer. Join now New: Earn 20% as an affiliate. Join now

Scrapes a Substack Notes page and exports engagement data

Substack notes scraper

by mohitagw15856 · MIT license · ★ 1,395 on GitHub · updated Sep 23

Substack notes scraper cover

Scrapes a Substack Notes page and exports engagement data to a formatted .xlsx file. Use when asked to download, analyse, or export Substack Notes performance data including likes, comments, and restacks.

---
name: substack-notes-scraper
description: "Scrapes a Substack Notes page and exports engagement data to a formatted .xlsx file. Use when asked to download, analyse, or export Substack Notes performance data including likes, comments, and restacks. Produces a formatted spreadsheet with conditional formatting, summary stats, and per-note engagement metrics."
---

# Substack Notes Scraper

Substack has no public API for Notes analytics. You can't see likes, comments, and restacks in one place without scrolling through your feed manually. This skill scrapes the rendered Notes page, filters to only your original content, and exports everything to a spreadsheet you can actually analyze.

> Credit: Originally created by a Substack newsletter author — adapted and extended for this library.

---

## Required Inputs

| Input | Format | Example |
|---|---|---|
| Notes URL | Full URL to the Notes tab | `https://substack.com/@handle/notes` |

Overview

Substack has no public API for Notes analytics. You can't see likes, comments, and restacks in one place without scrolling through your feed manually. This skill scrapes the rendered Notes page, filters to only your original content, and exports everything to a spreadsheet you can actually analyze.

Manual install (npx, ZIP)
Claude Codenpx skills add mohitagw15856/pm-claude-skills --skill substack-notes-scraper -g -a claude-code
Claude Code (manual)mkdir -p ~/.claude/skills && curl -sL https://codeload.github.com/mohitagw15856/pm-claude-skills/tar.gz/f6ca79348c55 \ | tar -xz -C ~/.claude/skills --strip-components=2 pm-claude-skills-f6ca79348c55/skills/substack-notes-scraper
Windows (PowerShell)New-Item -ItemType Directory -Force "$HOME\.claude\skills" | Out-Null; Invoke-WebRequest "https://m.agentalley.io/zip/312251c4d593f2a2f3f7/substack-notes-scraper.zip" -OutFile "$env:TEMP\substack-notes-scraper.zip"; Expand-Archive "$env:TEMP\substack-notes-scraper.zip" -DestinationPath "$HOME\.claude\skills" -Force
Claude.ai / desktopDownload the ZIP and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md7.3 KB
Read the files here
mohitagw15856/f6ca7931 file
SKILL.md
Show the full text185 lines

Substack Notes Scraper

Substack has no public API for Notes analytics. You can't see likes, comments, and restacks in one place without scrolling through your feed manually. This skill scrapes the rendered Notes page, filters to only your original content, and exports everything to a spreadsheet you can actually analyze.

Credit: Originally created by a Substack newsletter author — adapted and extended for this library.


Required Inputs

Input Format Example
Notes URL Full URL to the Notes tab https://substack.com/@handle/notes
Author handle or name Exact handle or display name @handle or Jane Smith
Date range Plain English or explicit range last 30 days or Jan 2026 – Mar 2026

Claude will ask for these if not provided upfront.


Output Structure

File
substack-notes-[handle]-[YYYY-MM-DD].xlsx
Sheet: "Notes Data"
Column Description
Date Publication date (YYYY-MM-DD)
Text Preview First 200 characters of the note
Full Text Complete note text
Likes Like count at time of scrape
Comments Comment count
Restacks Restack count
Total Engagement Likes + Comments + Restacks
Link Direct URL to the note
Note Type original or restack

Formatting applied:

  • Row 1: frozen header row
  • Auto-filter enabled on all columns
  • Top 20% by Likes column: highlighted yellow (#FFF2CC)
  • Column widths: auto-fit to content, min 12, max 60
Sheet: "Summary"
Scrape Date:         [YYYY-MM-DD HH:MM UTC]
Author:              [handle]
Date Range:          [start] – [end]
Total Notes:         [n]
Original Notes:      [n]
Restacks Filtered:   [n]

Avg Likes:           [n.n]
Avg Comments:        [n.n]
Avg Restacks:        [n.n]
Avg Total Eng:       [n.n]

Best Note (Likes):   [date] — [first 80 chars] — [n] likes
Best Note (Eng):     [date] — [first 80 chars] — [n] total engagement

Instructions for Claude

Step 1: Validate inputs

Confirm the three required inputs are present. If any are missing, ask before proceeding. Parse the date range into a concrete start date and end date (convert relative ranges like "last 30 days" to explicit dates using today's date).

Step 2: Fetch the Notes page

Use WebFetch to load the Notes URL. Substack Notes pages are JavaScript-rendered — request the full rendered HTML. If WebFetch returns a skeleton page without note content, note this in your response and ask the user to paste the page HTML manually or confirm browser access is available.

Step 3: Paginate through all notes in the date window

Substack Notes load incrementally. Repeat fetching or scrolling until either:

  • A note's date falls outside the target date range (stop loading more), or
  • No new content loads on the next request.

Rate-limit: wait 2 seconds between each paginated request. Do not hammer the endpoint.

Step 4: Parse each note

For every note element found on the page, extract:

  • Date: the timestamp on the note (convert to YYYY-MM-DD)
  • Author: the display name or handle shown on the note
  • Full text: complete body text, stripping HTML tags
  • Text preview: first 200 characters of full text
  • Likes count: the number shown on the like/heart counter
  • Comments count: the number shown on the comment counter
  • Restacks count: the number shown on the restack counter
  • Link: the direct permalink to the note
  • Note type: original if the author matches the specified author; restack if it belongs to someone else
Step 5: Filter

Keep ALL rows in the data (restacks included as rows with Note Type = restack). The Summary sheet stats should count only original notes. Mark restacks clearly so the user can filter them out themselves in Excel if preferred.

Apply date filter: exclude any note outside the specified date range.

Step 6: Calculate Total Engagement

For each row: Total Engagement = Likes + Comments + Restacks

Step 7: Identify top 20% by Likes

Sort original notes by Likes descending. Mark the top 20% (round up) for conditional formatting. These rows will be highlighted yellow in the output file.

Step 8: Build the .xlsx file

Use Python with openpyxl to generate the file. Structure:

# Required libraries
import openpyxl
from openpyxl.styles import PatternFill, Font, Alignment
from openpyxl.utils import get_column_letter
from datetime import datetime

# Sheet 1: Notes Data
# - Write header row, bold, freeze row 1
# - Write all data rows
# - Apply auto-filter: ws.auto_filter.ref = ws.dimensions
# - Apply yellow fill to top-20% rows by likes
# - Auto-size columns (iterate cells to find max length)

# Sheet 2: Summary
# - Write summary stats as key-value pairs, no table format

Name the file substack-notes-[handle]-[YYYY-MM-DD].xlsx using today's date.

Step 9: Report back

After generating the file, report:

  • File path
  • Total notes found, original vs. restacks
  • Date range actually covered
  • Top 3 notes by total engagement (date + preview + stats)
  • Any notes or warnings (e.g., page didn't fully load, some dates were ambiguous)

Quality Checks

  • All three required inputs were confirmed before starting
  • Rate limiting honored: 2-second delay between paginated requests
  • Author filter applied correctly — restacks are included as rows but flagged, not silently dropped
  • Date range filter applied — no notes outside the window appear in the data
  • Total Engagement column is Likes + Comments + Restacks (not hardcoded)
  • Top 20% highlight is based on the actual data distribution, not a fixed threshold
  • Header row is frozen and auto-filter is active
  • Summary sheet stats reference only original notes, not restacks
  • File is named with the author handle and today's date
  • If the page failed to load properly, the user was told — not silently given an empty file

Anti-Patterns

  • Do not proceed without a valid Substack handle or profile URL — scraping without a specific target cannot be completed
  • Do not ignore rate-limit responses from Substack — implement backoff and reduce request frequency before retrying
  • Do not export data without conditional formatting and summary stats — raw data without visualisation is not the expected output
  • Do not attempt to access private or subscriber-only notes — this skill is for public Notes content only
  • Do not produce output without a clear date range filter — undated exports make trend analysis impossible

Example Trigger Phrases

  • "Scrape my Substack Notes and export to Excel — my handle is @handle, last 60 days"
  • "Use the substack-notes-scraper skill on https://substack.com/@handle/notes for Q1 2026"
  • "Pull my notes engagement data into a spreadsheet"
  • "Export my Substack Notes stats with likes and restacks — author: Jane Smith, Jan–Mar 2026"
  • "Run the Substack scraper on my notes page and show me which posts performed best"
1---
2name: substack-notes-scraper
3description: "Scrapes a Substack Notes page and exports engagement data to a formatted .xlsx file. Use when asked to download, analyse, or export Substack Notes performance data including likes, comments, and restacks. Produces a formatted spreadsheet with conditional formatting, summary stats, and per-note engagement metrics."
4---
5 
6# Substack Notes Scraper
7 
8Substack has no public API for Notes analytics. You can't see likes, comments, and restacks in one place without scrolling through your feed manually. This skill scrapes the rendered Notes page, filters to only your original content, and exports everything to a spreadsheet you can actually analyze.
9 
10> Credit: Originally created by a Substack newsletter author — adapted and extended for this library.
11 
12---
13 
14## Required Inputs
15 
16| Input | Format | Example |
17|---|---|---|
18| Notes URL | Full URL to the Notes tab | `https://substack.com/@handle/notes` |
19| Author handle or name | Exact handle or display name | `@handle` or `Jane Smith` |
20| Date range | Plain English or explicit range | `last 30 days` or `Jan 2026 – Mar 2026` |
21 
22Claude will ask for these if not provided upfront.
23 
24---
25 
26## Output Structure
27 
28### File
29 
30```
31substack-notes-[handle]-[YYYY-MM-DD].xlsx
32```
33 
34### Sheet: "Notes Data"
35 
36| Column | Description |
37|---|---|
38| Date | Publication date (YYYY-MM-DD) |
39| Text Preview | First 200 characters of the note |
40| Full Text | Complete note text |
41| Likes | Like count at time of scrape |
42| Comments | Comment count |
43| Restacks | Restack count |
44| Total Engagement | Likes + Comments + Restacks |
45| Link | Direct URL to the note |
46| Note Type | `original` or `restack` |
47 
48**Formatting applied:**
49- Row 1: frozen header row
50- Auto-filter enabled on all columns
51- Top 20% by Likes column: highlighted yellow (`#FFF2CC`)
52- Column widths: auto-fit to content, min 12, max 60
53 
54### Sheet: "Summary"
55 
56```
57Scrape Date: [YYYY-MM-DD HH:MM UTC]
58Author: [handle]
59Date Range: [start] – [end]
60Total Notes: [n]
61Original Notes: [n]
62Restacks Filtered: [n]
63 
64Avg Likes: [n.n]
65Avg Comments: [n.n]
66Avg Restacks: [n.n]
67Avg Total Eng: [n.n]
68 
69Best Note (Likes): [date] — [first 80 chars] — [n] likes
70Best Note (Eng): [date] — [first 80 chars] — [n] total engagement
71```
72 
73---
74 
75## Instructions for Claude
76 
77### Step 1: Validate inputs
78 
79Confirm the three required inputs are present. If any are missing, ask before proceeding. Parse the date range into a concrete start date and end date (convert relative ranges like "last 30 days" to explicit dates using today's date).
80 
81### Step 2: Fetch the Notes page
82 
83Use `WebFetch` to load the Notes URL. Substack Notes pages are JavaScript-rendered — request the full rendered HTML. If WebFetch returns a skeleton page without note content, note this in your response and ask the user to paste the page HTML manually or confirm browser access is available.
84 
85### Step 3: Paginate through all notes in the date window
86 
87Substack Notes load incrementally. Repeat fetching or scrolling until either:
88- A note's date falls outside the target date range (stop loading more), or
89- No new content loads on the next request.
90 
91Rate-limit: wait 2 seconds between each paginated request. Do not hammer the endpoint.
92 
93### Step 4: Parse each note
94 
95For every note element found on the page, extract:
96- **Date**: the timestamp on the note (convert to YYYY-MM-DD)
97- **Author**: the display name or handle shown on the note
98- **Full text**: complete body text, stripping HTML tags
99- **Text preview**: first 200 characters of full text
100- **Likes count**: the number shown on the like/heart counter
101- **Comments count**: the number shown on the comment counter
102- **Restacks count**: the number shown on the restack counter
103- **Link**: the direct permalink to the note
104- **Note type**: `original` if the author matches the specified author; `restack` if it belongs to someone else
105 
106### Step 5: Filter
107 
108Keep ALL rows in the data (restacks included as rows with `Note Type = restack`). The Summary sheet stats should count only `original` notes. Mark restacks clearly so the user can filter them out themselves in Excel if preferred.
109 
110Apply date filter: exclude any note outside the specified date range.
111 
112### Step 6: Calculate Total Engagement
113 
114For each row: `Total Engagement = Likes + Comments + Restacks`
115 
116### Step 7: Identify top 20% by Likes
117 
118Sort original notes by Likes descending. Mark the top 20% (round up) for conditional formatting. These rows will be highlighted yellow in the output file.
119 
120### Step 8: Build the .xlsx file
121 
122Use Python with `openpyxl` to generate the file. Structure:
123 
124```python
125# Required libraries
126import openpyxl
127from openpyxl.styles import PatternFill, Font, Alignment
128from openpyxl.utils import get_column_letter
129from datetime import datetime
130 
131# Sheet 1: Notes Data
132# - Write header row, bold, freeze row 1
133# - Write all data rows
134# - Apply auto-filter: ws.auto_filter.ref = ws.dimensions
135# - Apply yellow fill to top-20% rows by likes
136# - Auto-size columns (iterate cells to find max length)
137 
138# Sheet 2: Summary
139# - Write summary stats as key-value pairs, no table format
140```
141 
142Name the file `substack-notes-[handle]-[YYYY-MM-DD].xlsx` using today's date.
143 
144### Step 9: Report back
145 
146After generating the file, report:
147- File path
148- Total notes found, original vs. restacks
149- Date range actually covered
150- Top 3 notes by total engagement (date + preview + stats)
151- Any notes or warnings (e.g., page didn't fully load, some dates were ambiguous)
152 
153---
154 
155## Quality Checks
156 
157- [ ] All three required inputs were confirmed before starting
158- [ ] Rate limiting honored: 2-second delay between paginated requests
159- [ ] Author filter applied correctly — restacks are included as rows but flagged, not silently dropped
160- [ ] Date range filter applied — no notes outside the window appear in the data
161- [ ] Total Engagement column is Likes + Comments + Restacks (not hardcoded)
162- [ ] Top 20% highlight is based on the actual data distribution, not a fixed threshold
163- [ ] Header row is frozen and auto-filter is active
164- [ ] Summary sheet stats reference only `original` notes, not restacks
165- [ ] File is named with the author handle and today's date
166- [ ] If the page failed to load properly, the user was told — not silently given an empty file
167 
168---
169 
170## Anti-Patterns
171 
172- [ ] Do not proceed without a valid Substack handle or profile URL — scraping without a specific target cannot be completed
173- [ ] Do not ignore rate-limit responses from Substack — implement backoff and reduce request frequency before retrying
174- [ ] Do not export data without conditional formatting and summary stats — raw data without visualisation is not the expected output
175- [ ] Do not attempt to access private or subscriber-only notes — this skill is for public Notes content only
176- [ ] Do not produce output without a clear date range filter — undated exports make trend analysis impossible
177 
178## Example Trigger Phrases
179 
180- "Scrape my Substack Notes and export to Excel — my handle is @handle, last 60 days"
181- "Use the substack-notes-scraper skill on https://substack.com/@handle/notes for Q1 2026"
182- "Pull my notes engagement data into a spreadsheet"
183- "Export my Substack Notes stats with likes and restacks — author: Jane Smith, Jan–Mar 2026"
184- "Run the Substack scraper on my notes page and show me which posts performed best"
185 
View all files on GitHub →

Details

Updated
Sep 23, 2026
License
MIT
Stars on the repo
★ 1,395
Checked
Source
mohitagw15856/pm-claude-skills ↗
Creator
mohitagw15856 · 193 listings
View creator

Made with substack-notes-scraper

Substack notes scraper — Galaxy 3D — fly through all 1170 skills as a glowing constellation you orbit and click into (from the mohitagw15856/pm-claude-skills README)
Substack notes scraper — Galaxy 3D — fly through all 1170 skills as a glowing constellation you orbit and click into (from the mohitagw15856/pm-claude-skills README)

by mohitagw15856

Substack notes scraper — PM Skills Wrapped — your practice turned into a shareable, Spotify-Wrapped-style story (from the mohitagw15856/pm-claude-skills README)
Substack notes scraper — PM Skills Wrapped — your practice turned into a shareable, Spotify-Wrapped-style story (from the mohitagw15856/pm-claude-skills README)

by mohitagw15856

Similar skills

See all →
SkillDraft written long-form content in your voicetimscheuerai/content-vault · by timscheueraiDraft written long-form content (newsletter issue, blog post, Substack issue) in your voice. 800-2000 words, structured intro + body + CTA, paragraph-by-paragraph not list-by-list. Pulls voice from /linkedin-copywriter's corpus (same author, same register · longer arc). Runs the brand-doc skill checklist before output. Logs the row in the Notion Content DB and (for newsletters) drafts a separate punchy subject line. Use when asked to "write a newsletter", "draft a blog post", "long-form X", "Substack issue about Y", "weekly newsletter", or "/long-form". For spoken video scripts (YouTube longs / shorts) use /youtube-script instead · the cadence is fundamentally different.★ 37 GitHub starsPromptA comprehensive producer-assistant prompt for podcastersMaster Podcast Producer & Sonic Storytellerf/prompts.chat · by Sercan SolmazA comprehensive producer-assistant prompt for podcasters that goes beyond standard question lists. It designs the episode's sound design (sonic cues), narrative arc, and opening hook to ensure maximum listener retention.New listingMCPPodcast content analysis specialistPodcast content analyzerdavila7/claude-code-templates · by davila7Podcast content analysis specialist. Use PROACTIVELY for identifying viral moments, creating chapter markers, extracting SEO keywords, and scoring engagement potential from transcripts.★ 32.3k GitHub starsMCPPodcast editing and post-production specialistPodcast editordavila7/claude-code-templates · by davila7Podcast editing and post-production specialist. Use PROACTIVELY for audio editing guidance, show notes creation, chapter markers, timestamp management, and podcast publishing workflows.★ 32.3k GitHub starsMCPPodcast metadata and show notes specialistPodcast metadata specialistdavila7/claude-code-templates · by davila7Podcast metadata and show notes specialist. Use PROACTIVELY for SEO-optimized titles, chapter markers, platform-specific descriptions, and comprehensive publishing metadata.★ 32.3k GitHub starsMCPAudio transcription specialistPodcast transcriberdavila7/claude-code-templates · by davila7Audio transcription specialist. Use PROACTIVELY for extracting accurate transcripts from media files with speaker identification, timestamps, and structured output.★ 32.3k GitHub stars

More from mohitagw15856

SkillDesign a 360-degree feedback survey or write a structured360-Degree Feedback Template Skillmohitagw15856/pm-claude-skills · by mohitagw15856Design a 360-degree feedback survey or write a structured 360 feedback report. Use when asked to build a 360 feedback process, write 360 feedback for a colleague, design a feedback survey, or produce a feedback report. Produces either a complete survey instrument with rating scales and open-ended questions, or a structured narrative feedback report with themes, strengths, and development areas.★ 1.4k GitHub starsSkillDesign statistically rigorous A/B tests for product featuresA/B Test Planner Skillmohitagw15856/pm-claude-skills · by mohitagw15856Design statistically rigorous A/B tests for product features, UI changes, onboarding flows, and pricing experiments. Use when asked to set up an experiment, design an A/B test, calculate sample size, or interpret test results. Produces a complete test plan with hypothesis, variant definitions, sample size, duration estimate, guardrail metrics, and a results interpretation guide.★ 1.4k GitHub starsSkillGenerate a WCAG 2.2 accessibility audit checklistAccessibility Audit Skillmohitagw15856/pm-claude-skills · by mohitagw15856Generate a WCAG 2.2 accessibility audit checklist and remediation suggestions for any UI or design. Use when asked to audit for accessibility, check WCAG compliance, review a design for a11y issues, or create an accessibility remediation plan. Produces a prioritised checklist with pass/fail assessments and specific fixes.★ 1.4k GitHub starsSkillBuild a structured account plan for any key customerAccount Plan Skillmohitagw15856/pm-claude-skills · by mohitagw15856Build a structured account plan for any key customer or target account. Use when asked to create an account plan, key account strategy, strategic account review, or territory plan. Produces a complete account plan with relationship map, growth opportunities, risks, and 90-day action plan.★ 1.4k GitHub starsSkillOptimize an article for Answer Engine Optimization so AIAEO Optimizer Skillmohitagw15856/pm-claude-skills · by mohitagw15856Optimize an article for Answer Engine Optimization (AEO) so AI engines like ChatGPT, Perplexity, and Claude can extract, quote, and cite it. Use when asked to AEO-optimize, make content AI-readable, improve AI citation chances, or adapt an article for answer engines. Produces an AEO-optimised rewrite with question headings, 50–80 word answer capsules, a paragraph-length audit, and flagged trust signals.★ 1.4k GitHub starsSkillConduct a structured ethical review of an AI or ML featureAI Ethics Review Skillmohitagw15856/pm-claude-skills · by mohitagw15856Conduct a structured ethical review of an AI or ML feature, model, or product. Use when preparing to deploy an AI system, assessing algorithmic risk, auditing a model for bias, or producing a responsible AI impact assessment. Produces a structured ethics review covering fairness, transparency, privacy, safety, accountability, and societal impact with a risk tier score, pre-deployment checklist, and prioritised mitigations.★ 1.4k GitHub stars