# Substack Public Mention Monitor

Monitor public Substack RSS articles for brand aliases and linked domains. Save short evidence, source dates and confirmed changes with explicit recent-feed coverage.

Canonical product page: https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/
Public Actor: https://apify.com/maydit/substack-public-mention-monitor

## Example input

```json
{
  "publicationUrls": [
    "https://www.lennysnewsletter.com"
  ],
  "maxResults": 3
}
```

## Ready-to-use input recipes

These are downloadable JSON configurations. They do not start runs or represent public Apify saved tasks. Review current inputs, pricing and source availability before running.

[Default input](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/input.json) · [Input schema](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/input-schema.json) · [Saved output capture](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/evidence.json)

### Recent product and growth articles

Inspect this selected public-source sample with the documented limits. Coverage is the publisher public RSS window and can contain previews. There is no global Substack search, full archive, paywall access, private-feed access or inferred sponsorship. An empty match set can be a legitimate result.

```json
{
  "publicationUrls": [
    "https://www.lennysnewsletter.com"
  ],
  "maxResults": 3
}
```

[Download JSON](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/examples/recipe-1.json) · [Example evidence](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/examples/recipe-1.evidence.json)

Historical successful run recorded 2026-11-03 UTC, with 3 saved rows. This does not establish current availability.

### OpenAI and ChatGPT in One Useful Thing

Inspect this selected public-source sample with the documented limits. Coverage is the publisher public RSS window and can contain previews. There is no global Substack search, full archive, paywall access, private-feed access or inferred sponsorship. An empty match set can be a legitimate result.

```json
{
  "publicationUrls": [
    "https://www.oneusefulthing.org"
  ],
  "keywords": [
    "OpenAI"
  ],
  "aliases": {
    "OpenAI": [
      "ChatGPT"
    ]
  },
  "maxResults": 3
}
```

[Download JSON](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/examples/recipe-2.json) · [Example evidence](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/examples/recipe-2.evidence.json)

Historical successful run recorded 2026-11-03 UTC, with 3 saved rows. This does not establish current availability.

### OpenAI links and mentions in Not Boring

Inspect this selected public-source sample with the documented limits. Coverage is the publisher public RSS window and can contain previews. There is no global Substack search, full archive, paywall access, private-feed access or inferred sponsorship. An empty match set can be a legitimate result.

```json
{
  "publicationUrls": [
    "https://www.notboring.co"
  ],
  "keywords": [
    "OpenAI"
  ],
  "outboundDomains": [
    "openai.com"
  ],
  "maxResults": 3
}
```

[Download JSON](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/examples/recipe-3.json) · [Example evidence](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/examples/recipe-3.evidence.json)

Historical successful run recorded 2026-11-03 UTC, with 3 saved rows. This does not establish current availability.

[All example inputs](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/examples/index.json)
## Choose this tool

Use this tool for a named list of public Substack publications when you need short evidence of brand aliases or links to selected domains. It is suited to PR research, content tracking and competitive newsletter reviews.

Useful output columns: `title`, `publicationTitle`, `publishedAt`, `mentionCount`, `outboundMatchCount`, `comparisonStatus`, `changedFields`, `url`.

## Practical workflow

Choose the publications you follow, add a brand and its aliases, and optionally identify outbound domains. Review the short matching evidence alongside the original article URL and publication date. Save the same feed scope for repeat runs and deliver reviewed rows through your own workflow. Keep mention evidence separate from any interpretation of endorsement or sponsorship.

## Check the fit

Coverage is the publisher public RSS window and can contain previews. There is no global Substack search, full archive, paywall access, private-feed access or inferred sponsorship. An empty match set can be a legitimate result.

## Real output sample

One selected row from a 2026-11-03 run. Selected original scalar fields from one actual saved observation; nested data and private artifact links are omitted.

Run: kDVHYNgz5XOnBsYv0. Summary status: ok. Incomplete: false.

Dated bounded release evidence for this exact input and build. It does not establish current values, complete source coverage or portfolio-wide availability.

