HTML Metadata Best Practices
You have now met every element that lives in the head. Each one is small. The skill is in putting them together: in the right order, with the right values, and without the mistakes that quietly cost a site its visitors.
This lesson is your capstone for the section. It gives you a complete template you can reuse, a checklist to review any page, and the tools to test the result. Keep it close, and use it every time you start a new site.
What You Will Learnβ
- A complete head template, in a sensible order
- A checklist by area: essentials, search, sharing, performance, accessibility, security, and global audiences
- What belongs site-wide, and what must be different on every page
- Common conflicts and duplicates
- Tools to test your head, and how to keep it correct over time
The Big Ideaβ
- HTML Code
- Head Generator
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 1. Encoding and viewport -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 2. Title and description, unique on every page -->
<title>Sourdough for Beginners | The Bread Bin</title>
<meta name="description" content="A gentle, step-by-step guide to baking your first sourdough loaf.">
<link rel="canonical" href="https://example.com/sourdough">
<!-- 3. Browser hints -->
<meta name="theme-color" content="#1d4ed8">
<meta name="color-scheme" content="light dark">
<!-- 4. Link previews -->
<meta property="og:type" content="article">
<meta property="og:title" content="Sourdough for Beginners">
<meta property="og:description" content="A gentle guide to your first loaf.">
<meta property="og:url" content="https://example.com/sourdough">
<meta property="og:image" content="https://example.com/images/sourdough-1200x630.jpg">
<meta property="og:image:alt" content="A golden loaf on a wooden board">
<meta name="twitter:card" content="summary_large_image">
<!-- 5. Icons and manifest -->
<link rel="icon" href="/favicon.ico" sizes="32x32">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/manifest.webmanifest">
<!-- 6. Styles first, then scripts -->
<link rel="stylesheet" href="/css/site.css">
<script src="/js/app.js" defer></script>
</head>
<body>
<h1>Sourdough for Beginners</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sourdough for Beginners | The Bread Bin</title>
<meta name="description" content="A gentle, step-by-step guide to baking your first sourdough loaf.">
<link rel="canonical" href="https://example.com/sourdough">
<meta name="theme-color" content="#1d4ed8">
<meta name="color-scheme" content="light dark">
<meta property="og:type" content="article">
<meta property="og:title" content="Sourdough for Beginners">
<meta property="og:description" content="A gentle, step-by-step guide to baking your first sourdough loaf.">
<meta property="og:url" content="https://example.com/sourdough">
<meta property="og:site_name" content="The Bread Bin">
<meta property="og:image" content="https://example.com/images/sourdough-1200x630.jpg">
<meta property="og:image:alt" content="Describe the picture here">
<meta name="twitter:card" content="summary_large_image">
<link rel="icon" href="/favicon.ico" sizes="32x32">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/manifest.webmanifest">
<link rel="stylesheet" href="/css/site.css">
<script src="/js/app.js" defer></script>
</head>
<body>
<!-- Your page goes here -->
</body>
</html>
Edit the fields above, then copy the result.
This is a starting point. The file names for the icons, manifest, stylesheet and script are examples, so change them to match your own files, and write real alternative text for the share image.
Use the generator to create a head for your own page, and paste it in as a starting point.
The Order, and Whyβ
| Step | What | Why here |
|---|---|---|
| 1 | charset, viewport | The browser needs the encoding before it reads text, and the width before it lays anything out |
| 2 | title, description, canonical | The most important facts about the page, near the top |
| 3 | theme-color, color-scheme | Hints the browser can use early, to avoid flashes of the wrong colour |
| 4 | Link-preview tags | Read by apps that often only scan the start of the page |
| 5 | Icons and manifest | Not urgent, but grouped together |
| 6 | Stylesheets, then scripts with defer | Styles first, so the page is painted once. Scripts last, so they do not hold it up |
If you have a <base> element, it goes very early, before anything that uses a relative address. If you have preconnect hints, put them before the files that will use those connections.
Site-Wide and Page-Specificβ
Some metadata is the same on every page. Some must be different.
| Same on every page | Different on every page |
|---|---|
charset, viewport | title |
lang (for a single-language site) | description |
| Icons, manifest | canonical address |
| Stylesheets and scripts | Link-preview title, description, and image |
theme-color, color-scheme | lang and hreflang links for translated pages |
Build your layout template once with the shared parts, and give each page its own values for the second column. That is how every well-built site stays consistent.
The Master Checklistβ
Essentialsβ
-
<!DOCTYPE html>is the very first thing -
<html lang="β¦">matches the real language (anddir="rtl"where needed) -
<meta charset="utf-8">is within the first 1024 bytes - A responsive
viewporttag - One
<title>per page - Every element in the head is one that is allowed there
Searchβ
- A unique, descriptive title, with the specific part first (about 50 to 60 characters)
- A unique description, written for people (about 120 to 160 characters)
- A full-address
canonicallink when the same page has several addresses - No accidental
noindex -
hreflanglinks, reciprocal and withx-default, for translated pages - Structured data (JSON-LD) where it fits, built safely
Sharingβ
- Open Graph title, description, URL, and image, with full
httpsaddresses - A share image of a suitable size (about 1200 by 630 pixels is a common recommendation), with alt text
- A favicon set: SVG, ICO, Apple touch icon, and manifest icons
Performanceβ
- Styles linked before scripts
- Scripts use
defer,async, ortype="module" - Only a few
preloadandpreconnecthints, each measured - Critical CSS is small. No
@importchains - No unused or duplicate files
Accessibilityβ
- Zoom is never blocked
-
langis correct, including on passages in other languages - The title describes the page, and changes with each view in a single-page app
- No automatic
refresh -
color-schemeandprefers-*settings are respected - The page works if a stylesheet or script fails to load
Security and Privacyβ
- No secrets in comments, meta tags, or scripts
- External files use
https,integrity, andcrossorigin - A Content-Security-Policy (preferably a header), including
base-uri - No unneeded
<base>element - Everything dynamic is escaped
- A considered
referrerpolicy - Consent is handled before loading tracking scripts, where the law requires it. This is not legal advice
Global Audiencesβ
- UTF-8 throughout, and a font that covers your scripts
- Titles and descriptions are written in the page's language
- A visible language switcher, with
hreflanglinks behind it - A lean head for slow connections
- Previews, titles, and images tested in more than one language
Audit a Pageβ
Paste any page (or just its head) into the auditor. It checks many of the items above, using the browser's real HTML parser, and gives each a result. The starting sample has several deliberate problems. Fix them one at a time, and watch the score rise.
- HTML Code
- Head Auditor
<!DOCTYPE html>
<html>
<head>
<title>Sourdough</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="description" content="Bread.">
<link rel="stylesheet" href="/css/site.css">
<script src="/js/app.js"></script>
</head>
Common Conflicts and Duplicatesβ
| Problem | What happens | Fix |
|---|---|---|
Two <title> elements | Only the first is used | Keep one |
| Two descriptions | Search engines pick one, unpredictably | Keep one |
title and og:title disagree | The tab and the share card say different things | Make them similar, even if not identical |
canonical points to another page | The page may drop out of search results | Point it to itself, or to the true original |
noindex plus a canonical | Mixed signals | Choose one purpose |
| Two viewports | Behaviour depends on the browser | Keep one |
| A header charset differs from the meta charset | The header usually wins | Make them match |
| Something invalid in the head | The head ends early, and later tags land in the body | Remove it |
| Tags added by script and written by hand | Duplicates | Choose one source |
Structured Dataβ
Structured data tells search engines exactly what your page is: an article, a product, an event, a recipe. The usual format is JSON-LD in a data script block:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Sourdough for Beginners",
"datePublished": "2026-10-20",
"author": { "@type": "Person", "name": "Ravi" }
}
</script>
Rules: describe only what is really visible on the page, keep the values accurate, and encode < as < when a server builds it from data. Search engines decide whether to use it, and what to show.
Test, Do Not Guessβ
You can see most problems in minutes if you use the right tools:
| Need | Tool |
|---|---|
| See what the browser really received | View source, and the Elements and Network panels in developer tools |
| Check that the HTML is valid | The W3C validator |
| Check speed, accessibility, and basic search readiness | Lighthouse (built into Chrome's developer tools) |
| Check how search engines see a live page | The search engine's webmaster tools (for example, Google Search Console), and their inspect-a-URL features |
| Check structured data | The search engines' structured data testing tools |
| Check link previews | The platforms' sharing debuggers (they also let you clear a cached preview) |
| Check on real devices | A real phone, a slow connection setting, and a screen reader |
| Catch problems before launch | Automated checks in your build (HTML linters, Lighthouse in continuous integration) |
Tool names and addresses change, so search for the current official one when you need it.
Keeping It Correct Over Timeβ
- Generate the head from one template, instead of copying it to each page.
- Store page values (title, description, image) with the page's content, such as in frontmatter, so writers cannot forget them.
- Review the head whenever you redesign, move domains, or add a language.
- Check live pages after each release for a leftover
noindex, a staging address incanonical, or a missing title. - Add automated checks so a mistake fails the build, rather than reaching visitors.
In Docusaurusβ
Most of this is already wired up for you:
| You want | Where it comes from |
|---|---|
| Title and description | The page's frontmatter title and description |
| Keywords | Frontmatter keywords (search engines largely ignore them, but they are harmless) |
| Share image | Frontmatter image, and themeConfig.image for a site-wide default |
| Favicon | favicon in docusaurus.config.js |
| Extra tags | headTags, stylesheets, scripts, or @docusaurus/Head |
| Language and translations | The i18n settings |
Canonical and hreflang | Generated by Docusaurus from your url, baseUrl, and locales |
Always open a built page's source to confirm what was produced, instead of trusting the configuration alone.
Good Habitsβ
- Start every project from the same, reviewed head template.
- Write unique titles and descriptions for every page.
- Never block zoom, never use
refresh, and never leave a straynoindex. - Put styles before scripts, and defer your scripts.
- Use full
httpsaddresses for canonical,hreflang, and share images. - Add
integrity, a CSP, andbase-uri. - Test with real tools and on real devices.
- Automate the checks, and review after every big change.
Accessibility Checklistβ
- The title identifies the page, and is unique within the site.
-
langis set and correct, includingdir="rtl"where needed. - The viewport allows zoom.
- No automatic redirects or refreshes without the user's control.
- Share images have alt text.
- Icons and
theme-colorkeep good contrast. - The page remains usable if scripts or styles fail.
- You have tested with a screen reader and the keyboard.
Security and Privacy Notesβ
- Review the head as public code. Anyone can read it, and so can automated scanners. Remove anything that should not be public.
- Prefer a Content-Security-Policy sent as a header, with
script-src,style-src, andbase-uri. A meta tag is a weaker second choice. - Treat every external file as a trust decision. Pin versions, use
integrity, and host important files yourself. - Early connections (
preconnect,prefetch) and third-party fonts and scripts can reveal visits to other companies. Choose them with care. - Be careful with fingerprinting. Do not collect screen sizes, fonts, and other details without a reason.
- Do not publish staging metadata. A staging site that is not blocked by a login and has no
noindexcan be indexed and leak unreleased work. noindexis not security. Use real authentication for private pages.
Global Audience Notesβ
- One language, one set of tags. Each language version has its own title, description, preview text,
lang, andhreflanglinks. - Test with long and short languages. Titles in German or Finnish can be much longer than in English, and Chinese, Japanese, or Korean ones can be much shorter, but wider per character.
- Check right-to-left pages end to end, including previews and icons.
- Do not guess a visitor's language from their country. Offer a switcher.
- Make the head light. Most visitors worldwide use mid-range phones on variable networks.
- Use images and colours that work across cultures, and give every image real alternative text in the page's language.
Common Mistakes to Avoidβ
- A different-looking head on every page, because it was copied by hand.
- The same title and description everywhere.
- A staging
noindexor stagingcanonicalthat reaches production. - Relative addresses in canonical,
hreflang, and share tags. - Blocking zoom.
- Scripts before styles, with no
defer. - Stuffing keywords.
- Trusting a score instead of reading the real result.
- Forgetting to retest after a redesign.
- Secrets in comments or in metadata.
- Conflicting signals, such as
noindexpluscanonical. - Leaving everything to a plugin, and never reading the output.
Practice Timeβ
Try these in your editor:
- Use the generator to make a head for a page of your own, and save it as a template.
- Paste your real site's head into the auditor, and fix the first three problems.
- Open View Source on your three favourite sites, and compare their heads with the template.
- Run Lighthouse on one of your pages, and read each metadata-related message.
- Check your page with the W3C validator, and fix every error.
- Test a link to your page in a chat app, and then change the image and see how the preview updates.
- Add JSON-LD to an article page, and check it with a structured data test.
- Add a Content-Security-Policy header with
base-uri, and see what breaks. - Make a translated copy of a page with
lang,hreflang, and a translated title and description. - Bonus: write a short script or build step that fails if a page has no title, no description, or a
noindex.
Quick Recapβ
Click a question to check your answer.
1. What goes first in the head, and why?
charset and viewport: the browser needs the encoding before it reads text, and the width before it lays the page out. Then the title, description, and other metadata, then styles, then deferred scripts.
2. Which metadata must be different on every page?
The title, the description, the canonical address, and the link-preview tags (and, for translations, lang and hreflang).
3. Name three accessibility rules for the head.
Never block zoom, set a correct lang, and give every page a unique, descriptive title. Also avoid automatic refresh, and keep the page usable if a script or style fails.
4. How do you reduce the risk of a hijacked base element?
Avoid using <base>, and add base-uri to your Content-Security-Policy, ideally sent as a header.
5. Why test with real tools?
A checklist or score cannot tell if your title is helpful, if a preview looks right, or how real search engines and devices behave. View source, validators, Lighthouse, sharing debuggers, and real phones show what visitors get.
6. What is the best way to keep heads consistent?
Generate them from one template, store each page's own title, description, and image with its content, and add automated checks to your build.
Key Takeawaysβ
- A good head is complete, ordered, and specific to each page.
- The order: charset and viewport, title and description, hints, previews, icons, styles, then deferred scripts.
- Share the common parts through a template, and give each page its own title, description, canonical address, and preview.
- Work through the checklist for essentials, search, sharing, performance, accessibility, security, and global audiences.
- Never block zoom, never leave a stray
noindex, and keep secrets and untrusted files out. - Test with real tools and on real devices, and automate the checks so mistakes cannot reach visitors.
Congratulations. You have finished the HTML Head section. You can now read any page's head, build a strong one from scratch, and spot the mistakes that quietly hurt visitors, search results, and security. Continue with the next section in the sidebar, and keep the master checklist handy for every project.