SEO & Meta Tags

Meta descriptions, Open Graph tags for social previews, canonical URLs, and structured data with JSON-LD.

Why <head> metadata matters beyond the browser tab

The introduction page in this track covered <title> and the viewport meta tag. There's a second layer of <head> metadata that never renders on the page at all, but directly shapes how a page appears in search results and when it's shared as a link on social media or in a chat app. None of it is required for a page to work — but skipping it means search engines and link-preview crawlers are left guessing at what the page is about.

The meta description

HTML
<meta name="description" content="Learn CSS Grid from scratch — template columns and rows, gap, named areas, and a full dashboard layout example.">

Search engines don't always use it verbatim (they sometimes generate a snippet from page content instead), but it's still the single most common source for the gray summary text shown under a search result's blue link. Keep it to roughly 150–160 characters — most search engines truncate beyond that — and write a genuine, specific summary of the page rather than a generic tagline repeated across every page on the site.

HTML
<meta name="robots" content="noindex, nofollow">

robots tells crawlers whether to index a page and whether to follow its links at all — useful for a staging environment, an internal admin page, or a duplicate/thank-you page you don't want appearing in search results.

Open Graph (originally a Facebook-authored standard, now used broadly by Slack, Discord, LinkedIn, iMessage, and most other platforms that render a link preview card) is a set of og:* meta tags describing how a URL should be represented when shared:

HTML
<meta property="og:title" content="CSS Grid — Full Tutorial">
<meta property="og:description" content="Learn CSS Grid from scratch, including a complete dashboard layout example.">
<meta property="og:image" content="https://noalabs.dev/images/css-grid-preview.png">
<meta property="og:url" content="https://noalabs.dev/tutorials/css/grid">
<meta property="og:type" content="article">
Tag Purpose
og:title The headline shown on the preview card — can differ from <title> if a shorter, punchier version reads better as a card headline.
og:description The card's body text.
og:image The preview thumbnail. Aim for at least 1200×630px — most platforms crop or reject smaller images.
og:url The canonical URL the card should link to, regardless of what URL variant (with tracking params, a trailing slash, etc.) was actually shared.
og:type What kind of content this is (website, article, product) — some platforms adjust the card layout based on it.

Twitter/X reads its own twitter:* tags first, falling back to Open Graph tags if they're absent — so it's worth adding a minimal Twitter Card block alongside Open Graph rather than assuming OG alone covers every platform:

HTML
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="CSS Grid — Full Tutorial">
<meta name="twitter:description" content="Learn CSS Grid from scratch, including a complete dashboard layout example.">
<meta name="twitter:image" content="https://noalabs.dev/images/css-grid-preview.png">

Canonical URLs

HTML
<link rel="canonical" href="https://noalabs.dev/tutorials/css/grid">

A canonical URL tells search engines "if you find this same content reachable at several different URLs, treat this one as the authoritative version." This matters more than it might seem — the same page is often reachable through more than one URL without anyone intending it: https:// vs a legacy http:// redirect, with and without a trailing slash, with tracking query parameters (?utm_source=twitter) appended, or a paginated/filtered view of content that's otherwise identical to the main page. Without a canonical tag, a search engine may treat these as separate, competing pages — diluting ranking signals that should all be consolidated onto one URL — or simply pick whichever version it happens to have crawled first, which might not be the one you'd choose.

Structured data with JSON-LD, briefly

Structured data is a machine-readable description of a page's content, embedded using the schema.org vocabulary — most commonly as a <script type="application/ld+json"> block. It's what powers "rich results" in search — star ratings under a recipe, a FAQ dropdown directly in search results, an event's date and venue shown inline:

HTML
<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "CSS Grid — Full Tutorial",
    "author": {
        "@type": "Organization",
        "name": "NOA Labs"
    },
    "datePublished": "2026-08-26"
}
</script>

This isn't rendered visually at all — it exists purely for machines parsing the page. A full treatment of schema.org's vocabulary (there are types for articles, products, recipes, events, FAQs, and dozens more, each with their own expected fields) is a large topic on its own; the takeaway here is just that this is the mechanism, JSON-LD is the format search engines now prefer over the older inline itemprop microdata syntax, and it's additive — it never replaces writing good visible content, only supplements it with an explicit, structured summary a crawler doesn't have to guess at.

A complete example <head>

HTML
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS Grid — Full Tutorial | NOA Labs</title>
    <meta name="description" content="Learn CSS Grid from scratch — template columns and rows, gap, named areas, and a full dashboard layout example.">
    <link rel="canonical" href="https://noalabs.dev/tutorials/css/grid">

    <meta property="og:title" content="CSS Grid — Full Tutorial">
    <meta property="og:description" content="Learn CSS Grid from scratch, including a complete dashboard layout example.">
    <meta property="og:image" content="https://noalabs.dev/images/css-grid-preview.png">
    <meta property="og:url" content="https://noalabs.dev/tutorials/css/grid">
    <meta property="og:type" content="article">

    <meta name="twitter:card" content="summary_large_image">
</head>

Common mistakes

  • Writing one generic <meta name="description"> and copy-pasting it across every page on a site — search engines and social previews then show the same summary regardless of what page was actually shared, which looks broken and hurts click-through.
  • Forgetting og:image — many platforms fall back to rendering a link with no thumbnail at all, which gets noticeably less engagement than a card with a real preview image.
  • Setting a canonical URL that points somewhere other than the page itself by accident (a common copy-paste bug across templated pages) — this actively tells search engines to ignore the current page in favor of a different one.
  • Assuming JSON-LD structured data guarantees a rich result — it makes a page eligible, but search engines still decide independently whether and how to display any enhanced result.