JSON-LD

Structured Data

JSON-LD tells Google exactly what a page is about (a product with a price, rating, availability). It enables rich results: stars and price shown directly in search. Render it as a script tag in the page:

export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const product = await getProduct(Number((await params).id));
  if (!product) notFound();

  const jsonLd = productJsonLd(product);
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, '\\u003c') }}
      />
      <h1>{product.name}</h1>
    </>
  );
}

Note: The replace(/</g, ...) escapes < so a product name containing </script> cannot break out of the tag (XSS).

Building the Object

Example

type Product = { id: number; name: string; price: number; stock: number; rating: number; reviews: number; image: string };

function productJsonLd(p: Product) {
  return {
    '@context': 'https://schema.org',
    '@type': 'Product',
    name: p.name,
    image: p.image,
    offers: {
      '@type': 'Offer',
      price: p.price.toFixed(2),
      priceCurrency: 'INR',
      availability: 'https://schema.org/' + (p.stock > 0 ? 'InStock' : 'OutOfStock'),
    },
    aggregateRating: { '@type': 'AggregateRating', ratingValue: p.rating, reviewCount: p.reviews },
  };
}

const ld = productJsonLd({ id: 42, name: 'Redmi Note 14 5G', price: 17999, stock: 12, rating: 4.3, reviews: 12480, image: 'https://cdn.shopease.in/p/42.jpg' });
console.log(JSON.stringify(ld, null, 2));

Output

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Redmi Note 14 5G",
  "image": "https://cdn.shopease.in/p/42.jpg",
  "offers": {
    "@type": "Offer",
    "price": "17999.00",
    "priceCurrency": "INR",
    "availability": "https://schema.org/InStock"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 4.3,
    "reviewCount": 12480
  }
}