Skip to content
Technical SEO — Complete Guide with Examples

Technical SEO — Complete Guide with Examples

DodaTech Updated Jun 15, 2026 8 min read

Technical SEO is the practice of optimizing a website’s infrastructure to help search engines crawl, index, and render pages effectively, covering site speed, mobile compatibility, structured data, and server configuration.

Why Technical SEO Matters

Even the best content and most backlinks won’t matter if Google can’t crawl your site or your pages load in 8 seconds. Technical SEO is the foundation. One technical issue — a slow server, broken sitemap, or wrong canonical tag — can destroy rankings overnight. DodaTech’s migration to a headless architecture with optimized Core Web Vitals improved organic traffic by 45% in three months.

Technical SEO Landscape

Think of technical SEO like the plumbing and electrical system of a house. You don’t see it when it works, but when it breaks, nothing else functions.

    graph TD
    subgraph Crawling[<b>Crawling & Indexing</b>]
        A[Googlebot crawls] --> B{Fetchable?}
        B -->|Yes| C[Parse content]
        B -->|No| D[Blocked or error]
        C --> E[Index content]
        C --> F[Canonical URL]
    end
    subgraph Rendering[<b>Rendering & UX</b>]
        G[Core Web Vitals] --> H[LCP < 2.5s]
        G --> I[FID < 100ms]
        G --> J[CLS < 0.1]
        K[Mobile-friendly] --> L[Responsive design]
    end
    subgraph Signals[<b>Signals</b>]
        M[Structured Data<br/>Schema.org JSON-LD]
        N[XML Sitemap]
        O[Robots.txt]
        P[Hreflang tags]
        Q[HTTPS]
    end
    E --> M
    E --> N
    E --> O
    E --> P
    H --> R[Google Ranking]
    I --> R
    J --> R
    L --> R
    M --> R
    style Technical fill:#3b82f6,color:#fff
  

Core Web Vitals — Google’s UX Metrics

Core Web Vitals are Google’s metrics for user experience, confirmed as ranking signals since the Page Experience update.

Largest Contentful Paint (LCP) — Loading Speed

Measures when the main content (hero image, headline) loads.

<!-- Optimize LCP by preloading the hero image -->
<head>
  <link rel="preload" href="/images/hero.webp" as="image" fetchpriority="high">
  <link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>
</head>

<!-- Use responsive images with srcset -->
<img src="/images/hero-400.webp"
     srcset="/images/hero-400.webp 400w,
             /images/hero-800.webp 800w,
             /images/hero-1200.webp 1200w"
     sizes="(max-width: 600px) 400px,
            (max-width: 1200px) 800px,
            1200px"
     alt="DodaTech Tutorials"
     width="1200" height="630"
     fetchpriority="high">

Bad LCP causes:

  • Unoptimized images (not compressed, wrong format)
  • Render-blocking CSS/JS
  • Slow server response time (>200ms TTFB)
  • Font loading delays

First Input Delay (FID) — Interactivity

Measures the time from when a user first interacts (clicks a button, taps a link) to when the browser responds.

<!-- Defer non-critical JavaScript -->
<script src="/js/analytics.js" defer></script>
<script src="/js/chat-widget.js" defer></script>

<!-- Inline critical CSS -->
<style>
  /* Critical above-the-fold styles only */
  .header { display: flex; }
  .hero { min-height: 60vh; }
  /* Everything else loaded asynchronously */
</style>
<link rel="stylesheet" href="/styles/main.css" media="print" onload="this.media='all'">

Cumulative Layout Shift (CLS) — Visual Stability

Measures how much the page layout shifts unexpectedly.

<!-- Always specify image dimensions to prevent layout shifts -->
<img src="/images/tutorial-thumbnail.webp"
     width="320"
     height="180"
     alt="Java Tutorial"
     loading="lazy">

<!-- Reserve space for dynamic content -->
<div id="ad-slot" style="min-height: 250px; width: 300px;"></div>

<!-- Don't inject content above existing content -->
<!-- BAD: inserting a banner that pushes content down -->
<!-- GOOD: use a reserved placeholder from the start -->
// Track CLS in the browser for debugging
let clsValue = 0;
let clsEntries = [];

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (!entry.hadRecentInput) {
      clsValue += entry.value;
      clsEntries.push(entry);
    }
  }
  console.log('CLS:', clsValue.toFixed(3));
}).observe({type: 'layout-shift', buffered: true});

Structured Data — JSON-LD Schema

Structured data helps Google understand your content and enables rich results (featured snippets, FAQ, breadcrumbs, how-to).

