DEV Community

Cover image for Meta Tags That Matter: A Developer's Guide to Title and Description Tags
Jay Barker
Jay Barker

Posted on

Meta Tags That Matter: A Developer's Guide to Title and Description Tags

I've seen more than once. A team ships a shiny new page template, everything looks great in the browser, and a week later someone notices that every product page in Google is titled "Home | Company." Nobody broke the layout. Nobody broke the tests. The <title> just quietly fell back to a default, on thousands of pages.

Meta tags are tiny, invisible in the UI and almost never tested, which makes them one of the easiest parts of a site to break. In this guide, I'll cover which meta tags actually matter in 2026, what Google really does with your titles and descriptions (with data, not folklore), how to implement them properly in common stacks, and how to test them so this class of bug never reaches production. A meta tag analyzer is the quickest way to see what you're actually shipping, and I'll show you how to automate the same checks in CI.

Disclosure: I work with the team behind SEO Site Checker, whose meta tag analyzer I mention below. Everything else in this guide is tool-agnostic.

The Short Version

If you only read one section, make it this one:

  • Give every page a unique <title> of roughly 50 to 60 characters that agrees with the page's H1.
  • Give every important page a unique meta description of roughly 150 to 160 characters.
  • Get robots, viewport and charset right. Breaking these hurts more than any badly worded title.
  • Ignore meta keywords. Google doesn't use it.
  • Render meta tags on the server and test them in CI, not just by eye.

Which Meta Tags Actually Matter in 2026

There are dozens of possible <meta> tags. Very few of them change anything. Here's the shortlist:

Tag What it does Affects rankings? Priority
<title> Main input for the title link in search results Yes High
meta name="description" Often used for the snippet under the title No, but affects clicks High
meta name="robots" / X-Robots-Tag Controls indexing and snippets Can remove you entirely Critical
meta name="viewport" Controls mobile rendering Indirectly High
meta charset Makes text render correctly Indirectly High
link rel="canonical" Points to the preferred URL Consolidates signals High
Open Graph and Twitter cards Social and chat link previews No Medium
hreflang links Language and region versions For multilingual sites Situational
meta name="keywords" Nothing, as far as Google is concerned No None

Strictly speaking, canonical and hreflang are <link> elements, not meta tags, but every audit checks them alongside the rest, so I've included them.

Title Tags: What Google Actually Does With Them

Google builds "title links," and your title tag is only one input

The first thing to understand is that Google doesn't simply display your <title>. It generates what it calls a title link, and Google's documentation on title links lists the sources it can draw from: the <title> element, the main visible heading, og:title, other large and prominent text on the page, anchor text, and the text of links pointing to the page.

In practice, your title tag still wins most of the time. Ahrefs' study of 953,276 title tags found Google used the original title for about two-thirds of top-ranking pages and rewrote the other 33.4%. When it did rewrite, it pulled from the page's H1 about half the time. That's a strong hint: if your <title> and your H1 disagree, Google may pick the H1.

Length is about pixels, not characters

Google doesn't publish a character limit. It truncates title links to fit the device width, which works out to roughly 600 pixels on desktop. Because characters vary in width (a "W" is much wider than an "i"), there's no perfect character count, but 50 to 60 characters is a safe range for most titles.

Length also seems to affect rewrites. In the same Ahrefs study, titles wider than 600 pixels were rewritten 46.12% of the time, well above the overall rate. Long titles don't just get cut off. They get replaced.

Writing rules that survive rewrites

  • Be descriptive and concise. Say what the page is, not what the site is.
  • Front-load the main topic, so it survives truncation.
  • Make every title distinct. Sibling pages shouldn't differ by a single word.
  • Put the brand at the end, after a delimiter like | or -, unless it's your homepage.
  • Keep the <title> consistent with the H1. They don't need to be identical, but they should clearly describe the same thing.
  • Don't stuff keywords or repeat the same phrase.

Why Google rewrites your title

Google is unusually specific about this. Its documentation lists the problems that trigger a rewrite: half-empty titles, obsolete titles (an old year left in a recurring page), inaccurate titles, "micro-boilerplate" where sibling pages share near-identical titles, no clear main heading, a language mismatch between the title and the content, and a duplicated site name. Almost every one of these is a template bug, which means it's fixable in code.

