Substack Recommendations avatar

Substack Recommendations

Pricing

from $0.01 / 1,000 recommendations

Go to Apify Store
Substack 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é

Maxime Dupré

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

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

🧾 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

  1. Add one or more public publication homepages or direct /recommendations URLs.
  2. Set maxHops to 0 for the submitted pages only, or to 1, 2, or 3 for bounded breadth-first follow-on levels.
  3. Leave maxItems empty 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.
  4. Set qualifyTargets to true when you also want a separate public assessment for recommendation targets.
  5. 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

FieldTypeWhat it does
startUrlsarray of objectsThe public publication pages used as mapping seeds. At least one is required.
startUrls[].urlstringA public publication homepage or direct recommendation-page URL.
maxHopsintegerThe number of recommendation levels to follow after the submitted pages. Use 0 for the submitted pages only. Values from 0 to 3 are allowed.
maxItemsintegerAn 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.
qualifyTargetsbooleanAdds 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

FieldTypeWhat it does
relationshipIdstringA stable ID for the directed recommendation relationship.
sourcePublicationobjectGroups the public publication that made the recommendation.
sourcePublication.namestringThe public name of the source publication.
sourcePublication.urlstringThe public URL of the source publication.
recommendedPublicationobjectGroups the public publication named by the recommendation.
recommendedPublication.namestringThe public name of the recommended publication.
recommendedPublication.urlstringThe public URL of the recommended publication.
recommendedPublication.authorstringThe public author name, when shown.
recommendedPublication.descriptionstringThe public description of the recommended publication, when shown.
recommendationobjectGroups the public recommendation text and attribution, when shown.
recommendation.blurbstringThe public text that describes the recommendation.
recommendation.attributionstringThe public name or text that attributes the recommendation.
provenanceobjectGroups the public recommendation page and collection time.
provenance.recommendationPageUrlstringThe public page where this recommendation was found.
provenance.collectedAtstringThe time when this relationship was collected.
discoveryobjectGroups the submitted seed and follow-on depth that led to the relationship.
discovery.seedUrlstringThe submitted public URL that led to this relationship.
discovery.hopintegerThe 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

FieldTypeWhat it does
relationshipIdstringA stable ID for the directed recommendation relationship.
sourcePublicationobjectGroups the public publication that made the recommendation.
sourcePublication.namestringThe public name of the source publication.
sourcePublication.urlstringThe public URL of the source publication.
recommendedPublicationobjectGroups the public publication named by the recommendation.
recommendedPublication.namestringThe public name of the recommended publication.
recommendedPublication.urlstringThe public URL of the recommended publication.
recommendedPublication.authorstringThe public author name, when shown.
recommendedPublication.descriptionstringThe public description of the recommended publication, when shown.
recommendationobjectGroups the public recommendation text and attribution, when shown.
recommendation.blurbstringThe public text that describes the recommendation.
recommendation.attributionstringThe public name or text that attributes the recommendation.
provenanceobjectGroups the public recommendation page and collection time.
provenance.recommendationPageUrlstringThe public page where this recommendation was found.
provenance.collectedAtstringThe time when this relationship was collected.
discoveryobjectGroups the submitted seed and follow-on depth that led to the relationship.
discovery.seedUrlstringThe submitted public URL that led to this relationship.
discovery.hopintegerThe number of follow-on levels from the submitted seed.
qualificationobjectGroups public signals about the recommended publication when qualification is requested.
qualification.topicsarray of stringsPublic topics covered by the publication.
qualification.headlinePatternsarray of stringsPatterns seen in recent public post headlines.
qualification.audienceLanestringThe public audience group the publication appears to serve.
qualification.editorialPromisestringThe main promise the publication makes to readers.
qualification.recentPublicPostsobjectGroups coverage and timing for recent public posts.
qualification.recentPublicPosts.postCountintegerThe number of public posts reviewed.
qualification.recentPublicPosts.coverageWindowDaysintegerThe number of days covered by the public post review.
qualification.recentPublicPosts.estimatedCadencestringThe estimated public posting cadence.
qualification.recentPublicPosts.lastPublicPostAtstringThe time of the latest public post reviewed.
qualification.paywallPosturestringHow much of the recent publication content is public.
qualification.audienceSizeSignalstringThe public audience size signal, when shown.
qualification.sponsorFitobjectGroups public signals about sponsor fit and available inventory.
qualification.sponsorFit.fitSignalsarray of stringsPublic facts that support or limit sponsor fit.
qualification.sponsorFit.inventorySignalsarray of stringsPublic signs of sponsor or advertising inventory.
qualification.sponsorFit.sponsorLanguagearray of stringsPublic words or phrases about sponsors or advertising.
qualification.sponsorFit.sponsorNamesarray of stringsPublic sponsor or advertiser names that were found.
qualification.sponsorFit.fitCategoriesarray of stringsCategories that match the publication audience or topic.
qualification.sponsorFit.commercialReadinessstringThe public evidence level for commercial readiness.
qualification.evidenceQualitystringThe quality of the public evidence used for the assessment.
qualification.confidencenumberConfidence in the public qualification assessment, from 0 to 1.
qualification.disqualifiersarray of stringsPublic facts that may rule out a sponsor fit.
qualification.missingDataarray of stringsPublic data that was not available for the assessment.
qualification.nextActionstringThe 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 🫡

Made with ❤️ by Maxime Dupré