Documentation
SEO and sharing
One seo() call for search engines, every social network, and rich results.
Metadata is a lot of tags to remember and easy to get subtly wrong. seo() takes one object and emits only what you filled in — every field is optional, and an omitted field produces no tag rather than an empty one.
export function head() {
return seo({
title: "Java Quiz",
description: "Practice Java questions online.",
canonical: "https://example.com/quiz/java",
});
}<title>Java Quiz</title>
<meta name="description" content="Practice Java questions online.">
<link rel="canonical" href="https://example.com/quiz/java">Three fields in, three tags out. It is a convenience over writing them yourself, never a gate in front of them — the result is an ordinary fragment, so hand-written tags sit beside it in the same head.
There are only three audiences
The list of networks is long; the list of protocols is not. Knowing which is which is most of the work.
Open Graph Facebook, Instagram, LinkedIn, WhatsApp,
Slack, Discord, Telegram, Signal, Pinterest,
iMessage, Teams
-> openGraph: { ... }
twitter:* X (renamed the company, not the markup)
-> x: { ... }
Google title, description, canonical, robots
+ schema.org for rich results
-> jsonLd: { ... }There is no instagram or linkedIn option because there would be nothing to put in one. Both read Open Graph and neither defines tags of its own — Instagram has no link-preview protocol at all.
The fuller shape
seo({
title: "Java Quiz",
description: "Practice Java questions online.",
canonical: "https://example.com/quiz/java",
openGraph: {
image: "/images/java-quiz.png", // made absolute for you
imageWidth: 1200,
imageHeight: 630,
siteName: "Example",
type: "article",
article: { publishedTime: "2026-08-13", authors: [".../ada"] },
},
x: { card: "summary_large_image", site: "@example" },
robots: { index: true, follow: true, maxImagePreview: "large" },
alternates: [{ hreflang: "fr", href: "https://example.com/fr/quiz" }],
jsonLd: { "@context": "https://schema.org", "@type": "Quiz", name: "Java Quiz" },
})Four things it does for you
- Relative image paths become absolute, against canonical or the current origin. A relative og:image is dropped by most crawlers, and the failure is invisible until someone shares the link.
- Open Graph tags use property, not name. Writing name="og:title" is the most common mistake in hand-written metadata and it silently does nothing.
- og:title, og:description, twitter:title and the rest fall back to the top-level values, so the common case is written once rather than three times.
- The card type defaults to summary_large_image when there is an image and summary when there is not — a large-image card with no image renders as a bare link.
Structured data
jsonLd is the lever for Google rich results — star ratings, breadcrumbs, FAQ accordions, recipe cards. None of the meta tags above can produce them; only schema.org can.
It is serialized into a application/ld+json block, which browsers parse as data and never execute — the same mechanism the island payload uses, and the reason it needs no CSP exception. The serializer escapes <, > and the line separators, so a value cannot close the element and inject markup.
Something wrong in the framework itself rather than the page? Open an issue on GitHub.