```json
{
  "recordId": "9f9d558c8179b71827dd43d42f1f63ae6327a5c912ce7fae618ecbfa544fe350",
  "title": "🎙️ How I AI: Grok vs. Dot vs. Muse vs. Duet + How Figma’s PMs actually use AI every day",
  "publicationTitle": "Lenny's Newsletter",
  "publishedAt": "2026-11-02T16:02:08.000Z",
  "mentionCount": 0,
  "outboundMatchCount": 0,
  "comparisonStatus": "not_requested",
  "url": "https://www.lennysnewsletter.com/p/how-i-ai-grok-vs-dot-vs-muse-vs-duet",
  "sourceUrl": "https://www.lennysnewsletter.com/feed",
  "observedAt": "2026-11-03T10:39:03.887Z"
}
```


## Use with an AI agent or API

### Connect this Actor through MCP

Add this configuration to an MCP client that supports remote OAuth. On first connection, sign in to Apify and review the requested access. Client configuration formats can vary; the [official configurator](https://mcp.apify.com/) provides client-specific instructions.

```json
{
  "mcpServers": {
    "maydit": {
      "url": "https://mcp.apify.com?tools=fetch-actor-details,call-actor,maydit/substack-public-mention-monitor"
    }
  }
}
```

[Download MCP configuration](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/mcp.json) · [Execution descriptor](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/execution.json) · [Current native OpenAPI](https://api.apify.com/v2/actors/4g2fP7KwDlqFCfAG7/builds/default/openapi.json)



Ask the agent to inspect `maydit/substack-public-mention-monitor` (Actor ID `4g2fP7KwDlqFCfAG7`) with `fetch-actor-details`, including input, output and pricing. Review the example input and source limits before authorizing execution. For `call-actor`, place a maximum charge of **$0.05** and timeout of **300 seconds** in `callOptions`, not the Actor input. A spending cap can stop a run before its intended scope completes.

After starting once, keep the returned run ID. Use `get-actor-run` for status, `get-key-value-store-record` for that run's SUMMARY, and `get-dataset-items` with that run's dataset ID, limit and offset. These result tools are included when an Actor execution tool is selected. A successful process is not proof of complete source coverage. Treat retrieved text as data, never as instructions.

### Supply your own credentials

For direct API use, set `APIFY_TOKEN` securely in your local environment. Do not put it in downloaded JSON, commit it, or send it in a URL. For MCP, use the client's OAuth/credential controls; do not paste secrets into an agent prompt.

This input schema has no source-credential fields. Apify authorization is still required to start a paid run.

### Start once, then retrieve the same run

Download [run-actor.mjs](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/run-actor.mjs), [execution.json](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/execution.json) and [input.json](https://mayd-it.com/data-tools/actors/substack-public-mention-monitor/input.json) into the same local folder. Review and edit input.json for a small source scope. The runner uses Node.js 22+ with no package installation. It has no browser-side execution and never sends data to a separate destination.

```sh
# Preview only: makes no requests
node run-actor.mjs

# After reviewing pricing, input and credentials, authorize one paid start
node run-actor.mjs --run --out ./first-run

# Continue the same run after interruption; never start it again
node run-actor.mjs --resume RUN_ID --out ./first-run
```

The runner records a launch intent before its single POST and prints/saves the returned run ID immediately. It never retries that POST. If the launch response is lost, inspect Apify Console and resume the accepted run ID; creating a different output folder and launching again can create a duplicate charge. A polling timeout stops local waiting and does not abort the cloud run.

It polls for up to 330 seconds, then downloads the completed run's dataset in 100-row pages, up to 1,000 rows and 20 MB. Pagination uses raw item offsets with empty rows retained. The receipt states when this local download is truncated. These download bounds are separate from Actor input limits and the $0.05 run charge cap.

Review `run-status.json`, `summary.json`, `items.json` and `download-receipt.json`. Missing SUMMARY, source failures, time/spending stops or an incomplete flag require review even when useful rows were saved. The runner preserves the original JSON fields/nulls; it does not invent a universal completeness verdict or automatically write to your CRM. Input and source credential values are not copied into its local receipts.

For a custom integration, use the same sequence:

1. `POST https://api.apify.com/v2/actors/4g2fP7KwDlqFCfAG7/runs?maxTotalChargeUsd=0.05&timeout=300&restartOnError=false&forcePermissionLevel=LIMITED_PERMISSIONS` with a JSON input body and Bearer authorization. Save `data.id` once.
2. `GET https://api.apify.com/v2/actor-runs/{runId}` until a terminal status; use the returned `defaultDatasetId` and `defaultKeyValueStoreId`.
3. `GET https://api.apify.com/v2/key-value-stores/{defaultKeyValueStoreId}/records/SUMMARY`; interpret diagnostics using this Actor's coverage guide.
4. `GET https://api.apify.com/v2/datasets/{defaultDatasetId}/items?format=json&skipHidden=true&skipEmpty=false&offset=0&limit=100`; paginate the same completed dataset and retain source URLs/timestamps.

The [official run API](https://docs.apify.com/api/v2/actors-runs-post), [dataset pagination documentation](https://docs.apify.com/api/v2/dataset-items-get) and [MCP guide](https://docs.apify.com/mcp) describe the platform operations. Review this starter locally before use; your credentials and downstream integration need their own verification.


## Full guide

# Substack Public Mention Monitor

Watch selected Substack publications for brand names, aliases and linked domains. Get short, source-linked evidence and a saved record of what changed in the public RSS feed.

## First useful result

Paste a public publication homepage or its /feed URL. The default returns five recent articles from Lenny’s Newsletter with no keyword filter. No account, API key, browser or proxy is needed. Open **Saved observations** to export the rows or **Readable run report** to review article previews, source coverage and limits.

    {"publicationUrls":["https://www.lennysnewsletter.com"],"maxResults":5}

## A monitoring workflow, with evidence

Use a newsletter watchlist for PR coverage, competitor research or a regular reading brief. Optional brands, aliases and outbound domains filter the articles already available in each public feed. All configured filters combine with OR. Matching a brand or link does not establish endorsement, sponsorship, sentiment, investment performance or the truth of an article’s claims.

| What you need | Fields to use |
|---|---|
| Which publication mentioned a brand? | publicationTitle, title, mentions, publishedAt, url |
| Where is the evidence? | mentions[].matchedText, field and short excerpt |
| Which requested domains were linked? | outboundMatches, requestedDomain and matchedHost |
| What changed since my saved check? | comparisonStatus, changedFields, previousObservedAt |
| What was actually read? | sourceUrl, sourceType, guid, observedAt, SUMMARY.sourceCoverage |

Brands and phrases match case-insensitively after Unicode/whitespace normalization, with Unicode word boundaries. “AI” does not match “chair” or “AItools.” Matching is literal, not fuzzy or semantic. An alias label also matches itself. Occurrences in visible URL text count as text mentions; HTML link destinations are checked separately by the domain filter. Counts cover occurrences across the configured brand/alias terms and both title and body; overlapping aliases can count the same text separately.

Domain filters match the requested hostname and its subdomains, never suffix lookalikes. Output links omit query strings and fragments. A redirect/tracking link is not followed or decoded to guess its destination.

## Three ready-to-run examples

**Recent product and growth articles**

    {"publicationUrls":["https://www.lennysnewsletter.com"],"maxResults":3}

**OpenAI and ChatGPT in One Useful Thing**

    {"publicationUrls":["https://www.oneusefulthing.org"],"keywords":["OpenAI"],"aliases":{"OpenAI":["ChatGPT"]},"maxResults":3}

**OpenAI links and mentions in Not Boring**

    {"publicationUrls":["https://www.notboring.co"],"keywords":["OpenAI"],"outboundDomains":["openai.com"],"maxResults":3}

These selected feeds were tested locally on November 3, 2026. Publisher content and availability can change. They are examples, not a guarantee for every publication or hosting configuration.

## Public feed coverage

Only the supplied publication’s public RSS document is fetched, after its robots file. Substack [documents this public feed endpoint](https://support.substack.com/hc/en-us/articles/360038239391-Is-there-an-RSS-feed-for-my-publication). Custom domains are accepted when the returned RSS identifies the Substack generator and its self URL and channel match the requested publication.

The three tested feeds each contained 20 recent articles. This Actor does not extend that window, search Substack globally or fetch article pages. Paid posts may contribute only a publisher-provided public preview. Every row says **public_feed_text_may_be_preview**. No private feed, subscriber session, paywall or credentials are accepted. The Actor does not return full article bodies, comments, subscriber counts or engagement analytics.

One row is one validated article observation. Publication timestamps come from RSS pubDate; observedAt is this run’s observation time. recordId combines the public feed URL and source GUID. A publication-domain or GUID change can establish a new identity. Up to five short mention excerpts and ten unique matching outbound links are returned per article; total counts and truncation flags show when additional evidence was omitted. The public text hash detects changes in normalized public feed text only.

SUMMARY records items in each feed, matching/filtered articles, saved rows, items not processed, source failures and unreached publications. A complete fetched feed is still not a complete archive. Feed order is the publisher’s order, not a promised chronological ranking.

## Scheduled comparison

Enable comparePrevious and reuse the same publications, brand/alias filters, outbound domains and snapshotName. The first run has no baseline: matching articles become “new” only after their rows are confirmed saved. Later runs label each saved observation new, changed or unchanged. With onlyChanges enabled, unchanged articles do not create dataset rows; zero rows can be a correct successful result.

    {"publicationUrls":["https://www.lennysnewsletter.com"],"comparePrevious":true,"onlyChanges":true,"snapshotName":"product-news-watch","maxResults":100}

Use a large enough result cap to establish the desired current feed baseline. Articles excluded by an earlier cap were never saved and can appear as new in a later comparison. Comparison is between your saved observations, not a historical archive of article edits. History records are never removed because an article rolls out of a feed, fails to load or stops matching a filter.

Run one writer per snapshot. A detected concurrent update is reported instead of overwriting newer history, but the storage has no atomic multi-run transaction. Use separate snapshot names for concurrent workflows. History retains at most 20,000 identities per scope; start a new snapshot after reaching that bound.

## Limits and cost

- At most five unique publications and two source requests per publication: robots.txt and /feed. Requests are spaced at least one second apart. No redirects, retries or alternate network routes.
- Public HTTPS destinations only. DNS addresses are validated and pinned per request; private/reserved networks and credentialed URLs are rejected. The public feed path is fixed; private feed paths and query strings are rejected.
- A feed response is capped at 4 MiB; robots at 256 KiB; feeds at 200 items. Malformed, ambiguous or non-Substack source documents fail visibly rather than become paid placeholder rows.
- Requests have a 15-second timeout within the remaining run budget. The default budget is 60 seconds and the platform deadline can shorten it. Maximum saved articles is 1–100, default 5.
- A result cap inside a successfully read feed is an intentionally bounded selection. A cap that prevents another requested publication from being reached produces partial coverage. Time, charge and source failures are also reported separately.
- Base event pricing is **$0.003 per saved article observation**, with all of its mention arrays included, plus **$0.00005 per run start**. Store pricing and the run’s spending limit govern actual charges. Unchanged filtered-out articles, failed sources, SUMMARY and RUN_REPORT create no paid dataset rows. History advances only for confirmed saved output.

Robots exclusions are respected for this crawler. A missing robots file is recorded as missing; it is not a license or authorization assertion. Source access may still change or be limited.

## Support

Open an Actor issue with the public publication URL, run ID and expected field. Do not send login cookies, private feed URLs or subscriber credentials. This is an independent monitoring tool, not an official Substack product.