<!-- JSON-LD for Tutorial Article -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "headline": "Java Streams and Lambdas — Explained with Examples",
  "description": "Master Java Streams API with practical examples.",
  "author": {
    "@type": "Organization",
    "name": "DodaTech"
  },
  "datePublished": "2026-06-15",
  "dateModified": "2026-06-15",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://dodatech.com/tutorials/java/java-streams/"
  },
  "publisher": {
    "@type": "Organization",
    "name": "DodaTech"
  },
  "image": "https://dodatech.com/images/java-streams-og.webp"
}
</script>

<!-- JSON-LD for Breadcrumbs -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {"@type": "ListItem", "position": 1, "name": "Home", "item": "https://dodatech.com/"},
    {"@type": "ListItem", "position": 2, "name": "Tutorials", "item": "https://dodatech.com/tutorials/"},
    {"@type": "ListItem", "position": 3, "name": "Java", "item": "https://dodatech.com/tutorials/java/"},
    {"@type": "ListItem", "position": 4, "name": "Java Streams"}
  ]
}
</script>

<!-- JSON-LD for FAQ (auto-generated by the faq shortcode) -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [{
    "@type": "Question",
    "name": "What is the difference between map() and flatMap()?",
    "acceptedAnswer": {
      "@type": "Answer",
      "text": "map() transforms each element 1:1. flatMap() transforms each element into a stream and flattens results."
    }
  }]
}
</script>

Schema Types by Content

Content TypeSchema TypeRich Result
Blog/ArticleArticle, TechArticleTop stories, headline
RecipeRecipeImage, ratings, cook time
FAQFAQPageExpandable Q&A
How-ToHowToStep-by-step with images
ProductProductPrice, availability, reviews
CourseCourseCourse info, provider
VideoVideoObjectVideo thumbnail, duration

XML Sitemap — Your Site Map for Google

The sitemap tells Google about all the pages on your site that should be indexed.

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://dodatech.com/</loc>
    <lastmod>2026-06-15</lastmod>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>https://dodatech.com/tutorials/java/</loc>
    <lastmod>2026-06-15</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.9</priority>
  </url>
  <url>
    <loc>https://dodatech.com/tutorials/java/java-streams/</loc>
    <lastmod>2026-06-15</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
  </url>
</urlset>

Sitemap best practices:

  • Include only canonical URLs (no duplicates)
  • Keep under 50,000 URLs per sitemap (or 50MB uncompressed)
  • Use a sitemap index for large sites
  • Submit to Google Search Console
  • Include in robots.txt

Robots.txt — Telling Google What to Crawl

