All components (204)
Page SEO
More · JsonLd
What it is and when to use it
Everything a page needs for search engines and social networks to understand it, in @amset/ui/seo: the metadata (title, description, canonical, Open Graph, X card, robots), the schema.org structured data, the sitemap.xml and the robots.txt. It runs on the server, carries no 'use client', ships no CSS and adds no JavaScript to the browser: JsonLd is the only component and it is a server component.
import { JsonLd, jsonLdGraph, organization, pageMetadata, webPage, webSite } from '@amset/ui/seo'
// app/anillos/page.tsx (Next, App Router)
export function generateMetadata() {
return pageMetadata({
siteUrl: 'https://aurelia.example',
siteName: 'Joyería Aurelia',
title: 'Anillos de oro artesanales',
description: 'Anillos de oro de 18 quilates hechos a mano…',
path: '/anillos',
image: { url: '/og/anillos.jpg', alt: 'Tres anillos de oro', width: 1200, height: 630 },
})
}
export default function Page() {
return <JsonLd data={jsonLdGraph(organization(…), webSite(…), webPage(…))} />
}
// app/sitemap.ts → sitemapEntries(siteUrl, páginas)
// app/robots.ts → robotsRules({ siteUrl, blockAll: process.env.VERCEL_ENV !== 'production' })When to use it
- On every public page:
pageMetadataingenerateMetadataand aJsonLdwith the page graph. The result ofpageMetadatais the NextMetadataas is, with no conversion. checkSeoin a test or in CI: it returns warnings (a title that gets cut, a short description, an image without dimensions) and errors that prevent publishing.robotsRules({ blockAll: true })inpreand in any environment that is not production: an indexed test copy competes with the real one.
When not to
- For an application screen behind the login: there is nothing to index there (
noindex). - Outside Next:
pageMetadatareturns an object with the same shape, but writing the<meta>tags is up to the project;sitemapXmlandrobotsTxtdo give you the files.
What it validates and what it does not let through: pageMetadata throws SeoError (with the list of issues) if the title or the description is missing, siteUrl is not absolute, the path does not start with "/", the image has no alternative text or a date is not ISO 8601. The JSON-LD builders throw on a headline longer than 110 characters, a negative price, a currency that is not ISO 4217, an article without an author or a search template without {search_term_string}. sitemapEntries throws on repeated addresses, priorities outside 0–1 and more than 50,000 entries. Failing at build time is on purpose: a page without a description should not reach production.
Security: serializeJsonLd escapes <, >, & and the Unicode line separators. A text with </script> (a product name typed by a user) cannot close the tag or inject HTML. JsonLd accepts the nonce of the site security policy.
Keyboard and accessibility: it draws nothing visible, so it has no keyboard. The alternative text of the social image is mandatory, and the title and the description are what a screen reader reads when the tab opens.
Fine-tuning: it has none; it draws nothing.
What it looks like
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "https://aurelia.example/#organization",
"name": "Aurelia Jewelry",
"url": "https://aurelia.example/"
}
]
}<JsonLd
data={jsonLdGraph(organization({ name: 'Aurelia Jewelry', url: 'https://aurelia.example' }))}
/>Props
Import it with import { JsonLd } from '@amset/ui/seo'. Required props are marked.
| Prop | Type | What it does |
|---|---|---|
datarequired | JsonLdDocument | readonly JsonLdDocument[] | — |
nonce | string | El `nonce` de la politica de seguridad del sitio, si la tiene. |
In the test bench
Every state and variant, to try one at a time, on its page at ui.amset.tech:
