When family or friends in India prepare for marriage alliances, the first thing they share on WhatsApp is a Matrimonial Biodata — a comprehensive 1- or 2-page document covering personal background, education, career, family lineage, horoscope/Kundali details, and partner expectations.
Unfortunately, most existing tools are either:
- Clunky MS Word templates that break layout on mobile.
- Scammy websites that force you to create an account, enter a phone number, or pay before you can even see your PDF preview.
- Ad-infested portals with designs that look like they were built in 2005. So I decided to build a fast, modern, and privacy-respecting alternative from scratch: BiodataMaker.org. and its dedicated free creator portal free.biodatamaker.org. Here is the tech stack, the architectural decisions, and the technical challenges I solved along the way. ---
🏗 The Architecture & Tech Stack
| Layer | Technology | Why Chosen? |
|---|---|---|
| Framework | Next.js 16 (App Router) | Instant page routing, React 19 compiler, static generation |
| Styling | Tailwind CSS v4 | Ultra-lean atomic CSS, royal dark/gold palette |
| Authentication | Firebase Auth | Anonymous guest sign-in + Google One Tap with zero friction |
| Database | Cloud Firestore | Real-time multi-device sync for saved drafts |
| Asset Storage | Cloudflare R2 | Zero-egress fee S3-compatible object storage for photo uploads |
| Hosting & Edge | Cloudflare Pages | Sub-millisecond global CDN caching and edge delivery |
| PDF Generation | html2canvas-pro + jsPDF | 100% in-browser rendering (no headless Chrome server costs) |
💡 Core Philosophy: "Zero Forced Signups"
The biggest friction point in web tools is requiring login before a user sees value.
On BiodataMaker.org:
- You open the studio, pick a template, fill in details, upload a photo, and click Download PDF or WhatsApp HD Image.
- It downloads instantly without asking for your email, phone number, or payment.
- If you want to sync your biodata across your laptop and phone, Firebase anonymous authentication automatically connects your draft to an account in 1 click using Google One Tap.
🛠 3 Interesting Engineering Challenges I Solved
1. In-Browser Multi-Page PDF Generation without Tainted Canvases
Server-side PDF generation (e.g., using Puppeteer) can get expensive and slow at scale. To keep exports fast and 100% free, I opted for client-side generation using html2canvas-pro + jsPDF.
However, user photos stored on CDNs caused CORS canvas tainting (SecurityError: The operation is insecure).
Solution: I implemented a pre-processing pipeline that inlines all image elements into base64 Data URLs via an internal proxy before feeding the DOM into the canvas engine:
async function inlineImages(rootEl: HTMLElement) {
const imgs = Array.from(rootEl.querySelectorAll("img"));
await Promise.all(
imgs.map(async (img) => {
const originalSrc = img.getAttribute("src") || img.src;
if (!originalSrc || originalSrc.startsWith("data:")) return;
try {
const res = await fetch(originalSrc, { mode: "cors" });
const blob = await res.blob();
const base64 = await new Promise<string>((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result as string);
reader.readAsDataURL(blob);
});
img.src = base64;
} catch (err) {
console.warn("Could not inline image for PDF capture:", err);
}
})
);
}
This guaranteed that canvas exports never fail, even on mobile Safari and Android WebViews.
2. Shaving 85% of Image Weight with Sharp Prebuild Pipelines
With 28 template preview images displayed on the homepage, initial testing showed the preview folder was nearly 15 MB in uncompressed PNGs!
Instead of running a heavy runtime image optimization server on Cloudflare Workers, I built an automated CI/CD prebuild hook using sharp that runs on every npm run build:
Automatically resizes oversized previews to max width 700px (retina-ready for 270px cards).
Applies 8-bit palette quantization and level-9 compression.
Result: Dropped the preview payload from 14.14 MB down to 1.69 MB (-88% reduction) with zero visible quality loss.
- Sub-50ms Global TTFB with Edge Cache Rules Next.js HTML pages are often treated as dynamic by default. To make the landing page and public template showcases instant worldwide, I configured custom headers in next.config.mjs:
// Cache public marketing HTML at the Cloudflare Edge for 24h
{
source: "/:path(pricing|invitations|free-biodata-maker|contact|terms|privacy)?",
headers: [
{
key: "Cache-Control",
value: "public, max-age=3600, s-maxage=86400, stale-while-revalidate=86400",
},
],
}
Coupled with a Cloudflare Cache Rule, HTML responses are served directly from RAM in the nearest edge node (Mumbai, Delhi, Singapore, Frankfurt) with 20ms–40ms TTFB.
✨ Features Built So Far
13 Luxury Themes: Traditional Vedic mandalas, Royal Darbar, High-fashion Rosewood editorial, and minimalist contemporary Swiss designs.
4 Exclusive 2-Page Royal Booklets: Page 1 features a full-cover portrait with sacred blessings, and Page 2 contains detailed career, Kundali, family, and partner preferences.
Digital Wedding Invitation Maker: Single-page WhatsApp cards and 2-page ceremony itinerary suites (Haldi, Mehendi, Sangeet, Phere, Reception).
PDF & Photo Merger Tool: Easily attach horoscope birth charts and family photos directly into a unified PDF.
🚀 Live Demo & Feedback
You can try the app right now without creating an account:
👉 BiodataMaker.org
I would love to hear feedback from the Dev.to community:
What do you think of the design and UX flow?
How are you handling client-side PDF generation in your own projects?
Drop your thoughts and questions in the comments below! 👇
Top comments (0)