← All guides

DIY guide · Medium API

Your site. Their Medium stories. Zero scrapers.

Linking out to Medium costs you SEO, session time, and brand control. Product teams that win treat Medium as a content source—not the final destination. This guide is the playbook: full posts on your URLs, your design system, your analytics.

The problem with "read on Medium"

Every click away from your domain is a leak. Google rarely treats embedded iframes or bare outbound links as *your* content. Your newsletter points to Medium and Medium gets the long session. Your product blog looks empty next to competitors who surface full articles in-product.

Scraping feels like a shortcut until Medium ships a markup change and your pipeline breaks at 2 a.m. You deserve better than regex on HTML that was never meant to be an API.

What a real embed looks like

A real embed is not a favicon and a title link. It is the full article—headings, images, code blocks—rendered inside your layout. Your nav, your footer, your CTA to sign up for *your* product. Medium stays the authoring tool; your site becomes the reading experience you control.

Teams choose HTML when they want drop-in rendering in React or WordPress. They choose Markdown when the site is Astro, Hugo, or a static pipeline. Zenndra returns both from the same article_id, so you are not locked into one stack.

The architecture that scales

Mature setups almost always look like this:

  • A catalog step that knows what exists (search, user feed, or editorial list).
  • A content step that fetches body markup once per article and stores it (database, object storage, or edge cache).
  • A render step that serves from cache so your origin is not calling an API on every page view.

That separation is what turns a demo into a product. The API call happens when content changes—not when a visitor refreshes.

Where Zenndra fits

Zenndra is a documented Medium API—not a scraper. You get predictable JSON, stable paths, and formats meant for developers: article metadata, full HTML, clean Markdown. You integrate once; when Medium changes their front-end, your contract stays the same.

That matters when you are betting a marketing site or a paid product on this pipeline.

Wiring it up (technical path)

When you are ready to implement, the happy path is straightforward. Discover stories with Search or Get User Articles so you have an article_id. Pull the body with Get Article HTML or Get Article Markdown. Sanitize HTML if your threat model requires it, map classes to your design tokens, set cache headers, and publish.

Keep a visible link to the original Medium post—authors and SEO both benefit. Cache aggressively; article bodies rarely change hourly.

What success looks like

You will know it worked when organic traffic lands on your URLs, time-on-site climbs, and nobody on the team maintains a scraper. The integration becomes boring—which is the goal.

What to avoid

  • DOM scrapers that break silently and poison your brand when layouts shift.
  • Hotlinking only titles and calling it an embed—users notice, and so does Google.
  • Fetching on every request—your API key and your latency budget will hate you.

Build the cache layer on day one. You will thank yourself at scale.

Starter code

javascript
// Fetch full article HTML for on-site rendering
const articleId = 'f5ef1da2850d';
const res = await fetch(`https://api.zenndra.com/article/${articleId}/html`, {
  headers: { Authorization: `Bearer ${process.env.ZENNDRA_API_KEY}` },
});
if (!res.ok) throw new Error(`Zenndra: ${res.status}`);
const { html } = await res.json();
// Cache `html` by articleId, render inside your layout component