Substack Recommendations
Pricing
from $0.01 / 1,000 recommendations
Substack Recommendations
Map public Substack recommendations from publication URLs. Get directed relationships with publication names, URLs, public context, and source pages in a dataset. Optionally assess recommended newsletters with public signals.
Pricing
from $0.01 / 1,000 recommendations
Rating
0.0
(0)
Developer
Maxime Dupré
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
🕸️ Map Substack newsletter recommendations
Newsletter researchers, media buyers, partnership teams, and creator agencies can use this Actor to map public Substack recommendations from the publication URLs they provide. It returns one directed relationship per saved recommendation with publication names, URLs, public context, source-page provenance, and collection time. This gives you a useful starting point for comparing newsletter networks and reviewing adjacent publications.
Request a separate public qualification pass when you need topics, headline patterns, posting timing, paywall posture, audience signals, sponsor-fit signals, evidence quality, and a recommended next action.
Use cases
- Compare public links around leading newsletters with Most Popular Substack Newsletters.
- Review public recommendation pages through Substack Examples before you map a network.
- Build a seed list with Find Substack Newsletters for a newsletter research project.
- Follow adjacent publications with Substack Newsletter Recommendations from a known seed.
- Map public newsletter links with Substack Recommendations from submitted pages.
🧾 See relationship rows and public newsletter signals
Each dataset row represents one public recommendation from a source publication to a recommended publication. Rows can include names, URLs, author and description context, public recommendation text, source-page provenance, collection time, and the discovery hop.
When qualifyTargets is enabled, a row can also include public topics, headline patterns, posting timing, paywall posture, audience signals, sponsor-fit signals, evidence quality, missing data, and a recommended next action. Optional public fields stay absent when the source does not show them.
🚦 Follow public recommendation paths at a chosen depth
- Add one or more public publication homepages or direct
/recommendationsURLs. - Set
maxHopsto0for the submitted pages only, or to1,2, or3for bounded breadth-first follow-on levels. - Leave
maxItemsempty to return all available results until the source is exhausted within the selected depth. Set it when you want to stop after a chosen number of saved relationships. - Set
qualifyTargetstotruewhen you also want a separate public assessment for recommendation targets. - Start the run and review the relationships in the Apify dataset.
The Actor reads reachable public pages without a Substack account or API key. It does not collect private, paid, subscriber-only, or inbound recommendation data. It also does not discover publications by keyword, so your submitted URLs define the starting set.
⚙️ Input
Use public Substack publication homepages, direct recommendation pages, or Substack-powered custom publication domains.
Input fields
| Field | Type | What it does |
|---|---|---|
startUrls | array of objects | The public publication pages used as mapping seeds. At least one is required. |
startUrls[].url | string | A public publication homepage or direct recommendation-page URL. |
maxHops | integer | The number of recommendation levels to follow after the submitted pages. Use 0 for the submitted pages only. Values from 0 to 3 are allowed. |
maxItems | integer | An optional stop for saved relationships. Leave it empty to return all available results until the source is exhausted within the selected depth. This field has no schema upper bound. |
qualifyTargets | boolean | Adds a separate public qualification pass for each recommendation target when set to true. It can return public topics, headline patterns, cadence, audience signals, paywall posture, and sponsor-fit signals. |
Default input
This is the complete public input from a successful current-beta default-input run:
{"startUrls": [{"url": "https://downtime.substack.com"}],"maxHops": 0,"maxItems": 10,"qualifyTargets": false}
🧾 Output
The dataset contains relationship rows. A qualified run uses the same relationship fields and adds a qualification object when a public assessment is requested and returned.
Relationship rows
| Field | Type | What it does |
|---|---|---|
relationshipId | string | A stable ID for the directed recommendation relationship. |
sourcePublication | object | Groups the public publication that made the recommendation. |
sourcePublication.name | string | The public name of the source publication. |
sourcePublication.url | string | The public URL of the source publication. |
recommendedPublication | object | Groups the public publication named by the recommendation. |
recommendedPublication.name | string | The public name of the recommended publication. |
recommendedPublication.url | string | The public URL of the recommended publication. |
recommendedPublication.author | string | The public author name, when shown. |
recommendedPublication.description | string | The public description of the recommended publication, when shown. |
recommendation | object | Groups the public recommendation text and attribution, when shown. |
recommendation.blurb | string | The public text that describes the recommendation. |
recommendation.attribution | string | The public name or text that attributes the recommendation. |
provenance | object | Groups the public recommendation page and collection time. |
provenance.recommendationPageUrl | string | The public page where this recommendation was found. |
provenance.collectedAt | string | The time when this relationship was collected. |
discovery | object | Groups the submitted seed and follow-on depth that led to the relationship. |
discovery.seedUrl | string | The submitted public URL that led to this relationship. |
discovery.hop | integer | The number of follow-on levels from the submitted seed. |
Example relationship row
This complete row is from a successful current-beta run:
{"relationshipId": "c2dca93a4ca8ce69ddd64065","sourcePublication": {"name": "The Common Reader","url": "https://www.commonreader.co.uk/"},"recommendedPublication": {"name": "Life and Letters","url": "https://lifeandletters.substack.com/","author": "Julianne Werlin","description": "Reflections on Literature in Demographic History"},"recommendation": {"blurb": "One of the best literary Substacks. Erudite humanism informed by social science. I am a fan.","attribution": "Henry Oliver"},"provenance": {"recommendationPageUrl": "https://www.commonreader.co.uk/recommendations","collectedAt": "2026-08-22T14:21:30.558Z"},"discovery": {"seedUrl": "https://www.henrikkarlsson.xyz/","hop": 2}}
Qualified relationship rows
| Field | Type | What it does |
|---|---|---|
relationshipId | string | A stable ID for the directed recommendation relationship. |
sourcePublication | object | Groups the public publication that made the recommendation. |
sourcePublication.name | string | The public name of the source publication. |
sourcePublication.url | string | The public URL of the source publication. |
recommendedPublication | object | Groups the public publication named by the recommendation. |
recommendedPublication.name | string | The public name of the recommended publication. |
recommendedPublication.url | string | The public URL of the recommended publication. |
recommendedPublication.author | string | The public author name, when shown. |
recommendedPublication.description | string | The public description of the recommended publication, when shown. |
recommendation | object | Groups the public recommendation text and attribution, when shown. |
recommendation.blurb | string | The public text that describes the recommendation. |
recommendation.attribution | string | The public name or text that attributes the recommendation. |
provenance | object | Groups the public recommendation page and collection time. |
provenance.recommendationPageUrl | string | The public page where this recommendation was found. |
provenance.collectedAt | string | The time when this relationship was collected. |
discovery | object | Groups the submitted seed and follow-on depth that led to the relationship. |
discovery.seedUrl | string | The submitted public URL that led to this relationship. |
discovery.hop | integer | The number of follow-on levels from the submitted seed. |
qualification | object | Groups public signals about the recommended publication when qualification is requested. |
qualification.topics | array of strings | Public topics covered by the publication. |
qualification.headlinePatterns | array of strings | Patterns seen in recent public post headlines. |
qualification.audienceLane | string | The public audience group the publication appears to serve. |
qualification.editorialPromise | string | The main promise the publication makes to readers. |
qualification.recentPublicPosts | object | Groups coverage and timing for recent public posts. |
qualification.recentPublicPosts.postCount | integer | The number of public posts reviewed. |
qualification.recentPublicPosts.coverageWindowDays | integer | The number of days covered by the public post review. |
qualification.recentPublicPosts.estimatedCadence | string | The estimated public posting cadence. |
qualification.recentPublicPosts.lastPublicPostAt | string | The time of the latest public post reviewed. |
qualification.paywallPosture | string | How much of the recent publication content is public. |
qualification.audienceSizeSignal | string | The public audience size signal, when shown. |
qualification.sponsorFit | object | Groups public signals about sponsor fit and available inventory. |
qualification.sponsorFit.fitSignals | array of strings | Public facts that support or limit sponsor fit. |
qualification.sponsorFit.inventorySignals | array of strings | Public signs of sponsor or advertising inventory. |
qualification.sponsorFit.sponsorLanguage | array of strings | Public words or phrases about sponsors or advertising. |
qualification.sponsorFit.sponsorNames | array of strings | Public sponsor or advertiser names that were found. |
qualification.sponsorFit.fitCategories | array of strings | Categories that match the publication audience or topic. |
qualification.sponsorFit.commercialReadiness | string | The public evidence level for commercial readiness. |
qualification.evidenceQuality | string | The quality of the public evidence used for the assessment. |
qualification.confidence | number | Confidence in the public qualification assessment, from 0 to 1. |
qualification.disqualifiers | array of strings | Public facts that may rule out a sponsor fit. |
qualification.missingData | array of strings | Public data that was not available for the assessment. |
qualification.nextAction | string | The next step suggested by the public evidence. |
Example qualified relationship row
This complete qualified row is from a successful current-beta run:
{"relationshipId": "d8e96d536a41cb961e708633","sourcePublication": {"name": "On Substack","url": "https://on.substack.com/"},"recommendedPublication": {"name": "The Substack Post","url": "https://post.substack.com/","author": "Substack","description": "A guide to the creators and stories shaping culture"},"provenance": {"recommendationPageUrl": "https://on.substack.com/recommendations","collectedAt": "2026-08-22T14:02:22.810Z"},"discovery": {"seedUrl": "https://on.substack.com/","hop": 0},"qualification": {"topics": ["The Weekender","Unstacked","Someone on Film"],"headlinePatterns": ["question-led headlines","headlines with a descriptive qualifier","product and technology topic framing"],"audienceLane": "A guide to the creators and stories shaping culture","editorialPromise": "A guide to the creators and stories shaping culture","recentPublicPosts": {"postCount": 12,"coverageWindowDays": 49,"estimatedCadence": "about weekly","lastPublicPostAt": "2026-08-22T13:03:05.947Z"},"paywallPosture": "mostly_public","sponsorFit": {"fitSignals": ["A guide to the creators and stories shaping culture","Recent public archive tag: The Weekender.","Recent public archive tag: Unstacked."],"inventorySignals": [],"sponsorLanguage": ["partner","advertising"],"sponsorNames": [],"fitCategories": ["The Weekender","Unstacked","Someone on Film"],"commercialReadiness": "promising"},"evidenceQuality": "high","confidence": 0.89,"disqualifiers": [],"missingData": ["No public audience size signal was shown.","No public sponsorship rate card or inventory terms were observed in the sampled pages."],"nextAction": "Review the missing public data before outreach."}}
💳 Pricing
Pricing is pay per event. Recommendation costs $0.00001 for each saved public recommendation relationship. When qualifyTargets is enabled, Newsletter assessment costs $0.009 for each public assessment saved for a requested recommendation target. The total depends on the number of saved events.
🔌 Integrations
The output is an Apify dataset. Use the dataset view or its API link to review the rows, export them, or pass them to your workflow.
Video guide
❓ FAQ
What happens when a public page has no visible recommendations?
The dataset has no relationship row for that page. The Actor does not invent a target or fill missing public fields.
Can I use a custom publication domain?
Yes. Use a Substack-powered custom publication homepage or its recommendation page as a seed.
Does the Actor read private or subscriber-only recommendations?
No. It uses publicly visible recommendation pages and cards. Private, paid, subscriber-only, and inbound recommendation data are outside the scope of this Actor.
Can I follow recommendations beyond the seed pages?
Yes. Set maxHops to 1, 2, or 3 for bounded breadth-first follow-on levels. Use 0 for seed pages only.
What does leaving maxItems empty do?
The Actor returns all available results until the source is exhausted within the selected depth. Set maxItems when you want to stop after a chosen number of saved relationships.
Why is a field missing from a relationship row?
Author, description, recommendation text, and attribution appear only when the public source displays them. Qualification fields appear when you request qualification and the public evidence supports them.
How can I compare two runs?
Use relationshipId to compare rows across snapshots. provenance and discovery also show the source page, collection time, submitted seed, and follow-on hop.
Can I discover newsletters by keyword?
No. Submit a list of public publication URLs. This Actor maps recommendations from those seeds, but it is not a keyword discovery tool.
Do I need a Substack account or API key?
No. The Actor reads reachable public pages without a Substack account or API key.
📝 Changelog
0.0: Initial release
🆘 Support
For issues, questions, or feature requests, file a ticket and I'll fix or implement it in less than 24h 🫡
🔗 Related Actors
- Substack Recommendations Network Scraper: compare a separate public recommendation graph for newsletter research.
- Substack Newsletter Sponsor Lead Analyzer: qualify recommended newsletters for public sponsor-fit and commercial signals.
- Substack Newsletter Scraper: add publication and recommendation graph context to broader newsletter research.
- Substack Scraper: Posts, Comments & Authors: collect post, comment, and author context around a recommendation network.
- Substack Leaderboard Scraper 📊: find ranked publications that can supply starting URLs for network mapping.
Made with ❤️ by Maxime Dupré