After 2 weeks of evenings and weekends, I shipped Toolsfluent: a free hub of 35+ online tools (calculators, converters, generators) targeting privacy-conscious users in South Asia, the Gulf, and globally.
Sharing the technical learnings here, not the marketing version. If you're a solo dev shipping a content-heavy site, this might save you a few weeks.
The stack
- Framework: Next.js 15 (App Router, RSC, ISR)
- Language: TypeScript
- Styling: Tailwind CSS
- Icons: lucide-react
-
Fonts: Inter (body) + Sora (brand) via
next/font/google - Theme: next-themes
- Hosting: Vercel (Hobby tier)
Static generation for every tool page. No database. No auth. Currency converter is the only thing that hits an external API (exchangerate-api.com free tier).
What worked unexpectedly well
1. Single source-of-truth for tools
Every tool's metadata lives in one TypeScript array:
export const TOOLS: Tool[] = [
{
slug: "mortgage-calculator",
name: "Mortgage Calculator",
description: "...",
category: "finance",
keywords: [...],
icon: "Home",
featured: true,
howToSteps: [...],
faqs: [...],
relatedTools: [...]
},
// ... 34 more
];
Adding a new tool means: add the entry, create a folder, write the calculator component. Sitemap, JSON-LD schema, search index, navigation, related tools, and category pages auto-update from the array.
This single decision saved hours per tool. By tool 20, I was shipping new tools in under an hour.
2. JSON-LD structured data on everything
Every tool ships:
-
SoftwareApplicationschema -
FAQPageschema (from FAQs in the data array) BreadcrumbList
Categories ship CollectionPage. Site root ships WebSite + Organization.
Google takes JSON-LD seriously for tool pages. Without it, you're invisible. With it, your tool can show up with rating stars, FAQs in SERP, and "free" pricing badge.
Build a single buildToolJsonLd(tool) helper and you're done.
3. Per-tool meta description, canonical, OG tags via one helper
export function buildMetadata({title, description, path, keywords, image}) {
const url = `${SITE_URL}${path}`;
return {
title: `${title} | ${SITE_NAME}`,
description,
keywords: keywords.join(", "),
metadataBase: new URL(SITE_URL),
alternates: { canonical: url },
openGraph: {
title, description, url,
images: [{ url: image, width: 1200, height: 630 }]
},
twitter: { card: "summary_large_image" },
robots: { index: true, follow: true }
};
}
Every page calls this. Zero metadata bugs. Easy to verify in view-source.
What surprised me
Em-dashes flagged as AI content
Google's Helpful Content classifier flags em-dashes (—) as a strong signal of AI-generated content. Removed all of them site-wide via sed and replaced with commas / colons / periods. Sounds silly but it's a real ranking heuristic.
Authoritative source citations matter on YMYL
Every health and finance blog post got 2-3 citations to authoritative sources (CDC, WHO, NIST, IRS, CFPB, RBI, GST Council India, HMRC). YMYL (Your Money or Your Life) content without citations gets de-ranked by Google's Quality Rater Guidelines.
Took an extra hour per post to research and cite properly. Made a measurable difference in indexing speed.
Canonical tag with vs without trailing slash
Spent hours debugging "Alternate page with proper canonical tag" warnings in GSC. Turned out my SITE_URL had no trailing slash but Google was crawling URLs with trailing slash. Both worked but Google was confused which one to canonicalize.
Fix: be consistent. Pick one and stick with it everywhere.
Image compressor as a Canvas API trick
Most image compressors upload to a server. The privacy-first version is just:
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0);
canvas.toBlob(blob => downloadBlob(blob), 'image/jpeg', 0.8);
};
img.src = URL.createObjectURL(file);
Quality knob is just the third arg to toBlob. Done. No upload, no server, no privacy concerns.
What's next
- More Pakistani / Indian / UAE niche tools (Marla converter, UAE gratuity, Pakistani GPA already shipped)
- WhatsApp share button site-wide (huge in PK / IN, ignored by most western tool sites)
- AI-augmented text tools using Claude API (cover letter generator, code explainer, etc.) — text only, no image gen because paid API costs would exceed AdSense revenue at this stage
Honest numbers
35 tools live, 17 blog posts, all legal pages, GA4 + Bing + GSC verified. Indexed in Google within 24 hours of launch.
Traffic so far: a handful of visits from my own testing. Distribution is the next problem to solve, not the build.
If you want to see the production version: https://www.toolsfluent.com
Honest feedback welcome — especially on schema markup gotchas, perf optimization wins I'm missing, or tools you'd actually use.
Top comments (0)