A template pattern that works

Here's a small title builder with sensible fallbacks. It tries the most specific version first and drops segments until the title fits:

const BRAND = 'Acme Tools';
const MAX_LENGTH = 60;

export function buildTitle({ page, section }) {
  const candidates = [
    [page, section, BRAND],
    [page, BRAND],
    [page],
  ];

  for (const parts of candidates) {
    const title = parts.filter(Boolean).join(' | ');
    if (title.length <= MAX_LENGTH) return title;
  }

  // Last resort: trim the page name at a word boundary
  return page.slice(0, page.lastIndexOf(' ', MAX_LENGTH)).trim();
}

buildTitle({ page: 'Cordless Drill 18V', section: 'Power Tools' });
// "Cordless Drill 18V | Power Tools | Acme Tools"
Enter fullscreen mode Exit fullscreen mode

The important part isn't the code. It's that the title is generated from real page data, with a deliberate fallback, instead of silently defaulting to the site name.

Meta Descriptions: Do They Still Matter?

Google rewrites most of them, so write them anyway

Here's the uncomfortable truth. Ahrefs' meta description study found Google rewrote 62.78% of meta descriptions, because it tailors snippets to each search query. A quarter of top-ranking pages didn't even have one.

So why bother? Because when your description is shown, it's your pitch in the search results, and a good one earns the click. It's also what most social platforms and chat apps fall back on for link previews. Google's guidance on meta descriptions says it uses them when they describe the page more accurately than the on-page text, which is a good reason to write them well.

Length

Again, there's no official limit. Snippets are truncated to fit the screen, commonly measured at around 920 pixels on desktop. Aim for roughly 150 to 160 characters, and put the key message in the first 120 or so, since mobile results often show less.

Writing rules

  • Make each one unique. Duplicate descriptions across a site are a missed opportunity.
  • Summarize the whole page, not just the first paragraph.
  • Include useful specifics, like price, date, author, availability or location.
  • Skip keyword lists. Google explicitly advises against them.
  • Match the searcher's intent. Tell them what they'll get by clicking.

Generating them programmatically

For large, database-driven sites, writing every description by hand isn't realistic, and Google says generated descriptions are fine as long as they're readable and varied. Build them from real fields, with a clean fallback:

const stripHtml = (s) => s.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();

function truncate(text, max) {
  if (text.length <= max) return text;
  return text.slice(0, text.lastIndexOf(' ', max - 1)) + '…';
}

export function productDescription(p) {
  const parts = [
    `${p.name} by ${p.brand}`,
    p.price && `from $${p.price}`,
    p.keyBenefit,
  ].filter(Boolean);

  let text = parts.join(', ') + '.';

  // Too thin? Fall back to a cleaned excerpt of the product copy
  if (text.length < 70 && p.body) text = stripHtml(p.body);

  return truncate(text, 160);
}
Enter fullscreen mode Exit fullscreen mode

Implementing Meta Tags in Your Stack

Plain HTML

For reference, here's a complete, correct <head> for a typical page. Note that charset comes first, within the first 1024 bytes of the document:

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Cordless Drill 18V | Power Tools | Acme Tools</title>
  <meta name="description" content="Lightweight 18V cordless drill with two batteries and a 3-year warranty. Free shipping on orders over $50.">
  <link rel="canonical" href="https://example.com/products/cordless-drill-18v">
  <meta property="og:title" content="Cordless Drill 18V | Acme Tools">
  <meta property="og:description" content="Lightweight 18V cordless drill with two batteries and a 3-year warranty.">
  <meta property="og:image" content="https://example.com/images/drill-og.jpg">
  <meta name="twitter:card" content="summary_large_image">
</head>
Enter fullscreen mode Exit fullscreen mode

Next.js App Router

Next.js has a built-in Metadata API, and it handles most of this for you. Set a title template and a base URL once in the root layout:

// app/layout.tsx
import type { Metadata } from 'next';

export const metadata: Metadata = {
  metadataBase: new URL('https://example.com'),
  title: { default: 'Acme Tools', template: '%s | Acme Tools' },
  description: 'Quality power tools with free shipping on orders over $50.',
};
Enter fullscreen mode Exit fullscreen mode

