Utilities Registry
Sixty-plus client-side browser tools, each its own SEO page.
RegistriesLiveReactJavaScript
60tools
What it is
A registry of free, client-side browser utilities (converters, encoders, generators, formatters). Each tool is statically generated with its own metadata, FAQ and WebApplication JSON-LD. Nothing leaves your machine.
Take it with you
The real, committed source behind this system — copy it or download the file. Plus a portable spec of everything on this page.
utility-tool-page.jsxjsx67 lines
The per-tool SEO page template — generateStaticParams + generateMetadata + WebApplication JSON-LD, all from one registry entry.
import { notFound } from 'next/navigation';
import { getToolById, getAllTools } from '@/utilities/registry';
import { keywordsFor } from '@/utilities/keywords';
import { buildMetadata, buildBreadcrumbJsonLd } from '@/lib/metadata';
import ToolPageClient from './ToolPageClient';
import HireCta from '@/components/cta/HireCta';
export function generateStaticParams() {
return getAllTools().map((t) => ({ tool: t.id }));
}
export async function generateMetadata({ params }) {
const { tool } = await params;
const result = getToolById(tool);
if (!result) return {};
const { tool: t } = result;
return buildMetadata({
title: t.metaTitle || t.name,
// Prefer a concise, SERP-length metaDescription where authored; fall back
// to the (longer) on-page howItWorks, then the one-line desc.
description: t.metaDescription || t.howItWorks || t.desc,
path: `/utilities/${t.id}`,
keywords: keywordsFor(t.id),
});
}
export default async function ToolPage({ params }) {
const { tool } = await params;
const result = getToolById(tool);
if (!result) notFound();
const { tool: t } = result;
const faqJsonLd = t.faq?.length
? {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: t.faq.map((item) => ({
'@type': 'Question',
name: item.q,
acceptedAnswer: { '@type': 'Answer', text: item.a },
})),
}
: null;
const appJsonLd = {
'@context': 'https://schema.org',
'@type': 'WebApplication',
name: t.metaTitle || t.name,
description: t.howItWorks || t.desc,
url: `https://www.jakelawrence.xyz/utilities/${t.id}`,
applicationCategory: 'DeveloperApplication',
operatingSystem: 'Web Browser',
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
};
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: buildBreadcrumbJsonLd(`/utilities/${t.id}`) }} />
{faqJsonLd && <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqJsonLd) }} />}
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(appJsonLd) }} />
<ToolPageClient toolId={t.id} />
<div style={{ maxWidth: 860, margin: '0 auto', padding: '0 20px 32px' }}>
<HireCta src="utilities" variant="compact" />
</div>
</>
);
}
Where it lives
- src/utilities/registry.js
- src/app/utilities/[tool]/page.jsx
See it in action
Utilities →FAQ
Do the utilities send my data anywhere?
No — they run entirely in your browser. Nothing leaves your machine.
Part of these stacks
Related systems
Want a system like this built for you?Work with me →