# robots.txt for DodaTech
User-agent: *
Allow: /
Disallow: /admin/
Disallow: /api/
Disallow: /*?ref=
Disallow: /*?utm_*
Disallow: /*sort=*
Disallow: /tmp/
Disallow: /private/

# Sitemap location
Sitemap: https://dodatech.com/sitemap.xml

Common robots.txt mistakes:

  • Blocking CSS/JS files (Google needs them to render pages)
  • Using Disallow: / on production (blocks all crawling)
  • Forgetting to update when site structure changes
  • Not including the sitemap URL

Canonical Tags — Preventing Duplicate Content

A canonical tag tells Google which version of a page is the original when duplicates exist.

<!-- Canonical tag — always on every page -->
<link rel="canonical" href="https://dodatech.com/tutorials/java/spring/">

<!-- Example: paginated pages should canonical to themselves -->
<link rel="canonical" href="https://dodatech.com/tutorials/java/spring/?page=2">

<!-- Example: print version should canonical to the main page -->
<link rel="canonical" href="https://dodatech.com/tutorials/java/spring/">

When to use canonical tags:

  • WWW vs non-WWW versions
  • HTTP vs HTTPS
  • URL parameters (sort, filter, ref)
  • Printer-friendly versions
  • Syndicated content (canonical back to original)
  • Paginated pages (each page self-canonical)

Hreflang Tags — International SEO

Hreflang tells Google which language version of a page to show for different regions.

<!-- Hreflang for multilingual site -->
<link rel="alternate" hreflang="en" href="https://dodatech.com/tutorials/java/spring/">
<link rel="alternate" hreflang="es" href="https://dodatech.com/es/tutoriales/java/spring/">
<link rel="alternate" hreflang="fr" href="https://dodatech.com/fr/tutoriels/java/spring/">
<link rel="alternate" hreflang="de" href="https://dodatech.com/de/tutorials/java/spring/">
<link rel="alternate" hreflang="x-default" href="https://dodatech.com/tutorials/java/spring/">
<!-- Alternative: hreflang in XML sitemap -->
<url>
    <loc>https://dodatech.com/tutorials/java/spring/</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://dodatech.com/tutorials/java/spring/"/>
    <xhtml:link rel="alternate" hreflang="es" href="https://dodatech.com/es/tutoriales/java/spring/"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://dodatech.com/tutorials/java/spring/"/>
</url>

Hreflang rules:

  • Each language page must link to ALL language versions (including itself)
  • Use x-default for the fallback language
  • Must be bidirectional — if page A links to page B, page B must link to page A
  • Use ISO 639-1 language codes (en, es, fr, de)

Mobile Optimization

Google uses mobile-first indexing — the mobile version is the primary version for ranking.

<!-- Viewport meta tag (required for mobile) -->
<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Use responsive images -->
<img src="/images/hero-400.webp"
     srcset="/images/hero-400.webp 400w, /images/hero-800.webp 800w"
     sizes="(max-width: 600px) 100vw, 50vw"
     alt="Description">

<!-- Avoid horizontal scrolling -->
<style>
  pre, code {
    overflow-x: auto;
    white-space: pre;
    word-wrap: normal;
  }
  img, video, embed {
    max-width: 100%;
    height: auto;
  }
  table {
    overflow-x: auto;
    display: block;
  }
</style>
// Test mobile-friendliness programmatically
function checkMobileViewport() {
  const viewport = document.querySelector('meta[name="viewport"]');
  if (!viewport) {
    console.error('No viewport meta tag! Required for mobile.');
  } else {
    console.log('Viewport set to:', viewport.content);
  }

  const touchTargets = document.querySelectorAll('a, button, input, select');
  let smallTargets = 0;
  touchTargets.forEach(el => {
    const rect = el.getBoundingClientRect();
    if (rect.width < 44 || rect.height < 44) {
      smallTargets++;
      console.warn(`Small tap target: ${el.tagName} ${el.textContent?.trim()?.substring(0, 30)}`);
    }
  });
  console.log(`Touch targets: ${touchTargets.length}, too small: ${smallTargets}`);
}

checkMobileViewport();

Common Mistakes

  1. Blocking CSS/JS in robots.txt: Google needs these to render pages. If blocked, Google sees blank pages. Never disallow CSS, JS, or image files.
  2. Self-canonical mismatches: The canonical tag URL must exactly match the page URL. Even a trailing slash mismatch can cause issues.
  3. Missing or incorrect hreflang: Without hreflang, Google may show the wrong language version or treat language variants as duplicates.
  4. Not testing Core Web Vitals: What looks fast on your development machine may be slow in the real world. Test with PageSpeed Insights and CrUX.
  5. Sitemap without priority updates: If you add a new page but don’t update the sitemap, Google may take weeks to discover it.

Practice Questions

  1. What are the three Core Web Vitals metrics?
  2. What does structured data (JSON-LD) do for SEO?
  3. What is the purpose of a canonical tag?
  4. How does mobile-first indexing affect technical SEO?
  5. What is the difference between Disallow and Allow in robots.txt?

Answers:

  1. LCP (<2.5s, loading), FID (<100ms, interactivity), CLS (<0.1, visual stability). These are confirmed ranking signals.
  2. Structured data helps Google understand content context and enables rich results (FAQ, how-to, breadcrumbs, product, review) in search results.
  3. A canonical tag tells Google which URL is the authoritative version when duplicate content exists. It consolidates ranking signals to one URL.
  4. Google predominantly uses the mobile version for indexing and ranking. Mobile issues directly impact desktop rankings too. All pages must be mobile-friendly.
  5. Disallow blocks crawling of specified paths. Allow overrides a Disallow for a specific path. Both are directives, not commands.

Mini Project: Technical SEO Audit

Perform a complete technical SEO audit on any website:

  1. Crawlability: Run Screaming Frog or Sitebulb to find broken links, redirects, and blocked resources
  2. Core Web Vitals: Test with PageSpeed Insights and CrUX report
  3. Mobile: Test with Google’s Mobile-Friendly Test
  4. Structured data: Validate with Google’s Rich Results Test
  5. Sitemap: Check format, errors, and submission status
  6. Robots.txt: Verify no critical resources are blocked
  7. Canonical: Ensure every page has self-canonical tag
  8. Hreflang (if multilingual): Check bidirectional linking is correct
  9. HTTPS: Verify certificate, mixed content, and HSTS headers
  10. Fix the top 3 issues and re-measure

This process is how DodaTech’s engineering team maintains the site’s technical health, ensuring tutorials rank well and load fast for learners worldwide.

Related topics: SEO, Google Analytics, Content Marketing, API, CI/CD

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro