# Medium Publication Finder: Subscribers & Activity (`datagrit/medium-publication-finder`) Actor

Find Medium publications by keyword and score each one: subscribers, posting cadence, claps per post, paywalled share and top authors.

- **URL**: https://apify.com/datagrit/medium-publication-finder.md
- **Developed by:** [datagrit](https://apify.com/datagrit) (community)
- **Categories:** Social media, Marketing, Lead generation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Medium Publication Finder: Subscribers & Activity do?

Medium Publication Finder turns a keyword (or a list of publication names) into one scorecard row per Medium publication: how many people follow it, how often it posts, when it last posted, how many claps a typical story gets, how much of it sits behind the paywall, and who writes for it.
It reads the public data Medium serves to any visitor, so there is no login, no API key and no Medium account involved. Export the rows as JSON, CSV or Excel, call the Actor through the Apify API, or connect it to n8n, Make and AI agents through MCP.

### Why use Medium Publication Finder?

Medium search lists publications by relevance and shows nothing about whether they are alive. This Actor adds the part you need to decide where to spend time: cadence and engagement computed from the latest 25 posts of each publication.

- **Build a pitch list.** Search a topic, keep publications with a few hundred to a few thousand followers that posted this month, and rank them by claps per 1,000 subscribers.
- **Drop dormant giants.** A publication with 800,000 followers and no post for a year is a bad target. Set "Posted within the last (days)" and it disappears.
- **Benchmark competitors and sponsors.** Compare posts per week, median claps, responses and member-only share across a shortlist of publications in your niche.
- **Find the editors.** Each row carries the creator, the editors and the most frequent authors with their usernames.
- **Feed dashboards and agents.** One flat row per publication, stable field names, no article dumps to post-process.

### Example output

| name | subscribers | postsPerWeek | daysSinceLastPost | activityStatus | medianClaps | medianClapsPer1kSubscribers | memberOnlySharePct |
|---|---|---|---|---|---|---|---|
| Midwest Startups | 389 | 0.2 | 4.4 | active | 2 | 5.14 | 0 |
| The Startup | 894499 | 1 | 134.5 | dormant | 269 | 0.3 | 68 |
| UX Collective | 634782 | 13.99 | 0.1 | active | 98 | 0.15 | 48 |

```json
{
  "query": "startup",
  "id": "30498dc3bd26",
  "slug": "midwest-startups",
  "name": "Midwest Startups",
  "url": "https://medium.com/midwest-startups",
  "customDomain": null,
  "tagline": "Navigating the ever-growing Midwest startup ecosystem.",
  "subscribers": 389,
  "creatorUsername": "midweststartups",
  "editorsCount": 5,
  "postsSampled": 25,
  "sampleSpanDays": 865.5,
  "lastPostAt": "2026-10-02T15:55:56.171Z",
  "daysSinceLastPost": 4.4,
  "postsPerWeek": 0.2,
  "activityStatus": "active",
  "medianClaps": 2,
  "averageClaps": 12.6,
  "medianClapsPer1kSubscribers": 5.14,
  "medianResponses": 0,
  "memberOnlySharePct": 0,
  "distinctAuthors": 2,
  "topAuthors": [{ "username": "midweststartups", "name": "Midwest Startups", "posts": 22 }],
  "topTags": [{ "tag": "startup", "posts": 22 }, { "tag": "venture-capital", "posts": 18 }],
  "bestPost": { "title": "2024 Best of the Midwest: Startup City Rankings", "claps": 139 },
  "found": true,
  "scrapedAt": "2026-10-07T02:17:41.511Z"
}
```

### How much does it cost?

You pay for each publication row that is delivered, with a lower price on paid Apify plans. Keywords with no matches, publications that do not exist and publications removed by your filters come back as status rows or are skipped, and none of them is charged. Set a maximum spend on the run and the Actor stops when it is reached.
The Actor uses plain HTTP requests, so a run of twenty publications takes seconds and uses very little memory.

### Input

- **Search keywords** – topics to search publications for, one per line. Each keyword is searched separately.
- **Publications to look up** – slugs (`better-programming`), links (`https://medium.com/swlh`) or custom domains (`uxdesign.cc`). Profiles of people (`@name`) are not publications and are ignored.
- **Publications per keyword** – how many publications to score per keyword, in Medium's ranking order, 1 to 100.
- **Recent posts to analyse** – how many recent posts feed the metrics, 5 to 25.
- **Minimum / maximum subscribers** – skip publications outside the range; skipped publications are not charged.
- **Posted within the last (days)** – keep only publications whose newest post is at most this old.
- **Maximum publications** – total limit of rows per run.
- **Proxy configuration** – optional; use it if Medium refuses requests from your region.

### Output fields

Each row has the publication identity (`id`, `slug`, `name`, `url`, `customDomain`, `tagline`, `description`), people (`creatorUsername`, `creatorName`, `editorsCount`, `editors`, `twitterUsername`, `newsletterSlug`), size (`subscribers`), cadence (`postsSampled`, `sampleSpanDays`, `lastPostAt`, `daysSinceLastPost`, `postsPerWeek`, `activityStatus`), engagement (`medianClaps`, `averageClaps`, `medianClapsPer1kSubscribers`, `medianResponses`), content (`medianReadingMinutes`, `medianWords`, `memberOnlySharePct`, `distinctAuthors`, `topAuthors`, `topTags`, `bestPost`) and the run context (`query`, `found`, `sourceUrl`, `scrapedAt`).
When nothing can be returned for an input you get one row with `found: false`, a `reason` and a `message`: `noMatches` (the keyword found no publications), `filteredOut` (publications were found but none passed your filters), `notFound` (no such slug or domain) or `fetchFailed` (Medium did not answer after retries).

### How the metrics are computed

Medium serves at most 25 recent posts per publication, so all cadence and engagement figures describe that sample. `postsPerWeek` is the number of sampled posts divided by the time between the oldest sampled post and now, and `sampleSpanDays` tells you how long that window is. `activityStatus` is `active` when the newest post is at most 14 days old, `slowing` up to 60 days and `dormant` beyond that. `medianClapsPer1kSubscribers` divides the median claps of the sample by followers, which makes small and large publications comparable.

### Limits

- The sample is the latest 25 posts; the Actor cannot page further back.
- Medium does not publish submission guidelines or acceptance rates, so the rows do not say whether a publication takes pitches. They tell you whether it is alive and how its stories perform.
- Clap counts are Medium's public totals and can be zero for publications whose readers rarely clap.
- Subscriber counts are Medium's follower numbers at the time of the run.

### Is it legal to scrape Medium publications?

The Actor reads only public publication data that Medium serves to anyone without logging in. It does not read member-only story text, private data or anything behind a login, and it does not bypass access controls. You are responsible for using the data in line with applicable laws, including data protection rules, and Medium's terms. If you find an issue, open it in the Issues tab; problems are answered within one business day.

### FAQ

**Why is a publication missing from my results?** Either Medium search did not return it for your keyword, or it was removed by your subscriber or activity filters. If every publication is removed you get one `filteredOut` row explaining it.

**Why are median claps zero?** Many publications get few claps. Look at `averageClaps` and `bestPost` to see whether a few stories carry the engagement. A missing value is never reported as zero: if Medium returns no clap count for any post, the field is `null` and the status message shows the clap-count coverage.

**Does it return articles?** No. It scores publications. Use an article scraper when you need story text.

**How fresh is the data?** Every run reads Medium live.

**Can I schedule runs?** Yes, use Apify schedules to track how follower counts and cadence change.

**Something looks wrong.** Open an issue with the input you used; layout changes at Medium are fixed quickly.

### Related Actors

See other data Actors from the same publisher on the Store profile.

# Changelog

This Actor's version history is a separate document: https://apify.com/datagrit/medium-publication-finder/changelog.md

# Actor input Schema

## `queries` (type: `array`):

Keywords to search Medium publications for, one per line (for example "startup" or "machine learning"). Each keyword is searched separately and the publications it returns are scored.

## `publications` (type: `array`):

Specific publications to score: a slug (better-programming), a link (https://medium.com/swlh) or a custom domain (uxdesign.cc). Profiles of people (@name) are not publications and are ignored.

## `maxPublicationsPerQuery` (type: `integer`):

How many publications to score for each search keyword, in the order Medium ranks them. Publications outside the subscriber range do not count toward this number.

## `postsSample` (type: `integer`):

How many of a publication's most recent posts feed the cadence and engagement figures, 5 to 25. Medium serves at most 25 per publication.

## `minSubscribers` (type: `integer`):

Skip publications with fewer followers than this. 0 means no minimum. Skipped publications are not charged.

## `maxSubscribers` (type: `integer`):

Skip publications with more followers than this, which is useful for finding smaller publications that answer pitches. 0 means no maximum.

## `activeWithinDays` (type: `integer`):

Keep only publications whose newest post is at most this many days old, which drops dormant publications with large follower counts. 0 means no limit. Publications without posts are skipped when this is set.

## `maxItems` (type: `integer`):

Stop after this many publication rows in total across all keywords and direct lookups.

## `proxyConfiguration` (type: `object`):

Optional proxy. Leave disabled unless Medium refuses requests from your region; residential proxy raises the platform cost of the run.

## Actor input object example

```json
{
  "queries": [
    "startup",
    "machine learning"
  ],
  "publications": [],
  "maxPublicationsPerQuery": 10,
  "postsSample": 25,
  "minSubscribers": 0,
  "maxSubscribers": 0,
  "activeWithinDays": 0,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All extracted records as a dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "startup",
        "machine learning"
    ],
    "publications": [],
    "maxPublicationsPerQuery": 10,
    "postsSample": 25,
    "minSubscribers": 0,
    "maxSubscribers": 0,
    "activeWithinDays": 0,
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagrit/medium-publication-finder").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "queries": [
        "startup",
        "machine learning",
    ],
    "publications": [],
    "maxPublicationsPerQuery": 10,
    "postsSample": 25,
    "minSubscribers": 0,
    "maxSubscribers": 0,
    "activeWithinDays": 0,
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("datagrit/medium-publication-finder").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "startup",
    "machine learning"
  ],
  "publications": [],
  "maxPublicationsPerQuery": 10,
  "postsSample": 25,
  "minSubscribers": 0,
  "maxSubscribers": 0,
  "activeWithinDays": 0,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call datagrit/medium-publication-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datagrit/medium-publication-finder"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/UeQkggMGFcmQjvOTN/builds/KzOt4zCV9h7IEAKsN/openapi.json
