How I Built a Privacy-First Markdown Editor with Astro + Cloudflare Pages
I wanted a Markdown editor that loads instantly, previews in real time, and never asks for my email. So I built MarkdownMaster.
Here's the full story: the tech stack, the architecture decisions, and what I learned along the way.
The Problem with Existing Markdown Editors
Most online Markdown editors fall into one of three camps:
- Heavy WYSIWYG apps — HackMD, Notion, etc. Cool features, but slow to load and require accounts
- Ad-cluttered free tools — Works, but the UX is awful
- Developer-only CLI tools — Great for terminal users, useless for sharing with non-technical teammates
I wanted something different: a clean, fast, privacy-first editor that works the moment you open the URL. No loading spinners. No cookie walls. No "sign up to save" nag screens.
The Stack: Why Astro + Cloudflare
After evaluating several options (Next.js, SvelteKit, plain HTML), I landed on:
| Concern | Solution |
|---|---|
| Speed | Astro static generation → zero JavaScript runtime |
| Global latency | Cloudflare Pages edge network → <50ms TTFB worldwide |
| Markdown parsing | marked.js → battle-tested GFM parser |
| Syntax highlighting | Prism.js → 100+ languages, lightweight |
| Dynamic content | Cloudflare D1 → edge SQLite for blog content |
| Analytics | GA4 with cookie consent banner |
Why Not Next.js?
Next.js is great, but for a content-heavy tool that doesn't need client-side state management, it's overkill. Every Next.js page ships 70-100KB of JavaScript even for static content. Astro ships zero.
Why Cloudflare Pages Over Vercel/Netlify?
- Free tier includes 500 builds/month (vs Vercel's 100 on hobby)
- D1 database at the edge (no cold starts like serverless)
- Workers for lightweight backend logic (affiliate links, A/B tests)
- Built-in analytics without third-party scripts
Architecture
┌─────────────────────────────────────────────────┐
│ Cloudflare │
│ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Pages │ │ Worker │ │ D1 │ │
│ │ (static) │──│(affiliate│──│(blog content, │ │
│ │ Astro │ │ injection)│ │ link templates)│ │
│ └──────────┘ └──────────┘ └───────────────┘ │
└─────────────────────────────────────────────────┘
│
▼
User's Browser
┌─────────────────────────────┐
│ marked.js (GFM parser) │
│ Prism.js (highlighting) │
│ GA4 (analytics) │
│ All client-side. Zero API │
└─────────────────────────────┘
Key architectural decisions:
1. Everything Runs Client-Side
The editor is pure HTML + CSS + JS. When you type on the left, marked.js converts it to HTML on the right — all in your browser. No server round-trips, no API calls, no latency.
This also means your content never leaves your device. I don't have a server to store it on even if I wanted to.
2. Astro for Static Generation
The blog, docs, and landing pages are all pre-built HTML. No SSR, no hydration, no client-side routing. Just pure HTML served from Cloudflare's edge.
---
// src/pages/index.astro
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout
title="Free Online Markdown Editor — MarkdownMaster"
description="Free online Markdown editor with real-time live preview..."
>
<section class="hero">
<h1>Write Markdown. See It Instantly.</h1>
<a href="/editor/">Start Writing Now →</a>
</section>
<!-- Features, etc -->
</BaseLayout>
3. Cloudflare Worker for Lightweight Backend
The only server-side code is a Worker that proxies requests from markdownmaster.site to the Pages deployment. It injects an affiliate button on HTML pages and passes everything else through untouched.
// Simplified Worker logic
export default {
async fetch(request, env) {
const response = await fetch(origin + url.pathname);
// Only inject into HTML responses
if (response.headers.get('content-type')?.includes('text/html')) {
let html = await response.text();
const links = await env.DB.prepare(
"SELECT links_json FROM link_templates WHERE site_id = ?"
).bind("tool-markdown").first();
html = html.replace('</body>', affiliateButton(links) + '</body>');
return new Response(html, response);
}
return response; // Static assets pass through untouched
}
}
4. Cookie Consent That Actually Respects Privacy
GDPR compliance isn't optional if you use GA4. But I hate those full-screen cookie walls that darken the page and force you to click through 12 toggles.
My solution: a slim bottom banner with one button.
// No framework, no npm dependency. Just vanilla JS.
(function(){
if (document.cookie.indexOf('mm_cookie_consent=1') !== -1) return;
document.getElementById('cookie-banner').style.display = 'flex';
document.getElementById('cookie-accept').onclick = function(){
document.cookie = 'mm_cookie_consent=1;max-age=31536000;path=/;SameSite=Lax';
document.getElementById('cookie-banner').style.display = 'none';
};
})();
The Blog: 17 Articles and Counting
I wrote 17 in-depth Markdown tutorials — from beginner cheat sheets to advanced topics like Mermaid diagrams and LaTeX math formulas. Each article is 2,500-3,500 words with real code examples.
| Article | Topic |
|---|---|
| Markdown Cheat Sheet | Complete syntax reference |
| How to Write Markdown | Step-by-step beginner guide |
| Markdown for Developers | README, docs, wikis |
| Advanced Markdown | Footnotes, Mermaid, Math |
| Build a Blog with Markdown + Astro | Full tutorial |
The blog serves two purposes:
- SEO — long-tail keywords like "how to create markdown tables" bring organic traffic
- Trust — Google's EEAT guidelines favor sites that demonstrate expertise with substantial content
SEO: What I Learned
Launching a new domain is humbling. You ship, you submit your sitemap, and... crickets. For weeks.
Here's what actually moved the needle:
1. Fix Canonical URLs Immediately
My blog pages had a canonical dead loop: the sitemap linked to /blog/post-name/ but the page's canonical tag pointed to /blog/post-name.html, which 301-redirected back to the clean URL. Google saw this and refused to index anything.
Fix: Align canonical with sitemap URLs. This single fix took my site from 0 to 7 organic search clicks in 24 hours.
2. EEAT Signals Matter
Google looks for "Experience, Expertise, Authoritativeness, Trustworthiness" signals. I added:
- About page with my name, GitHub profile, and technical background
- Footer links to the open-source repository
- Privacy policy that honestly describes GA4 cookie usage
- Cookie consent (GDPR compliance matters in 2026)
3. .site TLDs Have a Trust Problem
I learned this the hard way: Google's algorithms are skeptical of .site domains because they're commonly used by phishing sites. If I were starting over, I'd choose .com or .io. If you're stuck with .site like me, the EEAT signals above become even more critical.
What's Next
- Open-source the editor component as a standalone package
- Export formats: PDF, DOCX, HTML zip
- Keyboard shortcuts: Full VSCode-style command palette
- Collaboration: Real-time multiplayer editing via WebRTC (no server, still privacy-first)
Try It
markdownmaster.site — No sign-up, no tracking, no ads. Just open and write.
GitHub — Star the repo if you find it useful!
Built by KK Tian. I build fast, privacy-first web tools. Follow me on GitHub for more.
Top comments (0)