<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sebastian Casvean</title>
    <description>The latest articles on DEV Community by Sebastian Casvean (@zenndraapi).</description>
    <link>https://dev.to/zenndraapi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3958969%2F9d7a1830-fc1f-4561-a077-7c1a550ba81f.jpg</url>
      <title>DEV Community: Sebastian Casvean</title>
      <link>https://dev.to/zenndraapi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zenndraapi"/>
    <language>en</language>
    <item>
      <title>Extract Plain Text from Medium Posts for RAG and Search Indexes</title>
      <dc:creator>Sebastian Casvean</dc:creator>
      <pubDate>Sat, 30 May 2026 09:15:17 +0000</pubDate>
      <link>https://dev.to/zenndraapi/extract-plain-text-from-medium-posts-for-rag-and-search-indexes-14mm</link>
      <guid>https://dev.to/zenndraapi/extract-plain-text-from-medium-posts-for-rag-and-search-indexes-14mm</guid>
      <description>&lt;p&gt;Chunk clean article content for embeddings, summarization, and full-text search—skip nav, clap bars, and scripts.&lt;/p&gt;

&lt;h1&gt;
  
  
  Extract Plain Text from Medium Posts for RAG and Search Indexes
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;HTML embeds&lt;/strong&gt; are for humans; &lt;strong&gt;plain text&lt;/strong&gt; is for chunking, embeddings, and summarization. One call should return body text without nav, clap bars, or script tags.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tool outcome:&lt;/strong&gt; &lt;code&gt;ingest-medium-article.ts&lt;/code&gt; → chunked documents in your vector DB.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Pipeline
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Discover ids via user feed or &lt;a href="//./medium-keyword-research.md"&gt;search&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /article/{id}/content&lt;/code&gt; → plain text.&lt;/li&gt;
&lt;li&gt;Optional: &lt;code&gt;GET /article/{id}&lt;/code&gt; for title, tags, author metadata.&lt;/li&gt;
&lt;li&gt;Chunk → embed → upsert vector store.&lt;/li&gt;
&lt;li&gt;Query in your chat UI or internal search.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Ingest script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.zenndra.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ZENNDRA_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchArticleText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;articleId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;contentRes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metaRes&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/article/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;articleId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/content`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/article/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;articleId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contentRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;metaRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;articleId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;chunkText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;overlap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;overlap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wire &lt;code&gt;chunkText&lt;/code&gt; to &lt;a href="https://platform.openai.com/docs/guides/embeddings" rel="noopener noreferrer"&gt;OpenAI embeddings&lt;/a&gt;, &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;, or your host’s model—swap the vector client, keep the ingest shape.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chunking tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Include &lt;strong&gt;title + tags&lt;/strong&gt; in the embedding preamble for better retrieval.&lt;/li&gt;
&lt;li&gt;Store &lt;code&gt;article_id&lt;/code&gt; and &lt;code&gt;chunk_index&lt;/code&gt; in metadata for citations.&lt;/li&gt;
&lt;li&gt;Deduplicate re-ingest with content hash if posts are edited rarely.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Compliance (non-optional)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Respect &lt;a href="https://medium.com/policy/terms-of-service" rel="noopener noreferrer"&gt;Medium’s Terms of Service&lt;/a&gt; and author rights.&lt;/li&gt;
&lt;li&gt;Many teams only index &lt;strong&gt;their own&lt;/strong&gt; posts or licensed partners.&lt;/li&gt;
&lt;li&gt;Do not expose paywalled or member-only content through public bots without permission.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For human-readable syndication, see &lt;a href="//./embed-medium-articles-on-website.md"&gt;embed articles&lt;/a&gt;—different threat model than LLM training.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keywords
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;medium plain text api&lt;/code&gt;, &lt;code&gt;medium rag pipeline&lt;/code&gt;, &lt;code&gt;medium embeddings&lt;/code&gt;, &lt;code&gt;medium article content extraction&lt;/code&gt;, &lt;code&gt;llm medium&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://js.langchain.com/docs/concepts/text_splitters/" rel="noopener noreferrer"&gt;LangChain: text splitters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Zenndra: &lt;a href="https://zenndra.com/use-cases/ai-article-text-pipeline" rel="noopener noreferrer"&gt;Medium articles for AI and search indexes&lt;/a&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45gy4hi8k3vjet1reliy.png" alt=" " width="800" height="436"&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>llm</category>
      <category>api</category>
    </item>
    <item>
      <title>Medium API in 2026: Scraping vs Official API vs Zenndra (Honest Comparison)</title>
      <dc:creator>Sebastian Casvean</dc:creator>
      <pubDate>Fri, 29 May 2026 19:24:27 +0000</pubDate>
      <link>https://dev.to/zenndraapi/medium-api-in-2026-scraping-vs-official-api-vs-zenndra-honest-comparison-1pe8</link>
      <guid>https://dev.to/zenndraapi/medium-api-in-2026-scraping-vs-official-api-vs-zenndra-honest-comparison-1pe8</guid>
      <description>&lt;p&gt;If you've ever tried to pull data from Medium programmatically, you already know the pain.&lt;br&gt;
Medium retired their official API years ago. What's left is a graveyard of Stack Overflow threads, half-working scrapers, and a handful of third-party services with questionable reliability.&lt;br&gt;
This article breaks down your three real options in 2026 — honestly, with code — so you can pick what actually fits your use case.&lt;/p&gt;

&lt;p&gt;The Three Options&lt;/p&gt;

&lt;p&gt;DIY scraping — build and maintain your own scraper&lt;br&gt;
Medium's official API — limited, but it exists for authenticated flows&lt;br&gt;
Zenndra — a third-party REST API built after Medium killed theirs&lt;/p&gt;

&lt;p&gt;Let's go through each one.&lt;/p&gt;

&lt;p&gt;Option 1: DIY Scraping&lt;br&gt;
This is where most developers start. You fire up a headless browser, parse the HTML, and call it a day.&lt;br&gt;
The appeal: free, no dependency on a third party, full control.&lt;br&gt;
The reality: Medium's frontend changes constantly. Your scraper will break — not if, when. You'll spend more time maintaining the scraper than building the product you actually care about.&lt;br&gt;
A typical flow looks like this:&lt;br&gt;
bash# You'd need a headless browser or parse the raw HTML&lt;/p&gt;

&lt;h1&gt;
  
  
  Medium serves most content client-side, so curl alone won't cut it
&lt;/h1&gt;

&lt;p&gt;curl "&lt;a href="https://medium.com/@username" rel="noopener noreferrer"&gt;https://medium.com/@username&lt;/a&gt;" \&lt;br&gt;
  -H "User-Agent: Mozilla/5.0"&lt;/p&gt;

&lt;h1&gt;
  
  
  Good luck parsing that response reliably
&lt;/h1&gt;

&lt;p&gt;The HTML you get back is a mess of React-rendered markup with no stable selectors. And if Medium detects scraping patterns, you get rate-limited or blocked entirely.&lt;br&gt;
When to choose this: Almost never, unless you have very specific needs that no API covers and you're prepared to maintain it long-term.&lt;/p&gt;

&lt;p&gt;Option 2: Medium's Official API&lt;br&gt;
Medium does have an official API — but it's extremely limited.&lt;br&gt;
What it can do:&lt;/p&gt;

&lt;p&gt;Create posts (via OAuth)&lt;br&gt;
Get your own profile info&lt;br&gt;
Publish to publications you're a contributor to&lt;/p&gt;

&lt;p&gt;What it cannot do:&lt;/p&gt;

&lt;p&gt;Fetch any arbitrary user's articles&lt;br&gt;
Search content&lt;br&gt;
Get follower graphs&lt;br&gt;
Read publications you don't own&lt;br&gt;
Access tags, trending feeds, or article stats&lt;/p&gt;

&lt;p&gt;bash# The official API — only works for authenticated write operations&lt;br&gt;
curl "&lt;a href="https://api.medium.com/v1/me" rel="noopener noreferrer"&gt;https://api.medium.com/v1/me&lt;/a&gt;" \&lt;br&gt;
  -H "Authorization: Bearer YOUR_MEDIUM_TOKEN"&lt;/p&gt;

&lt;h1&gt;
  
  
  Returns YOUR profile only — not anyone else's
&lt;/h1&gt;

&lt;p&gt;If you're building anything read-heavy — a dashboard, a content aggregator, an AI pipeline, a research tool — the official API is essentially useless for you.&lt;br&gt;
When to choose this: Only if you need to publish content to Medium programmatically and nothing else.&lt;/p&gt;

&lt;p&gt;Option 3: Zenndra&lt;br&gt;
Zenndra is an unofficial REST API built specifically to fill the gap Medium left. 42 endpoints covering articles, users, publications, tags, feeds, and search — all returning clean, stable JSON.&lt;br&gt;
bash# Fetch any user's profile&lt;br&gt;
curl "&lt;a href="https://api.zenndra.com/v1/users/@username" rel="noopener noreferrer"&gt;https://api.zenndra.com/v1/users/@username&lt;/a&gt;" \&lt;br&gt;
  -H "Authorization: Bearer YOUR_ZENNDRA_KEY"&lt;/p&gt;

&lt;h1&gt;
  
  
  Response: 200 OK in ~142ms
&lt;/h1&gt;

&lt;h1&gt;
  
  
  {
&lt;/h1&gt;

&lt;h1&gt;
  
  
  "username": "username",
&lt;/h1&gt;

&lt;h1&gt;
  
  
  "name": "...",
&lt;/h1&gt;

&lt;h1&gt;
  
  
  "followers": 4201,
&lt;/h1&gt;

&lt;h1&gt;
  
  
  "bio": "..."
&lt;/h1&gt;

&lt;h1&gt;
  
  
  }
&lt;/h1&gt;

&lt;p&gt;bash# Get a user's articles&lt;br&gt;
curl "&lt;a href="https://api.zenndra.com/v1/user/%7Buser_id%7D/articles" rel="noopener noreferrer"&gt;https://api.zenndra.com/v1/user/{user_id}/articles&lt;/a&gt;" \&lt;br&gt;
  -H "Authorization: Bearer YOUR_ZENNDRA_KEY"&lt;br&gt;
bash# Search articles&lt;br&gt;
curl "&lt;a href="https://api.zenndra.com/v1/search/articles?query=machine+learning" rel="noopener noreferrer"&gt;https://api.zenndra.com/v1/search/articles?query=machine+learning&lt;/a&gt;" \&lt;br&gt;
  -H "Authorization: Bearer YOUR_ZENNDRA_KEY"&lt;br&gt;
bash# Trending feed for a tag&lt;br&gt;
curl "&lt;a href="https://api.zenndra.com/v1/recommended_feed/python" rel="noopener noreferrer"&gt;https://api.zenndra.com/v1/recommended_feed/python&lt;/a&gt;" \&lt;br&gt;
  -H "Authorization: Bearer YOUR_ZENNDRA_KEY"&lt;br&gt;
The free tier gets you started with no credit card required. Paid plans start at €3.90 for 1 million requests — which is about as cheap as this category gets.&lt;br&gt;
When to choose this: Any time you need read access to Medium content at scale — dashboards, newsletters, AI/LLM pipelines, research tools, content aggregators.&lt;/p&gt;

&lt;p&gt;Side-by-Side Comparison&lt;br&gt;
DIY ScrapingOfficial APIZenndraSetup timeDays / weeksMinutesMinutesRead any user✅ (fragile)❌✅Search content✅ (fragile)❌✅Stable endpoints❌✅✅LatencyUnpredictableFast~142ms P50Maintenance burdenHighNoneNoneCostYour timeFreeFrom €3.90/moRate limitsDependsStrictGenerousProduction-readyRiskyLimited useYes&lt;/p&gt;

&lt;p&gt;The Verdict&lt;br&gt;
If you're building anything that needs to read Medium content — just use Zenndra. The scraping path looks attractive until you've rebuilt your parser for the third time after a Medium frontend update.&lt;br&gt;
The official API is fine for publishing workflows, but it's not a real option for read-heavy use cases.&lt;br&gt;
Zenndra has a free tier with a playground where you can test every endpoint before writing a single line of integration code. Worth 5 minutes of your time: zenndra.com&lt;/p&gt;

&lt;p&gt;Have a use case this doesn't cover? Drop it in the comments — happy to help.&lt;/p&gt;

</description>
      <category>api</category>
      <category>productivity</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