Then generate page-specific metadata for dynamic routes:

// app/products/[slug]/page.tsx
import type { Metadata } from 'next';

type Props = { params: Promise<{ slug: string }> };

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params;
  const product = await getProduct(slug);

  return {
    title: product.name, // becomes "Cordless Drill 18V | Acme Tools"
    description: product.summary,
    alternates: { canonical: `/products/${slug}` },
    openGraph: { images: [product.image] },
  };
}
Enter fullscreen mode Exit fullscreen mode

Because this runs on the server, the tags are in the initial HTML response, which is exactly where you want them.

Astro and other static site generators

With Astro, a shared SEO component keeps every page consistent. Each page passes props from its front matter:

---
// src/components/SEO.astro
interface Props { title: string; description: string; image?: string }
const { title, description, image = '/og-default.jpg' } = Astro.props;
const fullTitle = `${title} | Acme Tools`;
const canonical = new URL(Astro.url.pathname, Astro.site);
---
<title>{fullTitle}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />
<meta property="og:title" content={fullTitle} />
<meta property="og:description" content={description} />
<meta property="og:image" content={new URL(image, Astro.site)} />
Enter fullscreen mode Exit fullscreen mode

The same pattern works in Hugo, Eleventy or any template engine: one component, required props and no silent defaults.

Single-page apps and client-side rendering

This is where most meta tag bugs live. If your tags are injected by JavaScript after the page loads, for example with React Helmet in a client-only app, the initial HTML contains whatever default was in index.html. Google does render JavaScript, but rendering can happen later than crawling. Most social media crawlers and chat apps don't run JavaScript at all, so your link previews will show the default title and image forever.

The fix is to render meta tags on the server, through SSR, static generation or prerendering. To see what non-JavaScript crawlers see, just fetch the page with curl. If the right title isn't in that response, it isn't really there.

CMS templates and fallbacks

If editors manage content in a CMS, make the SEO title and description fields required, or at least generate a sensible fallback from the page title and excerpt. Never ship an empty <title>, and never fall back to one site-wide description on every page. Both turn into duplicate-content warnings at scale.

The Other Meta Tags Developers Break

A few more tags cause outsized damage when they go wrong:

  • noindex left on from staging. Check both the <meta name="robots"> tag and the X-Robots-Tag HTTP header. The header version is often set at the server or CDN level and won't show in your page source.
  • A missing or wrong viewport. Without it, mobile browsers render a zoomed-out desktop layout.
  • Charset declared too late. If <meta charset> isn't near the top of the <head>, browsers may guess the encoding and mangle special characters.
  • Broken Open Graph images. Use absolute URLs, a large enough image (1200 × 630 pixels is a common target), and make sure the image isn't blocked by robots.txt.
  • Canonicals pointing to the wrong place. A canonical that points to a redirect, a 404 or the homepage tells Google to ignore the page you actually want indexed.

How to Test Your Meta Tags

Use a meta tag analyzer for a quick check

For a fast, visual check of any public URL, a free meta tag analyzer shows the live title and description with their lengths, the robots and viewport values, whether Open Graph tags are present, and a preview of how the result looks in Google. It's the quickest way to catch truncation and missing tags before a release, and it works on competitors' pages too, which is handy when you're benchmarking.

Check the raw response with curl and DevTools

For the ground truth, look at exactly what the server sends:

# Title, description, robots and Open Graph tags in the raw HTML
curl -s https://example.com/products/cordless-drill-18v \
  | grep -iE '<title>|name="description"|name="robots"|property="og:'

# The X-Robots-Tag header, which won't show in the page source
curl -sI https://example.com/products/cordless-drill-18v | grep -i x-robots-tag
Enter fullscreen mode Exit fullscreen mode

In DevTools, compare View Source (the raw response) with the Elements panel (the rendered DOM). If they disagree on the title, you're relying on client-side rendering.

Automate it in CI

Manual checks don't scale, and they don't catch regressions. Here's a small Node script (Node 18 or newer, which has fetch built in) that fetches one URL per template and fails the build on the most common problems:

