From 0 to Launch: The Architecture Behind OGify
A 'Build in Public' narrative about creating the studio's first SaaS, explaining the technological choices.
From 0 to Launch: The Architecture Behind OGify
Building a SaaS from scratch requires making dozens of critical technical choices. You are constantly balancing development speed (to hit market windows) with long-term maintainability and operational costs. For OGCraft (originally conceptualized as OGify), we needed an architecture that allowed our small team to move incredibly fast while reliably handling CPU-intensive image generation workloads at scale.
In this "Build in Public" technical post, we pull back the curtain on the complete architecture behind our visual generation API, detailing our chosen frameworks, rendering engines, and the seamless integration of our billing system.
The Foundation: React Router v8
We evaluated Next.js, Nuxt, and plain Express, but ultimately chose React Router v8 (the evolution of Remix) as our full-stack framework. It provides unmatched data loading paradigms that keep our dashboard lightning fast without complex client-side state management.
- Loaders and Actions: React Router's
actionfunctions act as our API controllers. Handling authentication, updating user templates, and processing Stripe webhooks happens flawlessly without needing a separate backend repository. - Vite Integration: The new Vite-based compiler provides instant Hot Module Replacement (HMR) during development, saving us hours of waiting for recompilations.
- Deployment Portability: The build output is a standard Node.js request handler, meaning we aren't locked into a specific edge provider and can run standard Docker containers on Railway.
Image Generation Engine: Satori + Resvg
The core value of our SaaS is generating images quickly. Traditionally, developers use headless Chromium (via Puppeteer or Playwright) to take screenshots of HTML pages. However, booting a browser consumes ~200MB of RAM and takes 1-2 seconds per request. This was unacceptable for our latency targets.
Instead, we built our rendering pipeline on Satori. Open-sourced by Vercel, Satori parses HTML and CSS (specifically flexbox layouts) and converts them purely to an SVG string using a subset of the browser layout engine. We then pipe that SVG through a Rust-based WebAssembly module, @resvg/resvg-js, to generate standard PNG files.
import satori from 'satori';
import { Resvg } from '@resvg/resvg-js';
import { readFileSync } from 'fs';
// Pre-load fonts into memory on server start
const interRegular = readFileSync('./fonts/Inter-Regular.woff');
const interBold = readFileSync('./fonts/Inter-Bold.woff');
export async function renderTemplateToPng(reactElement) {
// 1. Convert React/JSX to SVG incredibly fast
const svg = await satori(reactElement, {
width: 1200,
height: 630,
fonts: [
{ name: 'Inter', data: interRegular, weight: 400, style: 'normal' },
{ name: 'Inter', data: interBold, weight: 700, style: 'normal' },
],
});
// 2. Rasterize SVG to PNG using Rust bindings
const resvg = new Resvg(svg, {
fitTo: { mode: 'width', value: 1200 },
font: { loadSystemFonts: false }
});
return resvg.render().asPng();
}The Result: Image generation dropped from 1500ms (Puppeteer) to ~50ms per image, with less than 20MB of memory overhead. Furthermore, we retain the ability to write our visual templates using standard React JSX and Tailwind CSS, making template creation incredibly developer-friendly.
Quota-Based Billing with Stripe & MongoDB
Because OGCraft is an API-first product, our primary unit of value is the API request. We implemented a robust quota-based billing system.
We store user configurations and usage metrics in a managed MongoDB cluster. When a user creates a subscription, Stripe Webhooks are fired to our React Router backend, provisioning their API key. Every time an image is successfully generated via the API, an optimized atomic $inc operation updates the user's monthly usage counter.
If a user exceeds their quota, our middleware gracefully intercepts the request. Instead of crashing their application or returning a 403 error (which would result in broken images on their site), we serve a fallback watermarked image, bridging the gap between seamless technical reliability and clear monetization boundaries.
Conclusion
Dynamic OpenGraph images are no longer an optional luxury—they are a critical component of modern web SEO and social media marketing. Regardless of your stack, injecting custom social cards into your web pages is essential for standing out.
Ready to take your social share preview images to the next level without maintaining complex canvas code?
Build Stunning OG Cards with OGCraft
Customize templates in real-time in our interactive Playground and fetch high-performance OpenGraph images via a simple API URL.