SEO Fundamentals: On-Page SEO, Internal Links and JSON-LD
Business & ProductLesson 3 of 45 min read
What you'll learn
- Write title tags and meta descriptions that match intent and read well in results
- Structure a page with one h1 and meaningful h2 and h3 headings
- Plan internal links with descriptive anchor text
- Add valid JSON-LD structured data for an article, a breadcrumb trail and a local business
On this page
A climbing gym wrote a helpful article about choosing a first pair of climbing shoes. It has good advice, original photos and a respectful tone. In search results, however, it appears as "Untitled Document" with a snippet pulled from the cookie banner. Nothing is wrong with the writing. The page just never told the search engine and the reader what it is. On-page SEO is the work of saying so clearly, in the places search engines and people actually look.
Title tags and meta descriptions
The <title> element is the page's name in browser tabs and usually the clickable headline in results. Put the main idea first, make it specific, and add the brand last. There is no official character limit, but results truncate by display width, so roughly 50 to 60 characters is a safe working range. Search engines sometimes rewrite titles that are stuffed, vague or mismatched with the page, which is a useful signal that yours needs work.
The meta description is not a ranking input you can rely on, but it often becomes the snippet under the title, and a good one improves how many people click. Write one sentence of value (what the page contains, for whom) in about 120 to 160 characters, and make it unique per page. The engine may still choose its own snippet when it fits the query better.
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>How to Choose Your First Climbing Shoes | Northface Boulder Gym</title>
<meta name="description" content="Fit, shape and rubber explained for beginners, with a 10-minute in-store fitting checklist and what to avoid buying before your first month.">
<link rel="canonical" href="https://www.example.com/blog/choose-first-climbing-shoes">
</head>Headings that outline the page
Headings are an outline for both skimmers and assistive technology. Use one <h1> that states the page's subject, then <h2> for each major section and <h3> for subsections, without skipping levels for visual styling. Phrase headings the way a reader would ask the question, because they are often where answer-style snippets come from. Do not repeat the same keyword in every heading; it reads as stuffing, and it hurts navigation. Pick styling with CSS, not heading levels.
<h1>How to choose your first climbing shoes</h1>
<h2>Shoe shapes: flat, moderate and downturned</h2>
<h2>How a beginner's shoe should fit</h2>
<h3>Toes, heel and the crunch test</h3>
<h2>Rubber and stiffness in plain terms</h2>
<h2>What not to buy in your first month</h2>Internal links and anchor text
Internal links connect your pages. They let crawlers discover pages, spread a page's authority to related ones and show readers where to go next. Use descriptive anchor text that says what the destination is about. "Read our beginner's guide to climbing grades" is useful to both a person and a crawler; "click here" tells neither anything. Link from pages that already get visits to pages you want found, keep important pages within a few clicks of the home page, and link to related content in the body where it genuinely helps, not only in a footer.
| Anchor | Verdict | Why |
|---|---|---|
| click here | Weak | No information about the destination |
| climbing shoe fitting checklist | Good | Describes the page naturally |
| best climbing shoes best climbing shoes cheap | Avoid | Repeats the target phrase and reads as spam |
| https://www.example.com/blog/choose-first-climbing-shoes | Fine in references | Okay for citations, poor in running text |
Structured data with JSON-LD
Structured data is machine-readable markup that states facts about a page in a shared vocabulary (schema.org). Google recommends the JSON-LD format, placed in a script tag. Valid markup can make a page eligible for enhanced displays in results, but it never guarantees them, and the markup must describe content that is actually visible on the page. Here is an article with an author and dates.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "How to Choose Your First Climbing Shoes",
"description": "Fit, shape and rubber explained for beginners.",
"image": "https://www.example.com/images/climbing-shoes-fitting.jpg",
"datePublished": "2025-01-14",
"dateModified": "2025-02-02",
"author": {
"@type": "Person",
"name": "Mira Okafor",
"url": "https://www.example.com/about/mira-okafor"
},
"publisher": {
"@type": "Organization",
"name": "Northface Boulder Gym",
"logo": {
"@type": "ImageObject",
"url": "https://www.example.com/images/logo.png"
}
}
}
</script>A breadcrumb trail shows where the page sits in the site and can be displayed in results in place of a raw URL.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://www.example.com/" },
{ "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://www.example.com/blog" },
{ "@type": "ListItem", "position": 3, "name": "Choose your first climbing shoes" }
]
}
</script>For the gym's own home page, local business markup states the name, address and opening hours in a standard form.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SportsActivityLocation",
"name": "Northface Boulder Gym",
"url": "https://www.example.com/",
"telephone": "+1-555-0100",
"address": {
"@type": "PostalAddress",
"streetAddress": "12 Quarry Lane",
"addressLocality": "Springfield",
"postalCode": "00000",
"addressCountry": "US"
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "06:00",
"closes": "22:00"
}
]
}
</script>Images, URLs and the content itself
Give images a descriptive file name and an alt attribute that describes what the picture shows, which also serves screen reader users. Keep URLs short, readable and stable (/blog/choose-first-climbing-shoes, not /p?id=88213). Most importantly, the body text should answer the query completely, in the order a reader would want it, with original detail such as photos, measurements, first-hand experience or data the competition lacks. No tag compensates for a page that does not help.
Common mistakes
- Same title on every page. Symptom: Search Console and site audits show hundreds of duplicate titles, and results look identical. Fix: generate unique titles from each page's own data.
- Multiple h1 elements or heading levels used for size. Symptom: screen reader users hear a confusing outline. Fix: one h1, logical nesting, size with CSS.
- Invalid JSON-LD. Symptom: the Rich Results Test reports a parsing error such as a missing comma or an unquoted key. Fix: validate before deploying; a trailing comma breaks the whole block.
- Markup that contradicts the page. Symptom: the page shows one price and the structured data another. Fix: generate markup from the same data that renders the visible content.
- Keyword-stuffed anchor text and titles. Symptom: the engine rewrites your title in results, and the page reads awkwardly. Fix: write for the reader and keep the main phrase natural.
How this shows up in real projects and interviews
On a real site you rarely hand-edit these tags. You build a template that fills the title, description, canonical URL and JSON-LD from each page's data, which is why validating a sample of generated pages beats checking one by hand. Frameworks give you hooks for this metadata; see the Next.js course and the HTML fundamentals course for the markup basics. In interviews, expect questions such as "what makes a good title tag?" or "how would you add structured data to a product page?" Describe the template-driven approach and mention validation.
Try it yourself
Take one page from your own site and rewrite its title, meta description and heading outline. Then add Article or Product JSON-LD that matches the visible content and validate it in the Rich Results Test or the Schema Markup Validator.
Show a hint
Paste your JSON-LD into any JSON parser first to catch syntax errors such as trailing commas. Make sure every value in the markup (price, date, author) also appears on the page.
Key takeaways
- Write unique, specific titles (about 50 to 60 characters of visible width) and unique, helpful meta descriptions.
- Use one h1 and a logical h2 and h3 outline that mirrors the questions readers have.
- Link internally with descriptive anchor text, and keep important pages close to the home page.
- JSON-LD must be valid, must match visible content and only makes pages eligible for rich results.
- Generate metadata from page data in templates and validate samples of the output.
Test yourself
A trick from this lesson's ride: Title = what first, brand last, no keyword lists. Four more tricks like it wait along the route, each followed by a question.
Frequently asked questions
How long should a title tag and meta description be?
There is no fixed limit, since results truncate by pixel width, but roughly 50 to 60 characters for titles and 120 to 160 for descriptions is a sensible range. Put the key idea first and make each unique.
What is JSON-LD and why use it for SEO?
JSON-LD is a way to describe a page's content with schema.org vocabulary inside a script tag. It helps search engines understand entities such as articles, products and businesses, and can make a page eligible for enhanced results, though it does not guarantee them.
Are internal links important for SEO?
Yes. They let crawlers discover pages, show which pages matter and guide visitors to related content. Use descriptive anchor text and link from relevant pages rather than relying on footers or menus alone.