// scripts/check-meta.mjs
// Usage: node scripts/check-meta.mjs https://staging.example.com/ https://staging.example.com/products/sample
const urls = process.argv.slice(2);
const seenTitles = new Map();
let failed = false;

const fail = (url, msg) => { console.error(`FAIL ${url}: ${msg}`); failed = true; };
const getMeta = (html, name) =>
  html.match(new RegExp(`<meta\\s+name=["']${name}["']\\s+content=["']([^"']*)["']`, 'i'))?.[1];

for (const url of urls) {
  const res = await fetch(url);
  const html = await res.text();
  const title = html.match(/<title[^>]*>([^<]*)<\/title>/i)?.[1]?.trim();
  const description = getMeta(html, 'description');
  const robots = `${getMeta(html, 'robots') ?? ''} ${res.headers.get('x-robots-tag') ?? ''}`;

  if (!title) fail(url, 'missing <title>');
  else {
    if (title.length > 60) fail(url, `title is ${title.length} characters`);
    if (seenTitles.has(title)) fail(url, `duplicate title, also on ${seenTitles.get(title)}`);
    seenTitles.set(title, url);
  }
  if (!description) fail(url, 'missing meta description');
  if (/noindex/i.test(robots)) fail(url, 'noindex found');
}

process.exit(failed ? 1 : 0);
Enter fullscreen mode Exit fullscreen mode

The regexes assume your own templates write attributes in a consistent order, which is fine for checking your own output. If you need to handle arbitrary HTML, swap them for a proper parser like cheerio. Run it against staging after each deploy, and point it at production URLs too, to catch a stray noindex before Google does.

Common Mistakes Checklist

Paste this into a PR description or a ticket and tick it off for every new template:

- [ ] Every template outputs a unique <title>, around 50 to 60 characters
- [ ] <title> and H1 describe the same thing
- [ ] Brand name at the end of titles, not the start (except the homepage)
- [ ] No duplicate titles on paginated or filtered pages
- [ ] Unique meta description on every important page
- [ ] Meta tags present in the server HTML, not injected client-side
- [ ] No noindex in meta tags or X-Robots-Tag headers on production
- [ ] viewport and charset set correctly, with charset near the top of <head>
- [ ] Canonical points to the correct, indexable URL
- [ ] og:title, og:description and an absolute og:image URL present
Enter fullscreen mode Exit fullscreen mode

If you want the wider list beyond meta tags, this full reference of SEO checks explains each one and how to fix a failing result.

FAQs

What is a meta tag analyzer?

A meta tag analyzer is a tool that fetches a web page and reports its meta tags, such as the title, meta description, robots, viewport and Open Graph tags. Most also show character lengths, flag missing or duplicate tags, and preview how the page will look in Google's search results.

How long should a title tag be?

Google has no official limit, but it truncates title links at roughly 600 pixels on desktop, which is about 50 to 60 characters for most titles. Longer titles are also more likely to be rewritten. Put the most important words first so they survive truncation.

How long should a meta description be?

There's no official limit, but snippets are usually truncated at around 920 pixels on desktop, so roughly 150 to 160 characters is a sensible target. Put the key message in the first 120 characters, because mobile results often show less.

Does Google still use meta descriptions?

Yes, but not always. Google often generates its own snippet from page content to match a specific search, and one large study found it rewrote about 63% of meta descriptions. A well-written description is still worth having, because it's often shown and can improve your click-through rate.

Do meta keywords still matter for SEO?

No. Google has ignored the meta keywords tag for ranking for many years. It does no harm, but it does no good either. Spend the time on unique titles and descriptions instead, which actually affect how your pages appear in search.

Why is Google showing a different title than my title tag?

Google generates title links from several sources and may rewrite your title if it's too long, vague, duplicated across similar pages, outdated, or doesn't match the page's main heading. Keeping your title concise, unique and consistent with your H1 makes rewrites much less likely.

Wrapping Up

Treat meta tags like any other output of your code. Generate them from real data, render them on the server, and test them automatically. Ten minutes setting up a CI check is a lot cheaper than discovering, three months later, that every product page has been showing up in Google as "Home | Company."

Top comments (0)