Adios
BlogNext.js Ecommerce

Next.js Ecommerce

How to Configure Next.js Product Page SEO: Metadata, Schema, Images, and Variants

Build an indexable Next.js product page with canonical variant URLs, dynamic metadata, Product JSON-LD, optimized images, and accurate availability.

Adios teamUpdated July 17, 20268 min read

A product page is trustworthy when the canonical URL, visible variant, price, availability, images, structured data, and checkout behavior describe the same purchasable item.

Choose the canonical product model

Trail Supply sells the Alpine Shell in blue and red, with several sizes. The product story is shared; color and size are purchase selections. Its canonical page is /products/alpine-shell. Query parameters may restore a selection for users, but they do not automatically become separate indexable products.

Create variant URLs only when a variant has durable independent value: distinct content, imagery, demand, and internal discovery. Write the rule before implementation, then align redirects, internal links, sitemap entries, metadata, and structured data.

Render the complete product answer

Load the published product and purchasable variants in a Server Component. Render the name, description, price or range, material and fit details, availability explanation, images, shipping or return information, breadcrumbs, and related products. Use Client Components for selection and cart interaction.

Call notFound for an unknown product. For a discontinued product, decide whether historical information, replacement links, and support value justify keeping a successful page. Avoid a successful empty template that simply says the item is gone.

Generate metadata from resolved data

Use the same memoized product query for generateMetadata and the page. Build a specific title and description, canonical product URL, and product image card. A missing or unpublished record should not leak a title through metadata before the page returns not found.

Set metadataBase at the root and use stable image URLs with real dimensions. Product titles should distinguish the item without appending every variant and category keyword. Keep the visible H1 and metadata title semantically aligned.

export async function generateMetadata({ params }) {
  const { slug } = await params;
  const product = await getProduct(slug);
  if (!product) return { title: "Product not found" };

  return {
    title: product.name,
    description: product.seoDescription,
    alternates: { canonical: "/products/" + product.slug },
    openGraph: { images: [product.primaryImage.url] },
  };
}

Build a stable image experience

Store image width, height, alt text, variant association, and sort order with each asset. Use next/image with responsive sizes so the browser can reserve space and request an appropriate resource. Prioritize only the primary above-the-fold image.

Changing color can update the gallery without changing the canonical URL. The initial server render should show the default or requested valid variant, while invalid selection parameters fall back predictably rather than producing empty galleries.

Generate Product and Offer data

Build Product JSON-LD from the same record used by the page. Include real names, images, SKU or product identifiers, brand, and offers that match visible purchase choices. Use the appropriate availability URL and currency. Do not emit reviews or aggregate ratings unless real visible data supports them.

For variants, represent the offer or group model that matches the actual page. A single hard-coded lowest price can mislead when the visible selected variant costs more. If the page displays a range, keep the structured representation and checkout path consistent with that range.

const offers = product.variants
  .filter((variant) => variant.active)
  .map((variant) => ({
    "@type": "Offer",
    sku: variant.sku,
    price: variant.price.amount,
    priceCurrency: variant.price.currency,
    availability: variant.inStock
      ? "https://schema.org/InStock"
      : "https://schema.org/OutOfStock",
  }));

Build category and breadcrumb relationships

Link the Alpine Shell from its canonical jacket category, relevant editorial guides, and selected product recommendations. Use descriptive anchor text and visible breadcrumbs. Generate BreadcrumbList JSON-LD from that same canonical hierarchy.

A sitemap supports discovery but does not replace site architecture. Important products should be reachable through ordinary links. Keep redirected, noindex, unpublished, and noncanonical variant URLs out of product sitemaps.

Test edge product states

Test an unknown slug, discontinued product, missing image, one unavailable variant, every unavailable variant, a changed price, a selected query parameter, and a renamed slug. Compare raw HTML with hydrated output and validate the JSON-LD from the actual response.

Adios lets Trail Supply test those states on the production build behind a generated HTTPS route. Inspect build and runtime logs, verify the health route, then promote the release to the canonical custom domain with managed TLS.

  All articles