BlogUp — AI-Powered Blog Generation Platform

What I Built

BlogUp is a full-stack SaaS platform that lets anyone generate publish-ready, SEO-optimized blog posts in under 30 seconds. It goes beyond a simple text generator — it's a complete content engine with two core tools:

  • Blog Generator — create long-form articles from a title, keywords, tone, language, and custom instructions. Or paste any existing article URL and rewrite it into fresh, original content.
  • Blog Analytics — paste any blog URL and get a full SEO and content audit: scores across SEO, content quality, structure, and engagement, plus a prioritized list of exactly what to fix.

Additional features include one-click publishing to WordPress, Medium, and Dev.to, and exports to PDF, DOCX, HTML, and Markdown — so the output fits into whatever workflow the user already has.


Inspiration

The idea came from a personal frustration. I was building my own portfolio and wanted to write blog posts to drive traffic, but I kept stalling — not because I didn't have ideas, but because the act of writing, researching keywords, structuring content, and making it SEO-friendly felt like a full-time job on top of everything else.

I looked at existing tools and found two extremes: expensive, bloated platforms with steep learning curves, or generic chatbot wrappers that output low-quality text with no SEO intent behind it. There was nothing in the middle — something simple, opinionated, and actually designed for the problem.

That gap became BlogUp.


How I Built It

Tech Stack

Layer Technology
Framework Next.js 15 (App Router, Server Components)
AI Engine Google Gemini 2.5 Flash
Database & Auth Supabase (PostgreSQL + Row Level Security)
Payments PayPal Subscriptions API
Deployment Vercel (serverless)
Styling Tailwind CSS + shadcn/ui

Architecture Decisions

Next.js App Router made it natural to mix server and client components. Auth-gated pages run server-side for security, while the generation UI is fully client-side with real-time streaming feel.

Gemini 2.5 Flash was chosen over other models for its cost-efficiency at scale (the token cost per blog post is a fraction of a cent) and its strong performance on long-form structured content. The prompts are handcrafted: the generation prompt instructs the model to follow a strict content structure with H1–H4 headings, keyword density targets, internal linking stubs, and a minimum word count — not just "write a blog post about X."

The Blog Analytics engine is the technically most interesting part. It fetches the target URL server-side, strips all HTML (nav, footer, scripts, styles) down to pure article content, then passes it to a carefully structured prompt that returns a JSON report with scores and recommendations. Parsing the HTML noise out cleanly before the model sees it was critical — early versions had the model hallucinating content from cookie banners and nav menus.

Supabase RLS handles multi-tenancy cleanly. Each user's saved blogs, subscription status, and usage quota are isolated at the database level, not just in application logic.

The export pipeline (PDF, DOCX, HTML, Markdown) is entirely client-side using jsPDF, docx.js, and the native Blob API — no server round-trip needed, which keeps it fast and avoids unnecessary API costs.


Challenges I Faced

1. Static Prerendering vs. Runtime Environment Variables

The hardest production bug to track down. Vercel runs next build and statically prerenders public pages. Any module that called createClient() (Supabase) at the module level would throw supabaseUrl is required during the build — because NEXT_PUBLIC_* variables aren't inlined until runtime on the client.

The fix was a lazy Proxy in lib/supabase.ts that defers createClient() until the first actual method call:

export const supabase = new Proxy({} as SupabaseClient, {
  get(_, prop: string) {
    return (getClient() as any)[prop];
  },
});

Simple in hindsight, but it took a few failed deploys to trace through the webpack bundle back to the root cause.

2. Prompt Engineering for Consistent Output

Getting Gemini to return consistent, well-structured Markdown across hundreds of different topics took more iteration than any other part of the project. Early prompts produced articles that looked good for generic topics but fell apart on technical or multilingual inputs.

The breakthrough was being extremely explicit in the system prompt — specifying exactly which heading levels to use, requiring the model to justify keyword placement, and adding a "do not add disclaimers or AI-sounding preamble" instruction that immediately improved output quality.

For the analytics endpoint, the model needed to return strict JSON (no markdown fences, no explanation). Adding Return ONLY a valid JSON object and a hand-written schema example to the prompt reduced parsing failures from ~30% to near zero.

3. Handling URL-Based Rewriting Safely

The URL-to-blog feature fetches arbitrary URLs server-side, which opens surface area for SSRF. The fetch is guarded to only follow https:// URLs, with a timeout, and the HTML is stripped to plain text before it ever reaches the AI — so even a malicious page can't inject prompt content through its markup.

4. Subscription Quota Management

Tying blog generation to a monthly quota (stored in Supabase) introduced race conditions — two simultaneous requests could both read the same count before either write completed. Solved by moving the decrement to a Supabase database function with a row-level lock, so the check-and-decrement is atomic.


What I Learned

  • Prompt engineering is a real engineering discipline. It's not just "ask nicely." Treating prompts like code — with structure, edge case handling, and explicit output contracts — is what separates reliable AI features from demo toys.

  • Build-time vs. runtime in Next.js App Router. The mental model of "server components render once at request time" breaks down for static pages. Knowing exactly when code runs — build, request, or client — is now something I think about explicitly for every module I write.

  • Supabase RLS is worth the upfront investment. It takes discipline to write policies correctly, but having security at the data layer (not just the API layer) means I don't have to audit every route for missing auth checks.

  • Scope creep is the enemy of shipping. The first version of BlogUp had one feature: generate a blog post. Everything else — analytics, URL rewriting, exports, publishing integrations — was added after the core was working and validated. Shipping the MVP first gave me real feedback before I built the complex stuff.


What's Next

  • Agency Plan — multi-seat accounts for teams managing content for multiple clients
  • Bulk Generation — queue multiple articles and generate them overnight
  • Scheduled Publishing — set a date and BlogUp publishes to your platform automatically
  • Stripe integration — as an alternative to PayPal for global users

Built by Mohamed Belalia — full-stack developer based in Morocco. Stack: Next.js 15 · Gemini 2.5 Flash · Supabase · Vercel · PayPal

Built With

  • nextjs
  • supabase
Share this project:

Updates