Converts Beehiiv newsletter posts into properly formatted blog markdown files. Use when converting newsletters to blog posts, importing Beehiiv content, or creating blog posts from newsletter URLs.
A comprehensive guide for converting Substack (or Beehiiv) newsletter posts into properly formatted blog markdown files for the website.
https://didierrlopes.substack.com/p/<slug> or https://substack.com/home/post/p-<id>https://didierlopes.beehiiv.com/p/<slug>Use the imageFetch tool to extract content and images:
mcp__fetch__imageFetch with url=<newsletter-url> and images={"output": "file", "layout": "individual", "maxCount": 10}
Platform-specific notes:
Substack:
substack.com/home/post/p-<id>, the content may be embedded in JSON within the HTML. Use raw=true and extract the body_html field from the embedded JSON?utm_source=didierlopes.beehiiv.com&utm_medium=newsletter&utm_campaign=... from URLshttps://substackcdn.com/image/fetch/.../https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F<uuid>_<dimensions>.<ext>https://substackcdn.com/image/fetch/w_1200,c_limit,f_png,q_auto:good/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F<uuid>_<dimensions>.<ext>Beehiiv:
Key extraction requirements:
Format: YYYY-MM-DD
Substack:
https://didierrlopes.substack.com/archivethe-era-of-on-demand-software-26-01-31) but do NOT use it - it may not match the actual publication dateBeehiiv:
Rules:
2025-09-19-the-trampoline-job-optimize-your-career-for-growth.md---
slug: <title-slug-without-date>
title: <Full Newsletter Title>
date: <YYYY-MM-DD>
image: /blog/<filename>.webp
tags:
- <relevant-tag-1>
- <relevant-tag-2>
- <relevant-tag-3>
description: <Newsletter subtitle or first paragraph summary (max 160 chars)>
hideSidebar: true
---
Front Matter Rules:
.webp extension). If the post has no cover image, omit this fieldtrue for blog postsIMPORTANT: All images must be in WebP format for optimal file size and fast page loads.
Image Handling Rules:
Hero Image
https://didierrlopes.substack.com/archive). Extract thumbnail image URLs which follow the pattern with public%2Fimages%2F<uuid>. Download at high resolution using: https://substackcdn.com/image/fetch/w_1200,c_limit,f_png,q_auto:good/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F<uuid>_<dimensions>.<ext>https://substackcdn.com/image/youtube/w_728,c_limit/<video_id>)/static/blog/YYYY-MM-DD-slug.png (or .jpg) first, then convert to WebPstatic/blog/ directory, not just /blog/image: field from front matterContent Images
/static/blog/YYYY-MM-DD-slug_N.png (where N is sequential number)static/blog/ directoryConvert All Images to WebP After downloading images, convert them to WebP format using:
# For PNG/JPG images:
cwebp -q 90 "image.png" -o "image.webp" && rm "image.png"
# For GIF images (animated):
gif2webp -q 90 "image.gif" -o "image.webp" && rm "image.gif"
Final filenames should be:
/static/blog/YYYY-MM-DD-slug.webp/static/blog/YYYY-MM-DD-slug_N.webpImage Markdown Format

<!-- For centered images with custom width -->
<p align="center">
<img width="500" src="/blog/image-path.webp" alt="Description" />
</p>
Content Conversion Rules:
Opening Section
image field)<!-- truncate --> after intro paragraph for blog previewSection Dividers
Headings
##)###)Lists
-)<br /> after each list block for proper spacingExample:
- First item
- Second item
- Third item
<br />
Next paragraph starts here...
Links
?utm_source=...&utm_medium=...&utm_campaign=...)[link text](url)This [post](url)https://didierlopes.com/blog/<slug>)Emphasis
**text***text*Quotes and Citations
>) for extended quotes> <br /> between paragraphs<br /> after the quote blockExample:
> First paragraph of the quote goes here.
>
> <br />
>
> Second paragraph of the quote continues here.
<br />
**Author Name** - ["Article Title"](https://actual-link.com)
Code/Technical Content
YouTube Videos
https://www.youtube.com/watch?v=VIDEO_ID → VIDEO_ID)<br /> after the video embed so following text doesn't appear glued to itExample conversion:
https://www.youtube.com/watch?v=Zyw-YA0k3xo<div className="flex place-items-center justify-center items-center rounded-sm mx-auto">
<iframe
src="https://www.youtube.com/embed/Zyw-YA0k3xo"
width="800"
height="400"
/>
</div>
<br />
Note: Always verify the video link exists in the original content - don't assume or guess video IDs
Image Captions
Example:
<p align="center">
<img width="800" src="/blog/image.webp" alt="Description" />
</p>
<p align="center" style={{fontSize: '0.85em', marginTop: '-0.5em'}}>Caption text describing the image above.</p>
Remove from Newsletter:
?utm_source=...)Preserve:
Before finalizing:
image: field includes .webp extension (or is omitted if no cover image).webp extension/blog/ directory with correct namingSubstack URL: https://didierrlopes.substack.com/p/the-context-wars-in-financial-services
Converted to: /blog/2026-02-13-the-context-wars-in-financial-services.md
Beehiiv URL: https://didierlopes.beehiiv.com/p/the-trampoline-job-optimize-your-career-for-growth
Converted to: /blog/2025-09-19-the-trampoline-job-optimize-your-career-for-growth.md
Key transformations:
<!-- truncate --> marker for blog previewsubstack.com/home/post/p-<id> URLs directly for content extraction - try didierrlopes.substack.com/p/<slug> first as it renders better