datagrit

datagrit › Guides › Medium Publication Finder: Subscribers & Activity

Guide

How to find active Medium publications and rank them by engagement

Find Medium publications by keyword and score each by followers, posting cadence, claps per 1,000 followers and paywalled share, in Python or cURL.

Published 2026-10-07 · uses the Medium Publication Finder: Subscribers & Activity Actor

Anyone who writes for an audience on Medium eventually asks the same question: which publications are worth pitching? Founders want a place to publish a launch story, agencies build outreach lists for clients, newsletter writers look for cross-promotion, and analysts compare the publications in a niche. Medium search answers "which publications match this keyword" but not the questions that decide where to spend time. Is it still publishing? How many followers does it have? Do its stories get any claps?

This guide shows how to turn a keyword into a ranked table of publications with those answers, using the Medium Publication Finder Actor. The same field notes apply if you build the pipeline yourself on Medium's public data.

Where the data comes from

Medium's web pages sit behind a bot filter, and scraping the HTML of a publication page is fragile. The Actor does not parse pages. It asks the same public GraphQL endpoint that Medium's own site uses, which returns structured records: the publication (name, slug, optional custom domain, tagline, description, follower count, creator, editors) and its most recent posts (publication timestamp, claps, responses, reading time, word count, member-only flag, tags, author).

Two properties of that source shape the output:

Step 1: run a keyword search

The input needs at least one keyword in queries or one publication in publications. This input searches two topics, keeps up to ten publications per topic, and drops everything below 200 followers or without a post in the last 90 days:


{
  "queries": ["startup", "machine learning"],
  "maxPublicationsPerQuery": 10,
  "minSubscribers": 200,
  "activeWithinDays": 90,
  "maxItems": 50
}

Call it from Python with apify-client:


from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("datagrit/medium-publication-finder").call(run_input={
    "queries": ["startup", "machine learning"],
    "maxPublicationsPerQuery": 10,
    "minSubscribers": 200,
    "activeWithinDays": 90,
    "maxItems": 50,
})
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())

Or with cURL, which returns the rows directly:


curl -X POST "https://api.apify.com/v2/acts/datagrit~medium-publication-finder/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries":["startup"],"maxPublicationsPerQuery":10,"activeWithinDays":90}'

You can also look up publications you already know. The publications field accepts a slug (better-programming), a link (https://medium.com/swlh) or a custom domain (uxdesign.cc). Profiles of people (@name) are not publications, so they are ignored and listed in the run message.

Step 2: read the fields that matter

FieldExampleWhat it tells you
subscribers389Followers of the publication.
postsPerWeek0.2Sampled posts divided by the window they span.
daysSinceLastPost4.4Whether anyone is still publishing.
activityStatusactiveactive up to 14 days, slowing up to 60, dormant beyond.
medianClaps2A typical story, not one viral outlier.
medianClapsPer1kSubscribers5.14Engagement normalised by size.
memberOnlySharePct0Share of sampled stories behind Medium's paywall.
topAuthors[{"username": "midweststartups", "posts": 22}]Who actually writes there.
bestPost{"title": "...", "claps": 139}The standout story of the sample.

The numbers in that table are a real row. The Midwest Startups publication has 389 followers, posts about once every five weeks and earns a median of two claps per story, which works out to 5.14 claps per 1,000 followers. The Startup publication has 894,499 followers and a median of 269 claps, but its newest sampled post was more than four months old when we checked, so it is dormant and its engagement per follower is 0.3. Size alone would have ranked the two the other way round.

Step 3: three ways to use the table

A pitch list in pandas. Rank the publications that are alive and small enough to answer:


import pandas as pd

df = pd.DataFrame(rows)
df = df[df["found"] == True]
shortlist = df[(df["activityStatus"].isin(["active", "slowing"])) & (df["subscribers"] < 20000)]
print(shortlist.sort_values("medianClapsPer1kSubscribers", ascending=False)
      [["name", "subscribers", "postsPerWeek", "medianClapsPer1kSubscribers", "url"]].head(15))

A weekly competitor sheet. Put your own publication and three competitors in publications, schedule the Actor weekly in Apify, and append the rows to a spreadsheet or a database. Because every row carries scrapedAt, you can chart follower counts and postsPerWeek over time without storing anything in the Actor.

An editor lookup for outreach. Each row has creatorUsername, an editors list and topAuthors. Take the publications on your shortlist and read the usernames to find whom to address, then check the public profile pages yourself before writing to anyone.

Status rows and failures

The Actor never returns silent empty results. When nothing can be returned for an input, you get one row with found: false and a reason:

Status rows are not charged, and neither are publications removed by your filters. If Medium changes its response format so that follower counts, post lists or post dates stop appearing, the run fails with a message that says what is missing, instead of delivering rows full of nulls.

Limits to know about

Wrapping up

Search gives you names, and the scorecard tells you which of those names deserve an email. The Actor is on the Apify Store as Medium Publication Finder: Subscribers & Activity, and the full input and output reference is on the documentation page. It is priced per result, and a maximum spend on the run caps what a run can cost.

Try Medium Publication Finder: Subscribers & Activity on ApifyActor documentation

More guides