We build the unglamorous half of the web.
Metadata, preview cards, favicons. Nobody puts them on a roadmap, everybody notices when they break.
Why this exists
SiteAssets started as a five-line curl script that checked whether a page had an og:image before shipping a launch. The script kept being copied between projects, and the copy kept drifting — different checks, different opinions about what counts as “good”.
The product is the script with one opinion, written down: a weighted rule set, the same code behind every surface, and a report that tells you which tag to change rather than which rule you broke.
It is deliberately unglamorous work. Social previews break in the seams between your CDN, your framework and somebody else’s crawler, and those seams are where we spend our time.
What we optimise for
Deterministic over clever
The same URL produces the same score, on the website, the API and the MCP server. One rule engine, one weight table, no per-surface special cases.
Fetch like a crawler
We read server-rendered HTML and nothing else. No headless browser, no injected tags — because that is exactly what social crawlers see.
Explain the fix
A score without a reason is noise. Every failing check ships with the exact tag to add and a copy-paste snippet for it.
Small surface area
Few dependencies, four generator templates, a documented API. Less surface means fewer ways for the tool to be wrong about your site.
Under the hood
The score engine lives in src/lib/checker
and is the same code that powers the website, the REST API, the MCP server and the test suite. If the
docs and the product ever disagree, the product is right.
Framework Astro 5 (server output, Node adapter)
Styling Tailwind CSS v4 with oklch design tokens
Rendering Satori → Resvg → Sharp
Parsing cheerio
Auth + data managed Postgres
Payments merchant of record (no card data on our servers)
Agents Model Context Protocol What we build
Built in the open.
Every change ships to the website, the API and the MCP server at once, and every change is written down.